@ngx-smz/ui-kit 21.9.0-next.10 → 21.9.0-next.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1707,6 +1707,44 @@ class SmzDialogRef {
1707
1707
  }
1708
1708
  }
1709
1709
 
1710
+ const KEYS = {
1711
+ width: 'width',
1712
+ height: 'height',
1713
+ minWidth: 'minWidth',
1714
+ 'min-width': 'minWidth',
1715
+ maxWidth: 'maxWidth',
1716
+ 'max-width': 'maxWidth',
1717
+ minHeight: 'minHeight',
1718
+ 'min-height': 'minHeight',
1719
+ maxHeight: 'maxHeight',
1720
+ 'max-height': 'maxHeight',
1721
+ };
1722
+ /**
1723
+ * Separa os estilos de tamanho (`width`, `height`, `min-*`, `max-*`) do resto do `style`.
1724
+ *
1725
+ * Porcentagens so significam "porcentagem da tela" quando aplicadas ao painel do overlay (cujo pai ocupa a viewport);
1726
+ * dentro do frame elas seriam relativas ao painel, que tem largura "shrink-to-fit" (ex.: 60% de 531px).
1727
+ * O painel recebe o tamanho; o frame passa a ocupar 100% dele.
1728
+ */
1729
+ function smzSplitDialogSize(style, extra) {
1730
+ const pane = { ...(extra ?? {}) };
1731
+ const rest = {};
1732
+ for (const [key, value] of Object.entries(style ?? {})) {
1733
+ if (value === null || value === undefined || value === '')
1734
+ continue;
1735
+ const target = KEYS[key];
1736
+ if (target)
1737
+ pane[target] = String(value);
1738
+ else
1739
+ rest[key] = value;
1740
+ }
1741
+ for (const key of Object.keys(pane)) {
1742
+ if (!pane[key])
1743
+ delete pane[key];
1744
+ }
1745
+ return { pane, rest };
1746
+ }
1747
+
1710
1748
  /* eslint-disable max-len -- classes Tailwind nos templates */
1711
1749
  /** Componente que sera criado dentro do dialog. */
1712
1750
  const SMZ_DIALOG_CONTENT = new InjectionToken('SMZ_DIALOG_CONTENT');
@@ -1714,6 +1752,8 @@ const SMZ_DIALOG_CONTENT = new InjectionToken('SMZ_DIALOG_CONTENT');
1714
1752
  class SmzDialogFrameComponent {
1715
1753
  config = inject(SmzDialogConfig);
1716
1754
  ref = inject(SmzDialogRef);
1755
+ /** Tamanho vai para o painel do overlay (ver `smzSplitDialogSize`); o frame ocupa 100% dele. */
1756
+ size = smzSplitDialogSize(this.config.style, { width: this.config.width, height: this.config.height });
1717
1757
  injector = inject(Injector);
1718
1758
  contentType = inject(SMZ_DIALOG_CONTENT);
1719
1759
  host = viewChild.required('content', { read: ViewContainerRef });
@@ -1723,16 +1763,16 @@ class SmzDialogFrameComponent {
1723
1763
  });
1724
1764
  }
1725
1765
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzDialogFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1726
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzDialogFrameComponent, isStandalone: true, selector: "ui-dialog-frame", host: { classAttribute: "pointer-events-auto block" }, viewQueries: [{ propertyName: "host", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: `
1766
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzDialogFrameComponent, isStandalone: true, selector: "ui-dialog-frame", host: { properties: { "class.w-full": "!!size.pane.width", "class.h-full": "!!size.pane.height" }, classAttribute: "pointer-events-auto block" }, viewQueries: [{ propertyName: "host", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: `
1727
1767
  <div
1728
1768
  role="dialog"
1729
1769
  aria-modal="true"
1730
1770
  [attr.aria-label]="config.header || null"
1731
1771
  class="flex max-h-[90vh] max-w-[95vw] flex-col rounded-overlay border border-ui-line bg-ui-surface-2 font-ui text-ui-fg shadow-overlay"
1732
1772
  [class]="config.styleClass ?? ''"
1733
- [style.width]="config.width ?? null"
1734
- [style.height]="config.height ?? null"
1735
- [ngStyle]="config.style"
1773
+ [style.width]="size.pane.width ? '100%' : null"
1774
+ [style.height]="size.pane.height ? '100%' : null"
1775
+ [ngStyle]="size.rest"
1736
1776
  >
1737
1777
  @if (config.showHeader !== false) {
1738
1778
  <div class="flex items-center justify-between gap-4 border-b border-ui-line px-4 py-3">
@@ -1763,7 +1803,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
1763
1803
  selector: 'ui-dialog-frame',
1764
1804
  changeDetection: ChangeDetectionStrategy.OnPush,
1765
1805
  imports: [NgStyle],
1766
- host: { class: 'pointer-events-auto block' },
1806
+ // O painel do CDK e `display:flex`: o host e item flex e so ocupa o painel dimensionado se tiver largura/altura 100%.
1807
+ host: { class: 'pointer-events-auto block', '[class.w-full]': '!!size.pane.width', '[class.h-full]': '!!size.pane.height' },
1767
1808
  template: `
1768
1809
  <div
1769
1810
  role="dialog"
@@ -1771,9 +1812,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
1771
1812
  [attr.aria-label]="config.header || null"
1772
1813
  class="flex max-h-[90vh] max-w-[95vw] flex-col rounded-overlay border border-ui-line bg-ui-surface-2 font-ui text-ui-fg shadow-overlay"
1773
1814
  [class]="config.styleClass ?? ''"
1774
- [style.width]="config.width ?? null"
1775
- [style.height]="config.height ?? null"
1776
- [ngStyle]="config.style"
1815
+ [style.width]="size.pane.width ? '100%' : null"
1816
+ [style.height]="size.pane.height ? '100%' : null"
1817
+ [ngStyle]="size.rest"
1777
1818
  >
1778
1819
  @if (config.showHeader !== false) {
1779
1820
  <div class="flex items-center justify-between gap-4 border-b border-ui-line px-4 py-3">
@@ -1814,10 +1855,14 @@ class SmzDialogService {
1814
1855
  const resolved = Object.assign(new SmzDialogConfig(), config);
1815
1856
  const ref = new SmzDialogRef();
1816
1857
  const modal = resolved.modal !== false;
1858
+ // Porcentagens (ex.: `width: '60%'`) sao relativas a viewport quando aplicadas ao painel do overlay.
1859
+ const pane = smzSplitDialogSize(resolved.style, { width: resolved.width, height: resolved.height }).pane;
1817
1860
  const overlayRef = this.overlay.create({
1818
1861
  hasBackdrop: modal,
1819
1862
  positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically(),
1820
1863
  scrollStrategy: this.overlay.scrollStrategies.block(),
1864
+ ...pane,
1865
+ maxWidth: pane.maxWidth ?? '95vw',
1821
1866
  });
1822
1867
  if (resolved.baseZIndex != null) {
1823
1868
  overlayRef.hostElement.style.zIndex = String(resolved.baseZIndex + 1);
@@ -1896,6 +1941,8 @@ class SmzDialogComponent {
1896
1941
  viewContainer = inject(ViewContainerRef);
1897
1942
  host = inject(ElementRef);
1898
1943
  overlayRef;
1944
+ /** `width`/`height`/`min-*`/`max-*` de `style` vao para o painel do overlay (relativos a viewport); o frame ocupa 100% dele. */
1945
+ sizing = computed(() => smzSplitDialogSize(this.style()), ...(ngDevMode ? [{ debugName: "sizing" }] : []));
1899
1946
  dx = signal(0, ...(ngDevMode ? [{ debugName: "dx" }] : []));
1900
1947
  dy = signal(0, ...(ngDevMode ? [{ debugName: "dy" }] : []));
1901
1948
  constructor() {
@@ -1905,6 +1952,11 @@ class SmzDialogComponent {
1905
1952
  else
1906
1953
  this.dispose();
1907
1954
  });
1955
+ effect(() => {
1956
+ const maximized = this.maximized();
1957
+ const pane = this.sizing().pane;
1958
+ this.overlayRef?.updateSize(maximized ? { width: '100vw', height: '100vh', maxWidth: '100vw', maxHeight: '100vh', minWidth: '0', minHeight: '0' } : { ...pane, maxWidth: pane.maxWidth ?? '95vw' });
1959
+ });
1908
1960
  effect(() => {
1909
1961
  const position = this.position();
1910
1962
  this.overlayRef?.updatePositionStrategy(this.strategyFor(position));
@@ -1965,6 +2017,7 @@ class SmzDialogComponent {
1965
2017
  hasBackdrop: modal,
1966
2018
  positionStrategy: this.strategyFor(this.position()),
1967
2019
  scrollStrategy: this.overlay.scrollStrategies.block(),
2020
+ ...(this.maximized() ? { width: '100vw', height: '100vh', maxWidth: '100vw', maxHeight: '100vh' } : { ...this.sizing().pane, maxWidth: this.sizing().pane.maxWidth ?? '95vw' }),
1968
2021
  });
1969
2022
  SmzZIndex.set('modal', this.overlayRef.hostElement, 1100 + this.baseZIndex());
1970
2023
  if (this.overlayRef.backdropElement) {
@@ -2003,7 +2056,9 @@ class SmzDialogComponent {
2003
2056
  [attr.aria-label]="header() || null"
2004
2057
  class="pointer-events-auto flex flex-col border border-ui-line bg-ui-surface-2 font-ui text-ui-fg shadow-overlay"
2005
2058
  [class]="(maximized() ? 'h-screen w-screen max-h-none max-w-none rounded-none ' : 'max-h-[90vh] max-w-[95vw] rounded-overlay ') + (resizable() && !maximized() ? 'resize overflow-auto ' : '') + (styleClass() ?? '')"
2006
- [ngStyle]="maximized() ? null : style()"
2059
+ [ngStyle]="maximized() ? null : sizing().rest"
2060
+ [style.width]="!maximized() && sizing().pane.width ? '100%' : null"
2061
+ [style.height]="!maximized() && sizing().pane.height ? '100%' : null"
2007
2062
  [style.transform]="maximized() || (dx() === 0 && dy() === 0) ? null : 'translate(' + dx() + 'px, ' + dy() + 'px)'"
2008
2063
  >
2009
2064
  @if (headerTemplate(); as headerTpl) {
@@ -2061,7 +2116,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
2061
2116
  [attr.aria-label]="header() || null"
2062
2117
  class="pointer-events-auto flex flex-col border border-ui-line bg-ui-surface-2 font-ui text-ui-fg shadow-overlay"
2063
2118
  [class]="(maximized() ? 'h-screen w-screen max-h-none max-w-none rounded-none ' : 'max-h-[90vh] max-w-[95vw] rounded-overlay ') + (resizable() && !maximized() ? 'resize overflow-auto ' : '') + (styleClass() ?? '')"
2064
- [ngStyle]="maximized() ? null : style()"
2119
+ [ngStyle]="maximized() ? null : sizing().rest"
2120
+ [style.width]="!maximized() && sizing().pane.width ? '100%' : null"
2121
+ [style.height]="!maximized() && sizing().pane.height ? '100%' : null"
2065
2122
  [style.transform]="maximized() || (dx() === 0 && dy() === 0) ? null : 'translate(' + dx() + 'px, ' + dy() + 'px)'"
2066
2123
  >
2067
2124
  @if (headerTemplate(); as headerTpl) {
@@ -6536,6 +6593,11 @@ class SmzUiTimelineComponent {
6536
6593
  contentTemplate = computed(() => smzFindTemplate(this.templates(), 'content'), ...(ngDevMode ? [{ debugName: "contentTemplate" }] : []));
6537
6594
  oppositeTemplate = computed(() => smzFindTemplate(this.templates(), 'opposite'), ...(ngDevMode ? [{ debugName: "oppositeTemplate" }] : []));
6538
6595
  horizontal = computed(() => this.layout() === 'horizontal' || this.align() === 'top' || this.align() === 'bottom', ...(ngDevMode ? [{ debugName: "horizontal" }] : []));
6596
+ /** No layout horizontal, o conteudo fica acima da linha em `top` e nos itens impares de `alternate`/`right`. */
6597
+ contentOnTop(index) {
6598
+ const align = this.align();
6599
+ return align === 'top' || align === 'right' || (align === 'alternate' && index % 2 === 1);
6600
+ }
6539
6601
  rowReverse(index) {
6540
6602
  const align = this.align();
6541
6603
  return align === 'right' || (align === 'alternate' && index % 2 === 1);
@@ -6552,7 +6614,45 @@ class SmzUiTimelineComponent {
6552
6614
  }
6553
6615
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzUiTimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6554
6616
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzUiTimelineComponent, isStandalone: true, selector: "ui-timeline", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "block font-ui text-ui-fg" }, queries: [{ propertyName: "templates", predicate: SmzTemplateDirective, isSignal: true }], ngImport: i0, template: `
6555
- <div class="flex" [class]="horizontal() ? 'flex-row' : 'flex-col'" [ngClass]="styleClass()">
6617
+ @if (horizontal()) {
6618
+ <!-- Nao usar a classe grid do Tailwind: o CSS legado do core (.grid, PrimeFlex) a sobrescreve com display:flex !important.
6619
+ Grade de 3 linhas (conteudo de cima / marcadores / conteudo de baixo) com subgrade por item: todos os marcadores ficam na mesma linha. -->
6620
+ <div style="display: grid; grid-template-rows: auto auto auto" [style.grid-template-columns]="'repeat(' + (value() ?? []).length + ', minmax(0, 1fr))'" [ngClass]="styleClass()">
6621
+ @for (event of value() ?? []; track $index; let index = $index; let first = $first; let last = $last) {
6622
+ <div class="tl-item min-w-0" style="display: grid; grid-row: span 3; grid-template-rows: subgrid">
6623
+ <div class="flex min-w-0 flex-col justify-end px-2 pb-2 text-center" style="grid-row: 1">
6624
+ @if (contentOnTop(index)) {
6625
+ @if (contentTemplate(); as content) {
6626
+ <ng-container [ngTemplateOutlet]="content" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6627
+ }
6628
+ } @else if (oppositeTemplate(); as opposite) {
6629
+ <ng-container [ngTemplateOutlet]="opposite" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6630
+ }
6631
+ </div>
6632
+ <div class="flex items-center" style="grid-row: 2">
6633
+ <span class="h-0.5 flex-1" [class]="first ? 'bg-transparent' : 'bg-ui-line'"></span>
6634
+ @if (markerTemplate(); as marker) {
6635
+ <ng-container [ngTemplateOutlet]="marker" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6636
+ }
6637
+ @else {
6638
+ <span class="block h-4 w-4 shrink-0 rounded-full border-2 border-ui-primary bg-ui-surface-1"></span>
6639
+ }
6640
+ <span class="h-0.5 flex-1" [class]="last ? 'bg-transparent' : 'bg-ui-line'"></span>
6641
+ </div>
6642
+ <div class="flex min-w-0 flex-col px-2 pt-2 text-center" style="grid-row: 3">
6643
+ @if (!contentOnTop(index)) {
6644
+ @if (contentTemplate(); as content) {
6645
+ <ng-container [ngTemplateOutlet]="content" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6646
+ }
6647
+ } @else if (oppositeTemplate(); as opposite) {
6648
+ <ng-container [ngTemplateOutlet]="opposite" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6649
+ }
6650
+ </div>
6651
+ </div>
6652
+ }
6653
+ </div>
6654
+ } @else {
6655
+ <div class="flex flex-col" [ngClass]="styleClass()">
6556
6656
  @for (event of value() ?? []; track $index; let index = $index; let last = $last) {
6557
6657
  <div class="flex min-w-0 flex-1" [class]="horizontal() ? 'flex-col' : (rowReverse(index) ? 'flex-row-reverse' : 'flex-row')">
6558
6658
  <div class="flex-1" [class]="oppositeClass(index)">
@@ -6579,6 +6679,7 @@ class SmzUiTimelineComponent {
6579
6679
  </div>
6580
6680
  }
6581
6681
  </div>
6682
+ }
6582
6683
  `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6583
6684
  }
6584
6685
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzUiTimelineComponent, decorators: [{
@@ -6589,7 +6690,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
6589
6690
  imports: [NgClass, NgTemplateOutlet],
6590
6691
  host: { class: 'block font-ui text-ui-fg' },
6591
6692
  template: `
6592
- <div class="flex" [class]="horizontal() ? 'flex-row' : 'flex-col'" [ngClass]="styleClass()">
6693
+ @if (horizontal()) {
6694
+ <!-- Nao usar a classe grid do Tailwind: o CSS legado do core (.grid, PrimeFlex) a sobrescreve com display:flex !important.
6695
+ Grade de 3 linhas (conteudo de cima / marcadores / conteudo de baixo) com subgrade por item: todos os marcadores ficam na mesma linha. -->
6696
+ <div style="display: grid; grid-template-rows: auto auto auto" [style.grid-template-columns]="'repeat(' + (value() ?? []).length + ', minmax(0, 1fr))'" [ngClass]="styleClass()">
6697
+ @for (event of value() ?? []; track $index; let index = $index; let first = $first; let last = $last) {
6698
+ <div class="tl-item min-w-0" style="display: grid; grid-row: span 3; grid-template-rows: subgrid">
6699
+ <div class="flex min-w-0 flex-col justify-end px-2 pb-2 text-center" style="grid-row: 1">
6700
+ @if (contentOnTop(index)) {
6701
+ @if (contentTemplate(); as content) {
6702
+ <ng-container [ngTemplateOutlet]="content" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6703
+ }
6704
+ } @else if (oppositeTemplate(); as opposite) {
6705
+ <ng-container [ngTemplateOutlet]="opposite" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6706
+ }
6707
+ </div>
6708
+ <div class="flex items-center" style="grid-row: 2">
6709
+ <span class="h-0.5 flex-1" [class]="first ? 'bg-transparent' : 'bg-ui-line'"></span>
6710
+ @if (markerTemplate(); as marker) {
6711
+ <ng-container [ngTemplateOutlet]="marker" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6712
+ }
6713
+ @else {
6714
+ <span class="block h-4 w-4 shrink-0 rounded-full border-2 border-ui-primary bg-ui-surface-1"></span>
6715
+ }
6716
+ <span class="h-0.5 flex-1" [class]="last ? 'bg-transparent' : 'bg-ui-line'"></span>
6717
+ </div>
6718
+ <div class="flex min-w-0 flex-col px-2 pt-2 text-center" style="grid-row: 3">
6719
+ @if (!contentOnTop(index)) {
6720
+ @if (contentTemplate(); as content) {
6721
+ <ng-container [ngTemplateOutlet]="content" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6722
+ }
6723
+ } @else if (oppositeTemplate(); as opposite) {
6724
+ <ng-container [ngTemplateOutlet]="opposite" [ngTemplateOutletContext]="{ $implicit: event, index: index }" />
6725
+ }
6726
+ </div>
6727
+ </div>
6728
+ }
6729
+ </div>
6730
+ } @else {
6731
+ <div class="flex flex-col" [ngClass]="styleClass()">
6593
6732
  @for (event of value() ?? []; track $index; let index = $index; let last = $last) {
6594
6733
  <div class="flex min-w-0 flex-1" [class]="horizontal() ? 'flex-col' : (rowReverse(index) ? 'flex-row-reverse' : 'flex-row')">
6595
6734
  <div class="flex-1" [class]="oppositeClass(index)">
@@ -6616,6 +6755,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
6616
6755
  </div>
6617
6756
  }
6618
6757
  </div>
6758
+ }
6619
6759
  `,
6620
6760
  }]
6621
6761
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzTemplateDirective), { isSignal: true }] }] } });
@@ -8280,6 +8420,11 @@ class SmzPanelComponent {
8280
8420
  header = input('', ...(ngDevMode ? [{ debugName: "header" }] : []));
8281
8421
  toggleable = input(false, { ...(ngDevMode ? { debugName: "toggleable" } : {}), transform: booleanAttribute });
8282
8422
  collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : []));
8423
+ /**
8424
+ * O que alterna o painel: `icon` (padrao; so o botao) ou `header` (o cabecalho inteiro, exceto elementos
8425
+ * interativos dentro dele, como botoes do template `icons`). Equivale ao `toggler` do `p-panel`.
8426
+ */
8427
+ toggler = input('icon', ...(ngDevMode ? [{ debugName: "toggler" }] : []));
8283
8428
  /** Antes de alternar (cancelavel nao: apenas notifica). */
8284
8429
  beforeToggle = output();
8285
8430
  afterToggle = output();
@@ -8288,6 +8433,28 @@ class SmzPanelComponent {
8288
8433
  iconsTemplate = computed(() => smzFindTemplate(this.templates(), 'icons'), ...(ngDevMode ? [{ debugName: "iconsTemplate" }] : []));
8289
8434
  footerTemplate = computed(() => smzFindTemplate(this.templates(), 'footer'), ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
8290
8435
  hasHeader = computed(() => !!this.header() || !!this.headerTemplate() || this.toggleable(), ...(ngDevMode ? [{ debugName: "hasHeader" }] : []));
8436
+ headerToggles = computed(() => this.toggleable() && this.toggler() === 'header', ...(ngDevMode ? [{ debugName: "headerToggles" }] : []));
8437
+ onIconClick(event) {
8438
+ // No modo `header` o clique no botao sobe ate o cabecalho, que ja alterna.
8439
+ if (!this.headerToggles())
8440
+ this.toggle(event);
8441
+ }
8442
+ onHeaderClick(event) {
8443
+ if (!this.headerToggles())
8444
+ return;
8445
+ const target = event.target;
8446
+ const interactive = target.closest('button, a, input, select, textarea, label, [role="button"], [role="menuitem"]');
8447
+ // Ignora controles do template `icons`; o botao-seta do proprio painel (e o cabecalho) alternam.
8448
+ if (interactive && !interactive.classList.contains('p-panel-header') && !interactive.hasAttribute('data-panel-toggle'))
8449
+ return;
8450
+ this.toggle(event);
8451
+ }
8452
+ onHeaderKey(event) {
8453
+ if (!this.headerToggles() || event.target !== event.currentTarget)
8454
+ return;
8455
+ event.preventDefault();
8456
+ this.toggle(event);
8457
+ }
8291
8458
  toggle(event) {
8292
8459
  const next = !this.collapsed();
8293
8460
  this.beforeToggle.emit({ originalEvent: event, collapsed: next });
@@ -8295,16 +8462,25 @@ class SmzPanelComponent {
8295
8462
  this.afterToggle.emit({ originalEvent: event, collapsed: next });
8296
8463
  }
8297
8464
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8298
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzPanelComponent, isStandalone: true, selector: "ui-panel", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", beforeToggle: "beforeToggle", afterToggle: "afterToggle" }, host: { classAttribute: "p-panel block overflow-hidden rounded-card border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg" }, queries: [{ propertyName: "templates", predicate: SmzTemplateDirective, isSignal: true }], ngImport: i0, template: `
8465
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzPanelComponent, isStandalone: true, selector: "ui-panel", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, toggleable: { classPropertyName: "toggleable", publicName: "toggleable", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null }, toggler: { classPropertyName: "toggler", publicName: "toggler", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange", beforeToggle: "beforeToggle", afterToggle: "afterToggle" }, host: { classAttribute: "p-panel block overflow-hidden rounded-card border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg" }, queries: [{ propertyName: "templates", predicate: SmzTemplateDirective, isSignal: true }], ngImport: i0, template: `
8299
8466
  @if (hasHeader()) {
8300
- <div class="p-panel-header flex items-center justify-between gap-2 border-b border-ui-line bg-ui-surface-1 px-4 py-3">
8467
+ <div
8468
+ class="p-panel-header flex items-center justify-between gap-2 border-b border-ui-line bg-ui-surface-1 px-4 py-3"
8469
+ [class]="headerToggles() ? 'cursor-pointer select-none hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ui-focus' : ''"
8470
+ [attr.role]="headerToggles() ? 'button' : null"
8471
+ [attr.tabindex]="headerToggles() ? 0 : null"
8472
+ [attr.aria-expanded]="headerToggles() ? !collapsed() : null"
8473
+ (click)="onHeaderClick($event)"
8474
+ (keydown.enter)="onHeaderKey($event)"
8475
+ (keydown.space)="onHeaderKey($event)"
8476
+ >
8301
8477
  <div class="min-w-0 flex-1 font-semibold">
8302
8478
  @if (headerTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ header() }} }
8303
8479
  </div>
8304
8480
  <div class="flex items-center gap-1">
8305
8481
  @if (iconsTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> }
8306
8482
  @if (toggleable()) {
8307
- <button type="button" class="inline-flex h-8 w-8 items-center justify-center rounded-full text-ui-fg-muted transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" [attr.aria-expanded]="!collapsed()" [attr.aria-label]="collapsed() ? 'Expandir' : 'Recolher'" (click)="toggle($event)">
8483
+ <button type="button" class="inline-flex h-8 w-8 items-center justify-center rounded-full text-ui-fg-muted transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" data-panel-toggle [attr.aria-expanded]="!collapsed()" [attr.aria-label]="collapsed() ? 'Expandir' : 'Recolher'" [attr.tabindex]="headerToggles() ? -1 : null" (click)="onIconClick($event)">
8308
8484
  <svg viewBox="0 0 16 16" class="h-4 w-4 transition-transform duration-ui" [class.rotate-180]="!collapsed()" fill="none" aria-hidden="true"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" /></svg>
8309
8485
  </button>
8310
8486
  }
@@ -8328,14 +8504,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
8328
8504
  host: { class: 'p-panel block overflow-hidden rounded-card border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg' },
8329
8505
  template: `
8330
8506
  @if (hasHeader()) {
8331
- <div class="p-panel-header flex items-center justify-between gap-2 border-b border-ui-line bg-ui-surface-1 px-4 py-3">
8507
+ <div
8508
+ class="p-panel-header flex items-center justify-between gap-2 border-b border-ui-line bg-ui-surface-1 px-4 py-3"
8509
+ [class]="headerToggles() ? 'cursor-pointer select-none hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ui-focus' : ''"
8510
+ [attr.role]="headerToggles() ? 'button' : null"
8511
+ [attr.tabindex]="headerToggles() ? 0 : null"
8512
+ [attr.aria-expanded]="headerToggles() ? !collapsed() : null"
8513
+ (click)="onHeaderClick($event)"
8514
+ (keydown.enter)="onHeaderKey($event)"
8515
+ (keydown.space)="onHeaderKey($event)"
8516
+ >
8332
8517
  <div class="min-w-0 flex-1 font-semibold">
8333
8518
  @if (headerTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ header() }} }
8334
8519
  </div>
8335
8520
  <div class="flex items-center gap-1">
8336
8521
  @if (iconsTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> }
8337
8522
  @if (toggleable()) {
8338
- <button type="button" class="inline-flex h-8 w-8 items-center justify-center rounded-full text-ui-fg-muted transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" [attr.aria-expanded]="!collapsed()" [attr.aria-label]="collapsed() ? 'Expandir' : 'Recolher'" (click)="toggle($event)">
8523
+ <button type="button" class="inline-flex h-8 w-8 items-center justify-center rounded-full text-ui-fg-muted transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" data-panel-toggle [attr.aria-expanded]="!collapsed()" [attr.aria-label]="collapsed() ? 'Expandir' : 'Recolher'" [attr.tabindex]="headerToggles() ? -1 : null" (click)="onIconClick($event)">
8339
8524
  <svg viewBox="0 0 16 16" class="h-4 w-4 transition-transform duration-ui" [class.rotate-180]="!collapsed()" fill="none" aria-hidden="true"><path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" /></svg>
8340
8525
  </button>
8341
8526
  }
@@ -8350,7 +8535,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
8350
8535
  }
8351
8536
  `,
8352
8537
  }]
8353
- }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], beforeToggle: [{ type: i0.Output, args: ["beforeToggle"] }], afterToggle: [{ type: i0.Output, args: ["afterToggle"] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzTemplateDirective), { isSignal: true }] }] } });
8538
+ }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], toggleable: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggleable", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], toggler: [{ type: i0.Input, args: [{ isSignal: true, alias: "toggler", required: false }] }], beforeToggle: [{ type: i0.Output, args: ["beforeToggle"] }], afterToggle: [{ type: i0.Output, args: ["afterToggle"] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzTemplateDirective), { isSignal: true }] }] } });
8354
8539
 
8355
8540
  /* eslint-disable max-len -- classes Tailwind nos templates */
8356
8541
  /**
@@ -8585,7 +8770,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
8585
8770
  const ROW_BASE = 'border-b border-ui-line transition-colors duration-ui';
8586
8771
  /**
8587
8772
  * Tabela em arvore. Substitui o `p-treeTable` do PrimeNG.
8588
- * Os templates `header`, `body`, `caption`, `footer`, `emptymessage` e `summary` usam `smzTemplate`;
8773
+ * Os templates `colgroup`, `header`, `body`, `caption`, `footer`, `emptymessage` e `summary` usam `smzTemplate`;
8589
8774
  * o `body` recebe `let-rowNode let-rowData="rowData" let-columns="columns"`.
8590
8775
  *
8591
8776
  * <ui-tree-table [value]="nodes" [columns]="cols" selectionMode="checkbox" [(selection)]="sel">
@@ -8629,6 +8814,8 @@ class SmzTreeTableComponent {
8629
8814
  page = output();
8630
8815
  templates = contentChildren(SmzTemplateDirective, ...(ngDevMode ? [{ debugName: "templates" }] : []));
8631
8816
  headerTemplate = computed(() => smzFindTemplate(this.templates(), 'header'), ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
8817
+ /** `<colgroup>` com as larguras das colunas (como no `p-treeTable`); quando existe, a tabela usa `table-layout: fixed`. */
8818
+ colgroupTemplate = computed(() => smzFindTemplate(this.templates(), 'colgroup'), ...(ngDevMode ? [{ debugName: "colgroupTemplate" }] : []));
8632
8819
  bodyTemplate = computed(() => smzFindTemplate(this.templates(), 'body'), ...(ngDevMode ? [{ debugName: "bodyTemplate" }] : []));
8633
8820
  captionTemplate = computed(() => smzFindTemplate(this.templates(), 'caption'), ...(ngDevMode ? [{ debugName: "captionTemplate" }] : []));
8634
8821
  footerTemplate = computed(() => smzFindTemplate(this.templates(), 'footer'), ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
@@ -8850,7 +9037,10 @@ class SmzTreeTableComponent {
8850
9037
  <div class="border-b border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8851
9038
  }
8852
9039
  <div class="relative overflow-auto" [style.max-height]="scrollable() ? scrollHeight() : null">
8853
- <table class="w-full border-separate border-spacing-0 text-left [&_td]:border-b [&_td]:border-ui-line [&_td]:px-4 [&_td]:py-3 [&_th]:sticky [&_th]:top-0 [&_th]:border-b [&_th]:border-ui-line [&_th]:bg-ui-surface-1 [&_th]:px-4 [&_th]:py-3 [&_th]:font-semibold" [class]="tableStyleClass() ?? ''">
9040
+ <table class="w-full border-separate border-spacing-0 text-left [&_td]:border-b [&_td]:border-ui-line [&_td]:px-4 [&_td]:py-3 [&_th]:sticky [&_th]:top-0 [&_th]:border-b [&_th]:border-ui-line [&_th]:bg-ui-surface-1 [&_th]:px-4 [&_th]:py-3 [&_th]:font-semibold" [class]="(colgroupTemplate() ? 'table-fixed ' : '') + (tableStyleClass() ?? '')">
9041
+ @if (colgroupTemplate(); as tpl) {
9042
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" />
9043
+ }
8854
9044
  <thead>
8855
9045
  @if (headerTemplate(); as tpl) {
8856
9046
  <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" />
@@ -8899,7 +9089,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
8899
9089
  <div class="border-b border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8900
9090
  }
8901
9091
  <div class="relative overflow-auto" [style.max-height]="scrollable() ? scrollHeight() : null">
8902
- <table class="w-full border-separate border-spacing-0 text-left [&_td]:border-b [&_td]:border-ui-line [&_td]:px-4 [&_td]:py-3 [&_th]:sticky [&_th]:top-0 [&_th]:border-b [&_th]:border-ui-line [&_th]:bg-ui-surface-1 [&_th]:px-4 [&_th]:py-3 [&_th]:font-semibold" [class]="tableStyleClass() ?? ''">
9092
+ <table class="w-full border-separate border-spacing-0 text-left [&_td]:border-b [&_td]:border-ui-line [&_td]:px-4 [&_td]:py-3 [&_th]:sticky [&_th]:top-0 [&_th]:border-b [&_th]:border-ui-line [&_th]:bg-ui-surface-1 [&_th]:px-4 [&_th]:py-3 [&_th]:font-semibold" [class]="(colgroupTemplate() ? 'table-fixed ' : '') + (tableStyleClass() ?? '')">
9093
+ @if (colgroupTemplate(); as tpl) {
9094
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" />
9095
+ }
8903
9096
  <thead>
8904
9097
  @if (headerTemplate(); as tpl) {
8905
9098
  <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" />