@ngx-smz/ui-kit 21.9.0-next.3 → 21.9.0-next.5

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, input, booleanAttribute, computed, Directive, inject, TemplateRef, HostAttributeToken, ChangeDetectionStrategy, Component, ElementRef, output, forwardRef, Injector, DestroyRef, afterNextRender, Renderer2, effect, InjectionToken, viewChild, ViewContainerRef, Injectable, model, contentChildren, contentChild } from '@angular/core';
2
+ import { signal, input, booleanAttribute, computed, Directive, inject, TemplateRef, HostAttributeToken, ChangeDetectionStrategy, Component, ElementRef, afterEveryRender, output, forwardRef, Injector, DestroyRef, afterNextRender, Renderer2, effect, InjectionToken, viewChild, ViewContainerRef, Injectable, model, contentChildren, contentChild } from '@angular/core';
3
3
  import { Overlay } from '@angular/cdk/overlay';
4
4
  import { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';
5
5
  import * as i1 from '@angular/forms';
@@ -644,18 +644,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
644
644
  /** Area de texto. Substitui o `pTextarea` / `pInputTextarea` do PrimeNG. */
645
645
  class SmzTextareaDirective {
646
646
  invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : {}), transform: booleanAttribute });
647
+ /** Cresce com o conteudo (equivale ao `autoResize` do `pTextarea`). */
648
+ autoResize = input(false, { ...(ngDevMode ? { debugName: "autoResize" } : {}), transform: booleanAttribute });
649
+ el = inject(ElementRef);
650
+ constructor() {
651
+ afterEveryRender(() => this.resize());
652
+ }
653
+ resize() {
654
+ if (!this.autoResize())
655
+ return;
656
+ const textarea = this.el.nativeElement;
657
+ textarea.style.overflow = 'hidden';
658
+ textarea.style.height = 'auto';
659
+ textarea.style.height = `${textarea.scrollHeight}px`;
660
+ }
647
661
  staticClass = smzStaticHostClass();
648
662
  classes = computed(() => smzMergeClasses(textareaClasses({ invalid: String(this.invalid()) }), this.staticClass), ...(ngDevMode ? [{ debugName: "classes" }] : []));
649
663
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTextareaDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
650
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: SmzTextareaDirective, isStandalone: true, selector: "textarea[smzTextarea]", inputs: { invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.aria-invalid": "invalid() || null" } }, ngImport: i0 });
664
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: SmzTextareaDirective, isStandalone: true, selector: "textarea[smzTextarea]", inputs: { invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, autoResize: { classPropertyName: "autoResize", publicName: "autoResize", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "input": "resize()" }, properties: { "class": "classes()", "attr.aria-invalid": "invalid() || null" } }, ngImport: i0 });
651
665
  }
652
666
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTextareaDirective, decorators: [{
653
667
  type: Directive,
654
668
  args: [{
655
669
  selector: 'textarea[smzTextarea]',
656
- host: { '[class]': 'classes()', '[attr.aria-invalid]': 'invalid() || null' },
670
+ host: { '[class]': 'classes()', '[attr.aria-invalid]': 'invalid() || null', '(input)': 'resize()' },
657
671
  }]
658
- }], propDecorators: { invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }] } });
672
+ }], ctorParameters: () => [], propDecorators: { invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], autoResize: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoResize", required: false }] }] } });
659
673
 
660
674
  /**
661
675
  * Checkbox do ui-kit. Substitui o `p-checkbox` do PrimeNG.
@@ -665,6 +679,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
665
679
  */
666
680
  class SmzCheckboxComponent extends SmzValueAccessor {
667
681
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
682
+ inputId = input('', ...(ngDevMode ? [{ debugName: "inputId" }] : []));
668
683
  /** Valor deste item quando o modelo e um array (modo grupo). */
669
684
  value = input(undefined, ...(ngDevMode ? [{ debugName: "value" }] : []));
670
685
  /** Forca o modo booleano mesmo com `value` informado. Mantido por compatibilidade com o Prime. */
@@ -691,7 +706,7 @@ class SmzCheckboxComponent extends SmzValueAccessor {
691
706
  this.changed.emit({ checked: this.checked(), value: this.current() });
692
707
  }
693
708
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzCheckboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
694
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzCheckboxComponent, isStandalone: true, selector: "ui-checkbox", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, binary: { classPropertyName: "binary", publicName: "binary", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "inline-flex" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SmzCheckboxComponent), multi: true }], usesInheritance: true, ngImport: i0, template: `
709
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzCheckboxComponent, isStandalone: true, selector: "ui-checkbox", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, binary: { classPropertyName: "binary", publicName: "binary", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "inline-flex" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SmzCheckboxComponent), multi: true }], usesInheritance: true, ngImport: i0, template: `
695
710
  <label
696
711
  class="inline-flex items-center gap-2 font-ui text-ui-md text-ui-fg"
697
712
  [class]="isDisabled() ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'"
@@ -699,6 +714,7 @@ class SmzCheckboxComponent extends SmzValueAccessor {
699
714
  <input
700
715
  type="checkbox"
701
716
  class="peer sr-only"
717
+ [attr.id]="inputId() || null"
702
718
  [name]="name()"
703
719
  [checked]="checked()"
704
720
  [disabled]="isDisabled()"
@@ -737,6 +753,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
737
753
  <input
738
754
  type="checkbox"
739
755
  class="peer sr-only"
756
+ [attr.id]="inputId() || null"
740
757
  [name]="name()"
741
758
  [checked]="checked()"
742
759
  [disabled]="isDisabled()"
@@ -760,7 +777,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
760
777
  </label>
761
778
  `,
762
779
  }]
763
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], binary: [{ type: i0.Input, args: [{ isSignal: true, alias: "binary", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
780
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], binary: [{ type: i0.Input, args: [{ isSignal: true, alias: "binary", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
764
781
 
765
782
  /**
766
783
  * Radio do ui-kit. Substitui o `p-radiobutton` do PrimeNG.
@@ -1857,6 +1874,15 @@ class SmzDialogComponent {
1857
1874
  style = input(null, ...(ngDevMode ? [{ debugName: "style" }] : []));
1858
1875
  styleClass = input('', ...(ngDevMode ? [{ debugName: "styleClass" }] : []));
1859
1876
  baseZIndex = input(0, ...(ngDevMode ? [{ debugName: "baseZIndex" }] : []));
1877
+ /** Permite arrastar pelo cabecalho. */
1878
+ draggable = input(false, { ...(ngDevMode ? { debugName: "draggable" } : {}), transform: booleanAttribute });
1879
+ /** Mostra a alca nativa de redimensionar no canto inferior direito. */
1880
+ resizable = input(false, { ...(ngDevMode ? { debugName: "resizable" } : {}), transform: booleanAttribute });
1881
+ /** Mostra o botao de maximizar no cabecalho padrao (com `smzTemplate="header"` use `maximize()`). */
1882
+ maximizable = input(false, { ...(ngDevMode ? { debugName: "maximizable" } : {}), transform: booleanAttribute });
1883
+ maximized = model(false, ...(ngDevMode ? [{ debugName: "maximized" }] : []));
1884
+ /** Posicao na tela (como o `position` do `p-dialog`). */
1885
+ position = input('center', ...(ngDevMode ? [{ debugName: "position" }] : []));
1860
1886
  shown = output();
1861
1887
  hidden = output();
1862
1888
  panel = viewChild.required('panel');
@@ -1867,6 +1893,8 @@ class SmzDialogComponent {
1867
1893
  viewContainer = inject(ViewContainerRef);
1868
1894
  host = inject(ElementRef);
1869
1895
  overlayRef;
1896
+ dx = signal(0, ...(ngDevMode ? [{ debugName: "dx" }] : []));
1897
+ dy = signal(0, ...(ngDevMode ? [{ debugName: "dy" }] : []));
1870
1898
  constructor() {
1871
1899
  effect(() => {
1872
1900
  if (this.visible())
@@ -1874,6 +1902,51 @@ class SmzDialogComponent {
1874
1902
  else
1875
1903
  this.dispose();
1876
1904
  });
1905
+ effect(() => {
1906
+ const position = this.position();
1907
+ this.overlayRef?.updatePositionStrategy(this.strategyFor(position));
1908
+ });
1909
+ }
1910
+ /** Alterna entre maximizado e normal. */
1911
+ maximize() {
1912
+ this.maximized.update((value) => !value);
1913
+ this.dx.set(0);
1914
+ this.dy.set(0);
1915
+ }
1916
+ startDrag(event) {
1917
+ if (!this.draggable() || this.maximized() || event.target.closest('button'))
1918
+ return;
1919
+ event.preventDefault();
1920
+ const startX = event.clientX - this.dx();
1921
+ const startY = event.clientY - this.dy();
1922
+ const move = (e) => {
1923
+ this.dx.set(e.clientX - startX);
1924
+ this.dy.set(e.clientY - startY);
1925
+ };
1926
+ const up = () => {
1927
+ document.removeEventListener('pointermove', move);
1928
+ document.removeEventListener('pointerup', up);
1929
+ };
1930
+ document.addEventListener('pointermove', move);
1931
+ document.addEventListener('pointerup', up);
1932
+ }
1933
+ strategyFor(position) {
1934
+ const strategy = this.overlay.position().global();
1935
+ const horizontal = position.includes('left') ? 'left' : position.includes('right') ? 'right' : 'center';
1936
+ const vertical = position.startsWith('top') ? 'top' : position.startsWith('bottom') ? 'bottom' : position === 'left' || position === 'right' || position === 'center' ? 'center' : 'center';
1937
+ if (horizontal === 'left')
1938
+ strategy.left('0');
1939
+ else if (horizontal === 'right')
1940
+ strategy.right('0');
1941
+ else
1942
+ strategy.centerHorizontally();
1943
+ if (vertical === 'top')
1944
+ strategy.top('0');
1945
+ else if (vertical === 'bottom')
1946
+ strategy.bottom('0');
1947
+ else
1948
+ strategy.centerVertically();
1949
+ return strategy;
1877
1950
  }
1878
1951
  close() {
1879
1952
  this.visible.set(false);
@@ -1887,7 +1960,7 @@ class SmzDialogComponent {
1887
1960
  const modal = this.modal();
1888
1961
  this.overlayRef = this.overlay.create({
1889
1962
  hasBackdrop: modal,
1890
- positionStrategy: this.overlay.position().global().centerHorizontally().centerVertically(),
1963
+ positionStrategy: this.strategyFor(this.position()),
1891
1964
  scrollStrategy: this.overlay.scrollStrategies.block(),
1892
1965
  });
1893
1966
  SmzZIndex.set('modal', this.overlayRef.hostElement, 1100 + this.baseZIndex());
@@ -1919,24 +1992,33 @@ class SmzDialogComponent {
1919
1992
  this.overlayRef?.overlayElement.querySelector('[role="dialog"]')?.setAttribute('data-testid', testId);
1920
1993
  }
1921
1994
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1922
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzDialogComponent, isStandalone: true, selector: "ui-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, dismissableMask: { classPropertyName: "dismissableMask", publicName: "dismissableMask", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, baseZIndex: { classPropertyName: "baseZIndex", publicName: "baseZIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", shown: "shown", hidden: "hidden" }, queries: [{ propertyName: "templates", predicate: SmzTemplateDirective, isSignal: true }], viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
1995
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzDialogComponent, isStandalone: true, selector: "ui-dialog", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, modal: { classPropertyName: "modal", publicName: "modal", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, dismissableMask: { classPropertyName: "dismissableMask", publicName: "dismissableMask", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, baseZIndex: { classPropertyName: "baseZIndex", publicName: "baseZIndex", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, maximizable: { classPropertyName: "maximizable", publicName: "maximizable", isSignal: true, isRequired: false, transformFunction: null }, maximized: { classPropertyName: "maximized", publicName: "maximized", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { visible: "visibleChange", maximized: "maximizedChange", shown: "shown", hidden: "hidden" }, queries: [{ propertyName: "templates", predicate: SmzTemplateDirective, isSignal: true }], viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, isSignal: true }], ngImport: i0, template: `
1923
1996
  <ng-template #panel>
1924
1997
  <div
1925
1998
  role="dialog"
1926
1999
  aria-modal="true"
1927
2000
  [attr.aria-label]="header() || null"
1928
- class="pointer-events-auto 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"
1929
- [class]="styleClass() ?? ''"
1930
- [ngStyle]="style()"
2001
+ class="pointer-events-auto flex flex-col border border-ui-line bg-ui-surface-2 font-ui text-ui-fg shadow-overlay"
2002
+ [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() ?? '')"
2003
+ [ngStyle]="maximized() ? null : style()"
2004
+ [style.transform]="maximized() || (dx() === 0 && dy() === 0) ? null : 'translate(' + dx() + 'px, ' + dy() + 'px)'"
1931
2005
  >
1932
2006
  @if (headerTemplate(); as headerTpl) {
1933
- <div class="border-b border-ui-line px-4 py-3">
2007
+ <div class="border-b border-ui-line px-4 py-3" [class.cursor-move]="draggable() && !maximized()" (pointerdown)="startDrag($event)">
1934
2008
  <ng-container [ngTemplateOutlet]="headerTpl" />
1935
2009
  </div>
1936
2010
  }
1937
2011
  @else if (header() || closable()) {
1938
- <div class="flex items-center justify-between gap-4 border-b border-ui-line px-4 py-3">
2012
+ <div class="flex items-center justify-between gap-4 border-b border-ui-line px-4 py-3" [class.cursor-move]="draggable() && !maximized()" (pointerdown)="startDrag($event)">
1939
2013
  <span class="text-ui-lg font-medium">{{ header() }}</span>
2014
+ <div class="flex items-center gap-1">
2015
+ @if (maximizable()) {
2016
+ <button type="button" class="inline-flex h-8 w-8 cursor-pointer 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-label]="maximized() ? 'Restaurar' : 'Maximizar'" (click)="maximize()">
2017
+ <svg viewBox="0 0 16 16" class="h-4 w-4" fill="none" aria-hidden="true">
2018
+ @if (maximized()) { <path d="M5 3h8v8M3 5h8v8H3z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" /> } @else { <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" /> }
2019
+ </svg>
2020
+ </button>
2021
+ }
1940
2022
  @if (closable()) {
1941
2023
  <button
1942
2024
  type="button"
@@ -1949,6 +2031,7 @@ class SmzDialogComponent {
1949
2031
  </svg>
1950
2032
  </button>
1951
2033
  }
2034
+ </div>
1952
2035
  </div>
1953
2036
  }
1954
2037
  <div class="min-h-0 flex-1 overflow-auto p-4"><ng-content /></div>
@@ -1973,18 +2056,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
1973
2056
  role="dialog"
1974
2057
  aria-modal="true"
1975
2058
  [attr.aria-label]="header() || null"
1976
- class="pointer-events-auto 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"
1977
- [class]="styleClass() ?? ''"
1978
- [ngStyle]="style()"
2059
+ class="pointer-events-auto flex flex-col border border-ui-line bg-ui-surface-2 font-ui text-ui-fg shadow-overlay"
2060
+ [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() ?? '')"
2061
+ [ngStyle]="maximized() ? null : style()"
2062
+ [style.transform]="maximized() || (dx() === 0 && dy() === 0) ? null : 'translate(' + dx() + 'px, ' + dy() + 'px)'"
1979
2063
  >
1980
2064
  @if (headerTemplate(); as headerTpl) {
1981
- <div class="border-b border-ui-line px-4 py-3">
2065
+ <div class="border-b border-ui-line px-4 py-3" [class.cursor-move]="draggable() && !maximized()" (pointerdown)="startDrag($event)">
1982
2066
  <ng-container [ngTemplateOutlet]="headerTpl" />
1983
2067
  </div>
1984
2068
  }
1985
2069
  @else if (header() || closable()) {
1986
- <div class="flex items-center justify-between gap-4 border-b border-ui-line px-4 py-3">
2070
+ <div class="flex items-center justify-between gap-4 border-b border-ui-line px-4 py-3" [class.cursor-move]="draggable() && !maximized()" (pointerdown)="startDrag($event)">
1987
2071
  <span class="text-ui-lg font-medium">{{ header() }}</span>
2072
+ <div class="flex items-center gap-1">
2073
+ @if (maximizable()) {
2074
+ <button type="button" class="inline-flex h-8 w-8 cursor-pointer 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-label]="maximized() ? 'Restaurar' : 'Maximizar'" (click)="maximize()">
2075
+ <svg viewBox="0 0 16 16" class="h-4 w-4" fill="none" aria-hidden="true">
2076
+ @if (maximized()) { <path d="M5 3h8v8M3 5h8v8H3z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" /> } @else { <rect x="3" y="3" width="10" height="10" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round" /> }
2077
+ </svg>
2078
+ </button>
2079
+ }
1988
2080
  @if (closable()) {
1989
2081
  <button
1990
2082
  type="button"
@@ -1997,6 +2089,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
1997
2089
  </svg>
1998
2090
  </button>
1999
2091
  }
2092
+ </div>
2000
2093
  </div>
2001
2094
  }
2002
2095
  <div class="min-h-0 flex-1 overflow-auto p-4"><ng-content /></div>
@@ -2009,7 +2102,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
2009
2102
  </ng-template>
2010
2103
  `,
2011
2104
  }]
2012
- }], ctorParameters: () => [], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], dismissableMask: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissableMask", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], style: [{ type: i0.Input, args: [{ isSignal: true, alias: "style", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], baseZIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "baseZIndex", required: false }] }], shown: [{ type: i0.Output, args: ["shown"] }], hidden: [{ type: i0.Output, args: ["hidden"] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzTemplateDirective), { isSignal: true }] }] } });
2105
+ }], ctorParameters: () => [], propDecorators: { visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }, { type: i0.Output, args: ["visibleChange"] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], modal: [{ type: i0.Input, args: [{ isSignal: true, alias: "modal", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], dismissableMask: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissableMask", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], style: [{ type: i0.Input, args: [{ isSignal: true, alias: "style", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], baseZIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "baseZIndex", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], resizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "resizable", required: false }] }], maximizable: [{ type: i0.Input, args: [{ isSignal: true, alias: "maximizable", required: false }] }], maximized: [{ type: i0.Input, args: [{ isSignal: true, alias: "maximized", required: false }] }, { type: i0.Output, args: ["maximizedChange"] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], shown: [{ type: i0.Output, args: ["shown"] }], hidden: [{ type: i0.Output, args: ["hidden"] }], panel: [{ type: i0.ViewChild, args: ['panel', { isSignal: true }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzTemplateDirective), { isSignal: true }] }] } });
2013
2106
 
2014
2107
  const POSITIONS$2 = [
2015
2108
  { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 8 },
@@ -3811,9 +3904,11 @@ class SmzSelectButtonComponent extends SmzValueAccessor {
3811
3904
  /** Aceito por compatibilidade com o `p-selectbutton`; sem efeito. */
3812
3905
  appendTo = input(undefined, ...(ngDevMode ? [{ debugName: "appendTo" }] : []));
3813
3906
  changed = output();
3907
+ /** Sem `optionLabel`/`optionValue`, opcoes-objeto com `label`/`value` sao lidas automaticamente (como no PrimeNG). */
3908
+ sample = computed(() => (this.options() ?? [])[0], ...(ngDevMode ? [{ debugName: "sample" }] : []));
3814
3909
  config = computed(() => ({
3815
- optionLabel: this.optionLabel(),
3816
- optionValue: this.optionValue(),
3910
+ optionLabel: this.optionLabel() ?? (typeof this.sample() === 'object' && this.sample() !== null && 'label' in this.sample() ? 'label' : null),
3911
+ optionValue: this.optionValue() ?? (typeof this.sample() === 'object' && this.sample() !== null && 'value' in this.sample() ? 'value' : null),
3817
3912
  optionDisabled: this.optionDisabled(),
3818
3913
  dataKey: this.dataKey(),
3819
3914
  }), ...(ngDevMode ? [{ debugName: "config" }] : []));
@@ -5677,6 +5772,8 @@ class SmzInputMaskComponent extends SmzValueAccessor {
5677
5772
  placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
5678
5773
  readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : {}), transform: booleanAttribute });
5679
5774
  inputId = input('', ...(ngDevMode ? [{ debugName: "inputId" }] : []));
5775
+ /** Tipo do `<input>` nativo (`text`, `tel`, `password`...). */
5776
+ type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : []));
5680
5777
  inputed = output();
5681
5778
  blurred = output();
5682
5779
  completed = output();
@@ -5825,10 +5922,10 @@ class SmzInputMaskComponent extends SmzValueAccessor {
5825
5922
  this.field().nativeElement.setSelectionRange(position, position);
5826
5923
  }
5827
5924
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzInputMaskComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
5828
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.1", type: SmzInputMaskComponent, isStandalone: true, selector: "ui-input-mask", inputs: { mask: { classPropertyName: "mask", publicName: "mask", isSignal: true, isRequired: false, transformFunction: null }, slotChar: { classPropertyName: "slotChar", publicName: "slotChar", isSignal: true, isRequired: false, transformFunction: null }, characterPattern: { classPropertyName: "characterPattern", publicName: "characterPattern", isSignal: true, isRequired: false, transformFunction: null }, unmask: { classPropertyName: "unmask", publicName: "unmask", isSignal: true, isRequired: false, transformFunction: null }, autoClear: { classPropertyName: "autoClear", publicName: "autoClear", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { inputed: "inputed", blurred: "blurred", completed: "completed" }, host: { classAttribute: "flex min-w-0" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SmzInputMaskComponent), multi: true }], viewQueries: [{ propertyName: "field", first: true, predicate: ["field"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
5925
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.1", type: SmzInputMaskComponent, isStandalone: true, selector: "ui-input-mask", inputs: { mask: { classPropertyName: "mask", publicName: "mask", isSignal: true, isRequired: false, transformFunction: null }, slotChar: { classPropertyName: "slotChar", publicName: "slotChar", isSignal: true, isRequired: false, transformFunction: null }, characterPattern: { classPropertyName: "characterPattern", publicName: "characterPattern", isSignal: true, isRequired: false, transformFunction: null }, unmask: { classPropertyName: "unmask", publicName: "unmask", isSignal: true, isRequired: false, transformFunction: null }, autoClear: { classPropertyName: "autoClear", publicName: "autoClear", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { inputed: "inputed", blurred: "blurred", completed: "completed" }, host: { classAttribute: "flex min-w-0" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SmzInputMaskComponent), multi: true }], viewQueries: [{ propertyName: "field", first: true, predicate: ["field"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
5829
5926
  <input
5830
5927
  #field
5831
- type="text"
5928
+ [attr.type]="type()"
5832
5929
  class="h-control w-full min-w-0 rounded-control border border-ui-line-strong bg-ui-surface-1 px-control-x font-ui text-ui-md text-ui-fg transition-colors duration-ui placeholder:text-ui-fg-subtle focus:outline-none focus:ring-2 focus:ring-ui-focus disabled:cursor-not-allowed disabled:opacity-50 [&.ng-invalid.ng-dirty]:border-ui-danger"
5833
5930
  [attr.id]="inputId() || null"
5834
5931
  [attr.placeholder]="placeholder() || null"
@@ -5853,7 +5950,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
5853
5950
  template: `
5854
5951
  <input
5855
5952
  #field
5856
- type="text"
5953
+ [attr.type]="type()"
5857
5954
  class="h-control w-full min-w-0 rounded-control border border-ui-line-strong bg-ui-surface-1 px-control-x font-ui text-ui-md text-ui-fg transition-colors duration-ui placeholder:text-ui-fg-subtle focus:outline-none focus:ring-2 focus:ring-ui-focus disabled:cursor-not-allowed disabled:opacity-50 [&.ng-invalid.ng-dirty]:border-ui-danger"
5858
5955
  [attr.id]="inputId() || null"
5859
5956
  [attr.placeholder]="placeholder() || null"
@@ -5868,7 +5965,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
5868
5965
  />
5869
5966
  `,
5870
5967
  }]
5871
- }], propDecorators: { mask: [{ type: i0.Input, args: [{ isSignal: true, alias: "mask", required: false }] }], slotChar: [{ type: i0.Input, args: [{ isSignal: true, alias: "slotChar", required: false }] }], characterPattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "characterPattern", required: false }] }], unmask: [{ type: i0.Input, args: [{ isSignal: true, alias: "unmask", required: false }] }], autoClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClear", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], inputed: [{ type: i0.Output, args: ["inputed"] }], blurred: [{ type: i0.Output, args: ["blurred"] }], completed: [{ type: i0.Output, args: ["completed"] }], field: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }] } });
5968
+ }], propDecorators: { mask: [{ type: i0.Input, args: [{ isSignal: true, alias: "mask", required: false }] }], slotChar: [{ type: i0.Input, args: [{ isSignal: true, alias: "slotChar", required: false }] }], characterPattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "characterPattern", required: false }] }], unmask: [{ type: i0.Input, args: [{ isSignal: true, alias: "unmask", required: false }] }], autoClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoClear", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], inputed: [{ type: i0.Output, args: ["inputed"] }], blurred: [{ type: i0.Output, args: ["blurred"] }], completed: [{ type: i0.Output, args: ["completed"] }], field: [{ type: i0.ViewChild, args: ['field', { isSignal: true }] }] } });
5872
5969
 
5873
5970
  /* eslint-disable max-len -- classes Tailwind nos templates */
5874
5971
  const DEFAULT_MEDIUM = '^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})';
@@ -6028,15 +6125,19 @@ class SmzColorPickerComponent extends SmzValueAccessor {
6028
6125
  inputId = input('', ...(ngDevMode ? [{ debugName: "inputId" }] : []));
6029
6126
  /** Aceito por compatibilidade com o `p-colorpicker`; sem efeito. */
6030
6127
  appendTo = input(undefined, ...(ngDevMode ? [{ debugName: "appendTo" }] : []));
6128
+ /** Emitido quando o usuario escolhe uma cor (equivale ao `onChange` do `p-colorpicker`). */
6129
+ changed = output();
6031
6130
  hex = computed(() => {
6032
6131
  const raw = (this.current() ?? '').replace('#', '');
6033
6132
  return /^[0-9a-fA-F]{6}$/.test(raw) ? `#${raw.toLowerCase()}` : '#000000';
6034
6133
  }, ...(ngDevMode ? [{ debugName: "hex" }] : []));
6035
6134
  onInput(event) {
6036
- this.commit(event.target.value.replace('#', ''));
6135
+ const value = event.target.value.replace('#', '');
6136
+ this.commit(value);
6137
+ this.changed.emit({ originalEvent: event, value });
6037
6138
  }
6038
6139
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzColorPickerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
6039
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzColorPickerComponent, isStandalone: true, selector: "ui-color-picker", inputs: { inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "inline-flex" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SmzColorPickerComponent), multi: true }], usesInheritance: true, ngImport: i0, template: `
6140
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzColorPickerComponent, isStandalone: true, selector: "ui-color-picker", inputs: { inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, appendTo: { classPropertyName: "appendTo", publicName: "appendTo", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changed: "changed" }, host: { classAttribute: "inline-flex" }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SmzColorPickerComponent), multi: true }], usesInheritance: true, ngImport: i0, template: `
6040
6141
  <input
6041
6142
  type="color"
6042
6143
  class="h-control w-12 cursor-pointer rounded-control border border-ui-line-strong bg-ui-surface-1 p-1 focus:outline-none focus:ring-2 focus:ring-ui-focus disabled:cursor-not-allowed disabled:opacity-50"
@@ -6067,7 +6168,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
6067
6168
  />
6068
6169
  `,
6069
6170
  }]
6070
- }], propDecorators: { inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], appendTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendTo", required: false }] }] } });
6171
+ }], propDecorators: { inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], appendTo: [{ type: i0.Input, args: [{ isSignal: true, alias: "appendTo", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
6071
6172
 
6072
6173
  /* eslint-disable max-len -- classes Tailwind nos templates */
6073
6174
  /**
@@ -6218,12 +6319,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
6218
6319
  class SmzAccordionComponent {
6219
6320
  value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
6220
6321
  multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : {}), transform: booleanAttribute });
6322
+ /** Um painel foi aberto (equivale ao `onOpen` do `p-accordion`). */
6323
+ opened = output();
6324
+ /** Um painel foi fechado (equivale ao `onClose`). */
6325
+ closed = output();
6326
+ /** Aceito por compatibilidade com o `p-accordion`; sem efeito. */
6327
+ transitionOptions = input(null, ...(ngDevMode ? [{ debugName: "transitionOptions" }] : []));
6221
6328
  isOpen(value) {
6222
6329
  const current = this.value();
6223
6330
  return Array.isArray(current) ? current.includes(value) : current === value;
6224
6331
  }
6225
6332
  toggle(value) {
6226
6333
  const open = this.isOpen(value);
6334
+ (open ? this.closed : this.opened).emit({ value });
6227
6335
  if (this.multiple()) {
6228
6336
  const current = Array.isArray(this.value()) ? this.value() : this.value() === null ? [] : [this.value()];
6229
6337
  this.value.set(open ? current.filter((entry) => entry !== value) : [...current, value]);
@@ -6233,7 +6341,7 @@ class SmzAccordionComponent {
6233
6341
  }
6234
6342
  }
6235
6343
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzAccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6236
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzAccordionComponent, isStandalone: true, selector: "ui-accordion", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { classAttribute: "block overflow-hidden rounded-control border border-ui-line font-ui text-ui-fg" }, ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
6344
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzAccordionComponent, isStandalone: true, selector: "ui-accordion", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, transitionOptions: { classPropertyName: "transitionOptions", publicName: "transitionOptions", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", opened: "opened", closed: "closed" }, host: { classAttribute: "block overflow-hidden rounded-control border border-ui-line font-ui text-ui-fg" }, ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
6237
6345
  }
6238
6346
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzAccordionComponent, decorators: [{
6239
6347
  type: Component,
@@ -6243,7 +6351,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
6243
6351
  host: { class: 'block overflow-hidden rounded-control border border-ui-line font-ui text-ui-fg' },
6244
6352
  template: '<ng-content />',
6245
6353
  }]
6246
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }] } });
6354
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], transitionOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "transitionOptions", required: false }] }] } });
6247
6355
  class SmzAccordionPanelComponent {
6248
6356
  value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
6249
6357
  accordion = inject(SmzAccordionComponent);
@@ -6597,7 +6705,7 @@ class SmzPaginatorComponent {
6597
6705
  <button type="button" class="inline-flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-control px-2 font-ui text-ui-sm text-ui-fg transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent" aria-label="Pagina anterior" [disabled]="isFirst()" (click)="goTo(page() - 1)">
6598
6706
  <svg viewBox="0 0 16 16" class="h-4 w-4" fill="none" aria-hidden="true"><path d="M10 4L6 8l4 4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" /></svg>
6599
6707
  </button>
6600
- @if (showPageLinks()) {
6708
+ @if (showPageLinks() && totalRecords() > 0) {
6601
6709
  @for (link of links(); track link) {
6602
6710
  <button
6603
6711
  type="button"
@@ -6642,7 +6750,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
6642
6750
  <button type="button" class="inline-flex h-8 min-w-8 cursor-pointer items-center justify-center rounded-control px-2 font-ui text-ui-sm text-ui-fg transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:bg-transparent" aria-label="Pagina anterior" [disabled]="isFirst()" (click)="goTo(page() - 1)">
6643
6751
  <svg viewBox="0 0 16 16" class="h-4 w-4" fill="none" aria-hidden="true"><path d="M10 4L6 8l4 4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" /></svg>
6644
6752
  </button>
6645
- @if (showPageLinks()) {
6753
+ @if (showPageLinks() && totalRecords() > 0) {
6646
6754
  @for (link of links(); track link) {
6647
6755
  <button
6648
6756
  type="button"
@@ -7991,9 +8099,1144 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImpor
7991
8099
  args: [{ providedIn: 'root' }]
7992
8100
  }] });
7993
8101
 
8102
+ /* eslint-disable max-len -- classes Tailwind nos templates */
8103
+ /**
8104
+ * Card. Substitui o `p-card` do PrimeNG.
8105
+ * O conteudo padrao vai no corpo; `header`, `title`, `subtitle` e `footer` podem ser strings ou templates.
8106
+ *
8107
+ * <ui-card header="Titulo" subheader="Sub">conteudo<ng-template smzTemplate="footer">...</ng-template></ui-card>
8108
+ */
8109
+ class SmzCardComponent {
8110
+ /** Titulo em texto (equivale ao slot `title`). */
8111
+ header = input('', ...(ngDevMode ? [{ debugName: "header" }] : []));
8112
+ /** Subtitulo em texto (equivale ao slot `subtitle`). */
8113
+ subheader = input('', ...(ngDevMode ? [{ debugName: "subheader" }] : []));
8114
+ templates = contentChildren(SmzTemplateDirective, ...(ngDevMode ? [{ debugName: "templates" }] : []));
8115
+ headerTemplate = computed(() => smzFindTemplate(this.templates(), 'header'), ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
8116
+ titleTemplate = computed(() => smzFindTemplate(this.templates(), 'title'), ...(ngDevMode ? [{ debugName: "titleTemplate" }] : []));
8117
+ subtitleTemplate = computed(() => smzFindTemplate(this.templates(), 'subtitle'), ...(ngDevMode ? [{ debugName: "subtitleTemplate" }] : []));
8118
+ footerTemplate = computed(() => smzFindTemplate(this.templates(), 'footer'), ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
8119
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzCardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8120
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzCardComponent, isStandalone: true, selector: "ui-card", inputs: { header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, subheader: { classPropertyName: "subheader", publicName: "subheader", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "p-card flex flex-col overflow-hidden rounded-card border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg shadow-card" }, queries: [{ propertyName: "templates", predicate: SmzTemplateDirective, isSignal: true }], ngImport: i0, template: `
8121
+ @if (headerTemplate(); as tpl) {
8122
+ <div class="p-card-header"><ng-container [ngTemplateOutlet]="tpl" /></div>
8123
+ }
8124
+ <div class="p-card-body flex flex-1 flex-col gap-2 p-5">
8125
+ @if (titleTemplate() || header()) {
8126
+ <div class="p-card-title text-ui-xl font-semibold">
8127
+ @if (titleTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ header() }} }
8128
+ </div>
8129
+ }
8130
+ @if (subtitleTemplate() || subheader()) {
8131
+ <div class="p-card-subtitle text-ui-fg-muted">
8132
+ @if (subtitleTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ subheader() }} }
8133
+ </div>
8134
+ }
8135
+ <div class="p-card-content flex-1"><ng-content /></div>
8136
+ @if (footerTemplate(); as tpl) {
8137
+ <div class="p-card-footer"><ng-container [ngTemplateOutlet]="tpl" /></div>
8138
+ }
8139
+ </div>
8140
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8141
+ }
8142
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzCardComponent, decorators: [{
8143
+ type: Component,
8144
+ args: [{
8145
+ selector: 'ui-card',
8146
+ changeDetection: ChangeDetectionStrategy.OnPush,
8147
+ imports: [NgTemplateOutlet],
8148
+ host: { class: 'p-card flex flex-col overflow-hidden rounded-card border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg shadow-card' },
8149
+ template: `
8150
+ @if (headerTemplate(); as tpl) {
8151
+ <div class="p-card-header"><ng-container [ngTemplateOutlet]="tpl" /></div>
8152
+ }
8153
+ <div class="p-card-body flex flex-1 flex-col gap-2 p-5">
8154
+ @if (titleTemplate() || header()) {
8155
+ <div class="p-card-title text-ui-xl font-semibold">
8156
+ @if (titleTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ header() }} }
8157
+ </div>
8158
+ }
8159
+ @if (subtitleTemplate() || subheader()) {
8160
+ <div class="p-card-subtitle text-ui-fg-muted">
8161
+ @if (subtitleTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ subheader() }} }
8162
+ </div>
8163
+ }
8164
+ <div class="p-card-content flex-1"><ng-content /></div>
8165
+ @if (footerTemplate(); as tpl) {
8166
+ <div class="p-card-footer"><ng-container [ngTemplateOutlet]="tpl" /></div>
8167
+ }
8168
+ </div>
8169
+ `,
8170
+ }]
8171
+ }], propDecorators: { header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], subheader: [{ type: i0.Input, args: [{ isSignal: true, alias: "subheader", required: false }] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzTemplateDirective), { isSignal: true }] }] } });
8172
+
8173
+ /* eslint-disable max-len -- classes Tailwind nos templates */
8174
+ /**
8175
+ * Painel com cabecalho, recolhimento opcional e rodape. Substitui o `p-panel` do PrimeNG.
8176
+ *
8177
+ * <ui-panel header="Filtros" [toggleable]="true" [(collapsed)]="fechado">conteudo</ui-panel>
8178
+ */
8179
+ class SmzPanelComponent {
8180
+ header = input('', ...(ngDevMode ? [{ debugName: "header" }] : []));
8181
+ toggleable = input(false, { ...(ngDevMode ? { debugName: "toggleable" } : {}), transform: booleanAttribute });
8182
+ collapsed = model(false, ...(ngDevMode ? [{ debugName: "collapsed" }] : []));
8183
+ /** Antes de alternar (cancelavel nao: apenas notifica). */
8184
+ beforeToggle = output();
8185
+ afterToggle = output();
8186
+ templates = contentChildren(SmzTemplateDirective, ...(ngDevMode ? [{ debugName: "templates" }] : []));
8187
+ headerTemplate = computed(() => smzFindTemplate(this.templates(), 'header'), ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
8188
+ iconsTemplate = computed(() => smzFindTemplate(this.templates(), 'icons'), ...(ngDevMode ? [{ debugName: "iconsTemplate" }] : []));
8189
+ footerTemplate = computed(() => smzFindTemplate(this.templates(), 'footer'), ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
8190
+ hasHeader = computed(() => !!this.header() || !!this.headerTemplate() || this.toggleable(), ...(ngDevMode ? [{ debugName: "hasHeader" }] : []));
8191
+ toggle(event) {
8192
+ const next = !this.collapsed();
8193
+ this.beforeToggle.emit({ originalEvent: event, collapsed: next });
8194
+ this.collapsed.set(next);
8195
+ this.afterToggle.emit({ originalEvent: event, collapsed: next });
8196
+ }
8197
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8198
+ 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: `
8199
+ @if (hasHeader()) {
8200
+ <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">
8201
+ <div class="min-w-0 flex-1 font-semibold">
8202
+ @if (headerTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ header() }} }
8203
+ </div>
8204
+ <div class="flex items-center gap-1">
8205
+ @if (iconsTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> }
8206
+ @if (toggleable()) {
8207
+ <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)">
8208
+ <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>
8209
+ </button>
8210
+ }
8211
+ </div>
8212
+ </div>
8213
+ }
8214
+ @if (!collapsed()) {
8215
+ <div class="p-panel-content p-4"><ng-content /></div>
8216
+ @if (footerTemplate(); as tpl) {
8217
+ <div class="p-panel-footer border-t border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8218
+ }
8219
+ }
8220
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8221
+ }
8222
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzPanelComponent, decorators: [{
8223
+ type: Component,
8224
+ args: [{
8225
+ selector: 'ui-panel',
8226
+ changeDetection: ChangeDetectionStrategy.OnPush,
8227
+ imports: [NgTemplateOutlet],
8228
+ 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' },
8229
+ template: `
8230
+ @if (hasHeader()) {
8231
+ <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">
8232
+ <div class="min-w-0 flex-1 font-semibold">
8233
+ @if (headerTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> } @else { {{ header() }} }
8234
+ </div>
8235
+ <div class="flex items-center gap-1">
8236
+ @if (iconsTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" /> }
8237
+ @if (toggleable()) {
8238
+ <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)">
8239
+ <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>
8240
+ </button>
8241
+ }
8242
+ </div>
8243
+ </div>
8244
+ }
8245
+ @if (!collapsed()) {
8246
+ <div class="p-panel-content p-4"><ng-content /></div>
8247
+ @if (footerTemplate(); as tpl) {
8248
+ <div class="p-panel-footer border-t border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8249
+ }
8250
+ }
8251
+ `,
8252
+ }]
8253
+ }], 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 }] }] } });
8254
+
8255
+ /* eslint-disable max-len -- classes Tailwind nos templates */
8256
+ /**
8257
+ * Indicador de carregamento circular. Substitui o `p-progressspinner` do PrimeNG.
8258
+ * O tamanho vem das classes do host (ex.: `class="h-12 w-12"`); a cor, de `text-ui-primary` (herdavel).
8259
+ *
8260
+ * <ui-progress-spinner class="h-12 w-12" strokeWidth="4" />
8261
+ */
8262
+ class SmzProgressSpinnerComponent {
8263
+ strokeWidth = input(4, ...(ngDevMode ? [{ debugName: "strokeWidth" }] : []));
8264
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzProgressSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8265
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzProgressSpinnerComponent, isStandalone: true, selector: "ui-progress-spinner", inputs: { strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar", "aria-busy": "true" }, classAttribute: "inline-block h-10 w-10 text-ui-primary" }, ngImport: i0, template: `
8266
+ <svg viewBox="0 0 50 50" class="h-full w-full animate-spin" fill="none" aria-hidden="true">
8267
+ <circle cx="25" cy="25" r="20" stroke="currentColor" [attr.stroke-width]="strokeWidth()" stroke-linecap="round" stroke-dasharray="90 150" />
8268
+ </svg>
8269
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
8270
+ }
8271
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzProgressSpinnerComponent, decorators: [{
8272
+ type: Component,
8273
+ args: [{
8274
+ selector: 'ui-progress-spinner',
8275
+ changeDetection: ChangeDetectionStrategy.OnPush,
8276
+ host: { class: 'inline-block h-10 w-10 text-ui-primary', role: 'progressbar', 'aria-busy': 'true' },
8277
+ template: `
8278
+ <svg viewBox="0 0 50 50" class="h-full w-full animate-spin" fill="none" aria-hidden="true">
8279
+ <circle cx="25" cy="25" r="20" stroke="currentColor" [attr.stroke-width]="strokeWidth()" stroke-linecap="round" stroke-dasharray="90 150" />
8280
+ </svg>
8281
+ `,
8282
+ }]
8283
+ }], propDecorators: { strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }] } });
8284
+
8285
+ /* eslint-disable max-len -- classes Tailwind nos templates */
8286
+ const BASE = 'relative block [&_label]:pointer-events-none [&_label]:absolute [&_label]:left-3 [&_label]:z-10 [&_label]:text-ui-fg-subtle [&_label]:transition-all [&_label]:duration-ui';
8287
+ const RESTING = '[&_label]:top-1/2 [&_label]:-translate-y-1/2 [&_label]:text-ui-md';
8288
+ const FLOATED = {
8289
+ over: '[&_label]:-top-5 [&_label]:left-0 [&_label]:translate-y-0 [&_label]:text-ui-xs [&_label]:text-ui-fg-muted',
8290
+ on: '[&_label]:top-0 [&_label]:left-2 [&_label]:-translate-y-1/2 [&_label]:bg-ui-surface-1 [&_label]:px-1 [&_label]:text-ui-xs [&_label]:text-ui-fg-muted',
8291
+ in: '[&_label]:top-1.5 [&_label]:translate-y-0 [&_label]:text-ui-xs [&_label]:text-ui-fg-muted',
8292
+ };
8293
+ const IN_PADDING = '[&_input]:pt-4 [&_textarea]:pt-5 [&_[role=combobox]]:pt-4';
8294
+ /**
8295
+ * Rotulo flutuante. Substitui o `p-floatlabel` do PrimeNG.
8296
+ * O `<label>` projetado flutua quando o controle recebe foco ou tem valor
8297
+ * (detectado em `input`/`textarea` e em selects do kit; use `[filled]` para forcar).
8298
+ *
8299
+ * <ui-float-label variant="on"><input smzInputText id="n" /><label for="n">Nome</label></ui-float-label>
8300
+ */
8301
+ class SmzFloatLabelComponent {
8302
+ variant = input('over', ...(ngDevMode ? [{ debugName: "variant" }] : []));
8303
+ /** Forca o estado "preenchido" quando a deteccao automatica nao se aplica. */
8304
+ filled = input(null, ...(ngDevMode ? [{ debugName: "filled" }] : []));
8305
+ focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : []));
8306
+ detected = signal(false, ...(ngDevMode ? [{ debugName: "detected" }] : []));
8307
+ host = inject(ElementRef);
8308
+ floated = computed(() => this.focused() || (this.filled() ?? this.detected()), ...(ngDevMode ? [{ debugName: "floated" }] : []));
8309
+ classes = computed(() => {
8310
+ const variant = this.variant();
8311
+ return [BASE, this.floated() ? FLOATED[variant] : RESTING, variant === 'in' ? IN_PADDING : ''].join(' ');
8312
+ }, ...(ngDevMode ? [{ debugName: "classes" }] : []));
8313
+ constructor() {
8314
+ afterEveryRender(() => this.check());
8315
+ }
8316
+ check() {
8317
+ {
8318
+ const root = this.host.nativeElement;
8319
+ const field = root.querySelector('input:not([type=checkbox]):not([type=radio]), textarea');
8320
+ const combo = root.querySelector('[role=combobox]');
8321
+ let filled = false;
8322
+ if (field && field.value !== '')
8323
+ filled = true;
8324
+ else if (combo && !field)
8325
+ filled = !combo.querySelector('.text-ui-fg-subtle') && (combo.textContent ?? '').trim() !== '';
8326
+ if (filled !== this.detected())
8327
+ this.detected.set(filled);
8328
+ }
8329
+ }
8330
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzFloatLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8331
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzFloatLabelComponent, isStandalone: true, selector: "ui-float-label", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, filled: { classPropertyName: "filled", publicName: "filled", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focusin": "focused.set(true)", "focusout": "focused.set(false); check()", "input": "check()", "change": "check()" }, properties: { "class": "classes()" } }, ngImport: i0, template: '<ng-content />', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
8332
+ }
8333
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzFloatLabelComponent, decorators: [{
8334
+ type: Component,
8335
+ args: [{
8336
+ selector: 'ui-float-label',
8337
+ changeDetection: ChangeDetectionStrategy.OnPush,
8338
+ host: {
8339
+ '[class]': 'classes()',
8340
+ '(focusin)': 'focused.set(true)',
8341
+ '(focusout)': 'focused.set(false); check()',
8342
+ '(input)': 'check()',
8343
+ '(change)': 'check()',
8344
+ },
8345
+ template: '<ng-content />',
8346
+ }]
8347
+ }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], filled: [{ type: i0.Input, args: [{ isSignal: true, alias: "filled", required: false }] }] } });
8348
+
8349
+ /* eslint-disable max-len -- classes Tailwind nos templates */
8350
+ /** Painel de um `ui-splitter`. O conteudo e projetado dentro da area do painel. */
8351
+ class SmzSplitterPanelComponent {
8352
+ content = viewChild.required(TemplateRef);
8353
+ /** Tamanho inicial em % (sobrescreve `panelSizes` do splitter). */
8354
+ size = input(null, ...(ngDevMode ? [{ debugName: "size" }] : []));
8355
+ minSize = input(null, ...(ngDevMode ? [{ debugName: "minSize" }] : []));
8356
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzSplitterPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8357
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.1", type: SmzSplitterPanelComponent, isStandalone: true, selector: "ui-splitter-panel", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, minSize: { classPropertyName: "minSize", publicName: "minSize", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "content", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], ngImport: i0, template: '<ng-template><ng-content /></ng-template>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
8358
+ }
8359
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzSplitterPanelComponent, decorators: [{
8360
+ type: Component,
8361
+ args: [{
8362
+ selector: 'ui-splitter-panel',
8363
+ changeDetection: ChangeDetectionStrategy.OnPush,
8364
+ template: '<ng-template><ng-content /></ng-template>',
8365
+ }]
8366
+ }], propDecorators: { content: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], minSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSize", required: false }] }] } });
8367
+ /**
8368
+ * Divisor redimensionavel. Substitui o `p-splitter` / `p-splitterPanel` do PrimeNG.
8369
+ *
8370
+ * <ui-splitter layout="horizontal" [panelSizes]="[30, 70]" [minSizes]="[10, 20]">
8371
+ * <ui-splitter-panel>A</ui-splitter-panel><ui-splitter-panel>B</ui-splitter-panel>
8372
+ * </ui-splitter>
8373
+ */
8374
+ class SmzSplitterComponent {
8375
+ layout = input('horizontal', ...(ngDevMode ? [{ debugName: "layout" }] : []));
8376
+ panelSizes = input(null, ...(ngDevMode ? [{ debugName: "panelSizes" }] : []));
8377
+ minSizes = input(null, ...(ngDevMode ? [{ debugName: "minSizes" }] : []));
8378
+ resizeEnd = output();
8379
+ panels = contentChildren(SmzSplitterPanelComponent, ...(ngDevMode ? [{ debugName: "panels" }] : []));
8380
+ root = viewChild.required('root');
8381
+ overrides = signal(null, ...(ngDevMode ? [{ debugName: "overrides" }] : []));
8382
+ sizes = computed(() => {
8383
+ const override = this.overrides();
8384
+ if (override && override.length === this.panels().length)
8385
+ return override;
8386
+ const panels = this.panels();
8387
+ const base = this.panelSizes() ?? [];
8388
+ const explicit = panels.map((panel, i) => panel.size() ?? base[i] ?? null);
8389
+ const known = explicit.reduce((sum, size) => sum + (size ?? 0), 0);
8390
+ const free = explicit.filter((size) => size === null).length;
8391
+ const share = free > 0 ? Math.max(0, 100 - known) / free : 0;
8392
+ return explicit.map((size) => size ?? share);
8393
+ }, ...(ngDevMode ? [{ debugName: "sizes" }] : []));
8394
+ min(index) {
8395
+ return this.panels()[index]?.minSize() ?? this.minSizes()?.[index] ?? 0;
8396
+ }
8397
+ startDrag(event, index) {
8398
+ event.preventDefault();
8399
+ const rect = this.root().nativeElement.getBoundingClientRect();
8400
+ const total = this.layout() === 'horizontal' ? rect.width : rect.height;
8401
+ const start = this.layout() === 'horizontal' ? event.clientX : event.clientY;
8402
+ const initial = [...this.sizes()];
8403
+ const move = (e) => {
8404
+ const delta = (((this.layout() === 'horizontal' ? e.clientX : e.clientY) - start) / total) * 100;
8405
+ this.resize(initial, index, delta);
8406
+ };
8407
+ const up = () => {
8408
+ document.removeEventListener('pointermove', move);
8409
+ document.removeEventListener('pointerup', up);
8410
+ this.resizeEnd.emit({ sizes: this.sizes() });
8411
+ };
8412
+ document.addEventListener('pointermove', move);
8413
+ document.addEventListener('pointerup', up);
8414
+ }
8415
+ onKey(event, index) {
8416
+ const keys = this.layout() === 'horizontal' ? { dec: 'ArrowLeft', inc: 'ArrowRight' } : { dec: 'ArrowUp', inc: 'ArrowDown' };
8417
+ if (event.key !== keys.dec && event.key !== keys.inc)
8418
+ return;
8419
+ event.preventDefault();
8420
+ this.resize([...this.sizes()], index, event.key === keys.inc ? 2 : -2);
8421
+ this.resizeEnd.emit({ sizes: this.sizes() });
8422
+ }
8423
+ resize(initial, index, delta) {
8424
+ const pair = initial[index] + initial[index + 1];
8425
+ const next = Math.min(Math.max(initial[index] + delta, this.min(index)), pair - this.min(index + 1));
8426
+ const sizes = [...initial];
8427
+ sizes[index] = next;
8428
+ sizes[index + 1] = pair - next;
8429
+ this.overrides.set(sizes);
8430
+ }
8431
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzSplitterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8432
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzSplitterComponent, isStandalone: true, selector: "ui-splitter", inputs: { layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, panelSizes: { classPropertyName: "panelSizes", publicName: "panelSizes", isSignal: true, isRequired: false, transformFunction: null }, minSizes: { classPropertyName: "minSizes", publicName: "minSizes", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { resizeEnd: "resizeEnd" }, host: { classAttribute: "block h-full w-full overflow-hidden rounded-control border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg" }, queries: [{ propertyName: "panels", predicate: SmzSplitterPanelComponent, isSignal: true }], viewQueries: [{ propertyName: "root", first: true, predicate: ["root"], descendants: true, isSignal: true }], ngImport: i0, template: `
8433
+ <div #root class="flex h-full w-full" [class.flex-col]="layout() === 'vertical'">
8434
+ @for (panel of panels(); track $index; let i = $index) {
8435
+ <div class="min-h-0 min-w-0 overflow-auto" [style.flex]="'0 0 ' + sizes()[i] + '%'" [style.width]="layout() === 'horizontal' ? sizes()[i] + '%' : null" [style.height]="layout() === 'vertical' ? sizes()[i] + '%' : null">
8436
+ <ng-container [ngTemplateOutlet]="panel.content()" />
8437
+ </div>
8438
+ @if (i < panels().length - 1) {
8439
+ <div
8440
+ role="separator"
8441
+ tabindex="0"
8442
+ class="shrink-0 bg-ui-line transition-colors duration-ui hover:bg-ui-primary focus-visible:bg-ui-primary focus-visible:outline-none"
8443
+ [class]="layout() === 'horizontal' ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'"
8444
+ [attr.aria-orientation]="layout() === 'horizontal' ? 'vertical' : 'horizontal'"
8445
+ (pointerdown)="startDrag($event, i)"
8446
+ (keydown)="onKey($event, i)"
8447
+ ></div>
8448
+ }
8449
+ }
8450
+ </div>
8451
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8452
+ }
8453
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzSplitterComponent, decorators: [{
8454
+ type: Component,
8455
+ args: [{
8456
+ selector: 'ui-splitter',
8457
+ changeDetection: ChangeDetectionStrategy.OnPush,
8458
+ imports: [NgTemplateOutlet],
8459
+ host: { class: 'block h-full w-full overflow-hidden rounded-control border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg' },
8460
+ template: `
8461
+ <div #root class="flex h-full w-full" [class.flex-col]="layout() === 'vertical'">
8462
+ @for (panel of panels(); track $index; let i = $index) {
8463
+ <div class="min-h-0 min-w-0 overflow-auto" [style.flex]="'0 0 ' + sizes()[i] + '%'" [style.width]="layout() === 'horizontal' ? sizes()[i] + '%' : null" [style.height]="layout() === 'vertical' ? sizes()[i] + '%' : null">
8464
+ <ng-container [ngTemplateOutlet]="panel.content()" />
8465
+ </div>
8466
+ @if (i < panels().length - 1) {
8467
+ <div
8468
+ role="separator"
8469
+ tabindex="0"
8470
+ class="shrink-0 bg-ui-line transition-colors duration-ui hover:bg-ui-primary focus-visible:bg-ui-primary focus-visible:outline-none"
8471
+ [class]="layout() === 'horizontal' ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize'"
8472
+ [attr.aria-orientation]="layout() === 'horizontal' ? 'vertical' : 'horizontal'"
8473
+ (pointerdown)="startDrag($event, i)"
8474
+ (keydown)="onKey($event, i)"
8475
+ ></div>
8476
+ }
8477
+ }
8478
+ </div>
8479
+ `,
8480
+ }]
8481
+ }], propDecorators: { layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], panelSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelSizes", required: false }] }], minSizes: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSizes", required: false }] }], resizeEnd: [{ type: i0.Output, args: ["resizeEnd"] }], panels: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzSplitterPanelComponent), { isSignal: true }] }], root: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }] } });
8482
+
8483
+ /* eslint-disable max-len -- classes Tailwind nos templates */
8484
+ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument, @typescript-eslint/explicit-module-boundary-types */
8485
+ const ROW_BASE = 'border-b border-ui-line transition-colors duration-ui';
8486
+ /**
8487
+ * Tabela em arvore. Substitui o `p-treeTable` do PrimeNG.
8488
+ * Os templates `header`, `body`, `caption`, `footer`, `emptymessage` e `summary` usam `smzTemplate`;
8489
+ * o `body` recebe `let-rowNode let-rowData="rowData" let-columns="columns"`.
8490
+ *
8491
+ * <ui-tree-table [value]="nodes" [columns]="cols" selectionMode="checkbox" [(selection)]="sel">
8492
+ * <ng-template smzTemplate="header" let-columns><tr><th *ngFor="let c of columns">{{ c.header }}</th></tr></ng-template>
8493
+ * <ng-template smzTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
8494
+ * <tr [smzTtRow]="rowNode"><td><ui-tree-table-toggler [rowNode]="rowNode" />{{ rowData.name }}</td></tr>
8495
+ * </ng-template>
8496
+ * </ui-tree-table>
8497
+ */
8498
+ class SmzTreeTableComponent {
8499
+ value = input([], ...(ngDevMode ? [{ debugName: "value" }] : []));
8500
+ columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : []));
8501
+ selectionMode = input(null, ...(ngDevMode ? [{ debugName: "selectionMode" }] : []));
8502
+ selection = model(null, ...(ngDevMode ? [{ debugName: "selection" }] : []));
8503
+ propagateSelectionUp = input(true, { ...(ngDevMode ? { debugName: "propagateSelectionUp" } : {}), transform: booleanAttribute });
8504
+ propagateSelectionDown = input(true, { ...(ngDevMode ? { debugName: "propagateSelectionDown" } : {}), transform: booleanAttribute });
8505
+ loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : {}), transform: booleanAttribute });
8506
+ scrollable = input(false, { ...(ngDevMode ? { debugName: "scrollable" } : {}), transform: booleanAttribute });
8507
+ scrollHeight = input(null, ...(ngDevMode ? [{ debugName: "scrollHeight" }] : []));
8508
+ emptyMessage = input('', ...(ngDevMode ? [{ debugName: "emptyMessage" }] : []));
8509
+ tableStyleClass = input('', ...(ngDevMode ? [{ debugName: "tableStyleClass" }] : []));
8510
+ paginator = input(false, { ...(ngDevMode ? { debugName: "paginator" } : {}), transform: booleanAttribute });
8511
+ rows = model(10, ...(ngDevMode ? [{ debugName: "rows" }] : []));
8512
+ first = model(0, ...(ngDevMode ? [{ debugName: "first" }] : []));
8513
+ rowsPerPageOptions = input(null, ...(ngDevMode ? [{ debugName: "rowsPerPageOptions" }] : []));
8514
+ sortField = model(null, ...(ngDevMode ? [{ debugName: "sortField" }] : []));
8515
+ sortOrder = model(1, ...(ngDevMode ? [{ debugName: "sortOrder" }] : []));
8516
+ /** Destaca a linha sob o cursor (padrao: ligado). */
8517
+ rowHover = input(true, { ...(ngDevMode ? { debugName: "rowHover" } : {}), transform: booleanAttribute });
8518
+ showCurrentPageReport = input(false, { ...(ngDevMode ? { debugName: "showCurrentPageReport" } : {}), transform: booleanAttribute });
8519
+ currentPageReportTemplate = input('Mostrando {first} a {last} de {totalRecords}', ...(ngDevMode ? [{ debugName: "currentPageReportTemplate" }] : []));
8520
+ /** Campos (de `node.data`) consultados pelo filtro global. */
8521
+ globalFilterFields = input(null, ...(ngDevMode ? [{ debugName: "globalFilterFields" }] : []));
8522
+ /** `lenient`: um no que casa mantem toda a sua subarvore; `strict`: so os nos que casam (e seus ancestrais). */
8523
+ filterMode = input('lenient', ...(ngDevMode ? [{ debugName: "filterMode" }] : []));
8524
+ nodeSelect = output();
8525
+ nodeUnselect = output();
8526
+ nodeExpand = output();
8527
+ nodeCollapse = output();
8528
+ sorted = output();
8529
+ page = output();
8530
+ templates = contentChildren(SmzTemplateDirective, ...(ngDevMode ? [{ debugName: "templates" }] : []));
8531
+ headerTemplate = computed(() => smzFindTemplate(this.templates(), 'header'), ...(ngDevMode ? [{ debugName: "headerTemplate" }] : []));
8532
+ bodyTemplate = computed(() => smzFindTemplate(this.templates(), 'body'), ...(ngDevMode ? [{ debugName: "bodyTemplate" }] : []));
8533
+ captionTemplate = computed(() => smzFindTemplate(this.templates(), 'caption'), ...(ngDevMode ? [{ debugName: "captionTemplate" }] : []));
8534
+ footerTemplate = computed(() => smzFindTemplate(this.templates(), 'footer'), ...(ngDevMode ? [{ debugName: "footerTemplate" }] : []));
8535
+ emptyTemplate = computed(() => smzFindTemplate(this.templates(), 'emptymessage'), ...(ngDevMode ? [{ debugName: "emptyTemplate" }] : []));
8536
+ summaryTemplate = computed(() => smzFindTemplate(this.templates(), 'summary'), ...(ngDevMode ? [{ debugName: "summaryTemplate" }] : []));
8537
+ /** Os nos sao mutaveis (`expanded`, `partialSelected`); este contador forca o recalculo das linhas. */
8538
+ version = signal(0, ...(ngDevMode ? [{ debugName: "version" }] : []));
8539
+ filterService = inject(SmzFilterService);
8540
+ globalFilter = signal(null, ...(ngDevMode ? [{ debugName: "globalFilter" }] : []));
8541
+ columnFilters = signal({}, ...(ngDevMode ? [{ debugName: "columnFilters" }] : []));
8542
+ /** Nos raiz que passam nos filtros (global e por coluna), ou `null` quando nao ha filtro ativo. */
8543
+ get filteredNodes() {
8544
+ return this.visibility()?.roots ?? null;
8545
+ }
8546
+ /** Visibilidade calculada dos filtros: quais nos aparecem e quais ancestrais expandir. */
8547
+ visibility = computed(() => {
8548
+ this.version();
8549
+ const global = this.globalFilter();
8550
+ const columns = this.columnFilters();
8551
+ const active = Object.entries(columns).filter(([, filter]) => filter.value !== null && filter.value !== undefined && filter.value !== '');
8552
+ if (!global?.value && active.length === 0)
8553
+ return null;
8554
+ const matches = (node) => {
8555
+ for (const [field, filter] of active) {
8556
+ const test = this.filterService.filters[filter.matchMode] ?? this.filterService.filters['contains'];
8557
+ if (!test(SmzObjectUtils.resolveFieldData(node.data, field), filter.value))
8558
+ return false;
8559
+ }
8560
+ if (global?.value) {
8561
+ const test = this.filterService.filters[global.matchMode] ?? this.filterService.filters['contains'];
8562
+ const fields = this.globalFilterFields() ?? Object.keys(node.data ?? {});
8563
+ if (!fields.some((field) => test(SmzObjectUtils.resolveFieldData(node.data, field), global.value)))
8564
+ return false;
8565
+ }
8566
+ return true;
8567
+ };
8568
+ const visible = new Set();
8569
+ const expand = new Set();
8570
+ const lenient = this.filterMode() === 'lenient';
8571
+ const mark = (node, forced) => {
8572
+ const self = matches(node);
8573
+ let anyChild = false;
8574
+ for (const child of node.children ?? []) {
8575
+ if (mark(child, forced || (lenient && self)))
8576
+ anyChild = true;
8577
+ }
8578
+ const show = self || anyChild || forced;
8579
+ if (show)
8580
+ visible.add(node);
8581
+ if (anyChild && !self)
8582
+ expand.add(node);
8583
+ return self || anyChild;
8584
+ };
8585
+ const roots = (this.value() ?? []).filter((node) => mark(node, false));
8586
+ return { roots, visible, expand };
8587
+ }, ...(ngDevMode ? [{ debugName: "visibility" }] : []));
8588
+ rootCount = computed(() => this.visibility()?.roots.length ?? (this.value() ?? []).length, ...(ngDevMode ? [{ debugName: "rootCount" }] : []));
8589
+ flatRows = computed(() => {
8590
+ this.version();
8591
+ const field = this.sortField();
8592
+ const order = this.sortOrder();
8593
+ const filter = this.visibility();
8594
+ const out = [];
8595
+ const sort = (nodes) => field ? [...nodes].sort((a, b) => order * compareValues(SmzObjectUtils.resolveFieldData(a.data, field), SmzObjectUtils.resolveFieldData(b.data, field))) : nodes;
8596
+ const walk = (nodes, parent, level) => {
8597
+ for (const node of sort(nodes)) {
8598
+ if (filter && !filter.visible.has(node))
8599
+ continue;
8600
+ out.push({ node, parent, level });
8601
+ if ((node.expanded || filter?.expand.has(node)) && node.children?.length)
8602
+ walk(node.children, node, level + 1);
8603
+ }
8604
+ };
8605
+ walk(this.value() ?? [], null, 0);
8606
+ return out;
8607
+ }, ...(ngDevMode ? [{ debugName: "flatRows" }] : []));
8608
+ /** Linhas visiveis; com paginador, a pagina atual e calculada sobre os nos raiz. */
8609
+ pageRows = computed(() => {
8610
+ const all = this.flatRows();
8611
+ if (!this.paginator())
8612
+ return all;
8613
+ const roots = all.filter((row) => row.level === 0);
8614
+ const pageRoots = new Set(roots.slice(this.first(), this.first() + this.rows()).map((row) => row.node));
8615
+ let include = false;
8616
+ return all.filter((row) => {
8617
+ if (row.level === 0)
8618
+ include = pageRoots.has(row.node);
8619
+ return include;
8620
+ });
8621
+ }, ...(ngDevMode ? [{ debugName: "pageRows" }] : []));
8622
+ /** Filtro global (equivale a `filterGlobal` do `p-treeTable`). */
8623
+ filterGlobal(value, matchMode = 'contains') {
8624
+ this.globalFilter.set(value ? { value, matchMode } : null);
8625
+ this.first.set(0);
8626
+ }
8627
+ /** Filtro de uma coluna (campo de `node.data`). Valor vazio remove o filtro. */
8628
+ filter(value, field, matchMode = 'contains') {
8629
+ this.columnFilters.update((current) => ({ ...current, [field]: { value, matchMode } }));
8630
+ this.first.set(0);
8631
+ }
8632
+ /** Limpa filtros, ordenacao e volta para a primeira pagina (equivale a `clear()` do `p-treeTable`). */
8633
+ clear() {
8634
+ this.globalFilter.set(null);
8635
+ this.columnFilters.set({});
8636
+ this.sortField.set(null);
8637
+ this.sortOrder.set(1);
8638
+ this.first.set(0);
8639
+ }
8640
+ refresh() {
8641
+ this.version.update((v) => v + 1);
8642
+ }
8643
+ toggleNode(rowNode, event) {
8644
+ const node = rowNode.node;
8645
+ node.expanded = !node.expanded;
8646
+ (node.expanded ? this.nodeExpand : this.nodeCollapse).emit({ node, originalEvent: event });
8647
+ this.refresh();
8648
+ }
8649
+ sortBy(field) {
8650
+ const order = this.sortField() === field && this.sortOrder() === 1 ? -1 : 1;
8651
+ this.sortField.set(field);
8652
+ this.sortOrder.set(order);
8653
+ this.sorted.emit({ field, order });
8654
+ }
8655
+ isSelected(node) {
8656
+ const selection = this.selection();
8657
+ return Array.isArray(selection) ? selection.includes(node) : selection === node;
8658
+ }
8659
+ selectionState(node) {
8660
+ if (this.isSelected(node))
8661
+ return 'checked';
8662
+ return node.partialSelected ? 'partial' : 'unchecked';
8663
+ }
8664
+ onRowClick(rowNode, event) {
8665
+ const mode = this.selectionMode();
8666
+ const node = rowNode.node;
8667
+ if (!mode || node.selectable === false)
8668
+ return;
8669
+ if (mode === 'checkbox')
8670
+ return; // selecao so pelo checkbox
8671
+ const selected = this.isSelected(node);
8672
+ if (mode === 'single') {
8673
+ this.selection.set(selected ? null : node);
8674
+ }
8675
+ else {
8676
+ const current = Array.isArray(this.selection()) ? this.selection() : [];
8677
+ this.selection.set(selected ? current.filter((entry) => entry !== node) : [...current, node]);
8678
+ }
8679
+ (selected ? this.nodeUnselect : this.nodeSelect).emit({ node, originalEvent: event });
8680
+ }
8681
+ toggleCheckbox(rowNode, event) {
8682
+ const node = rowNode.node;
8683
+ const selected = this.isSelected(node);
8684
+ const set = new Set(Array.isArray(this.selection()) ? this.selection() : []);
8685
+ const apply = (target, value) => {
8686
+ if (value)
8687
+ set.add(target);
8688
+ else
8689
+ set.delete(target);
8690
+ target.partialSelected = false;
8691
+ if (this.propagateSelectionDown())
8692
+ target.children?.forEach((child) => apply(child, value));
8693
+ };
8694
+ apply(node, !selected);
8695
+ if (this.propagateSelectionUp()) {
8696
+ for (let parent = rowNode.parent; parent; parent = this.findParent(parent)) {
8697
+ const children = parent.children ?? [];
8698
+ const all = children.every((child) => set.has(child));
8699
+ const some = children.some((child) => set.has(child) || child.partialSelected);
8700
+ if (all)
8701
+ set.add(parent);
8702
+ else
8703
+ set.delete(parent);
8704
+ parent.partialSelected = !all && some;
8705
+ }
8706
+ }
8707
+ this.selection.set([...set]);
8708
+ (selected ? this.nodeUnselect : this.nodeSelect).emit({ node, originalEvent: event });
8709
+ this.refresh();
8710
+ }
8711
+ /** Marca/desmarca todos os nos (checkbox do cabecalho). */
8712
+ toggleAll(checked) {
8713
+ const set = new Set();
8714
+ const walk = (nodes) => {
8715
+ for (const node of nodes) {
8716
+ node.partialSelected = false;
8717
+ if (checked && node.selectable !== false)
8718
+ set.add(node);
8719
+ walk(node.children ?? []);
8720
+ }
8721
+ };
8722
+ walk(this.value() ?? []);
8723
+ this.selection.set([...set]);
8724
+ this.refresh();
8725
+ }
8726
+ allSelected() {
8727
+ const total = this.countNodes(this.value() ?? []);
8728
+ const selection = this.selection();
8729
+ return total > 0 && Array.isArray(selection) && selection.length >= total;
8730
+ }
8731
+ countNodes(nodes) {
8732
+ return nodes.reduce((sum, node) => sum + 1 + this.countNodes(node.children ?? []), 0);
8733
+ }
8734
+ findParent(node) {
8735
+ const search = (nodes, parent) => {
8736
+ for (const candidate of nodes) {
8737
+ if (candidate === node)
8738
+ return parent;
8739
+ const found = search(candidate.children ?? [], candidate);
8740
+ if (found !== undefined)
8741
+ return found;
8742
+ }
8743
+ return undefined;
8744
+ };
8745
+ return search(this.value() ?? [], null) ?? null;
8746
+ }
8747
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8748
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzTreeTableComponent, isStandalone: true, selector: "ui-tree-table", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, selection: { classPropertyName: "selection", publicName: "selection", isSignal: true, isRequired: false, transformFunction: null }, propagateSelectionUp: { classPropertyName: "propagateSelectionUp", publicName: "propagateSelectionUp", isSignal: true, isRequired: false, transformFunction: null }, propagateSelectionDown: { classPropertyName: "propagateSelectionDown", publicName: "propagateSelectionDown", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, scrollable: { classPropertyName: "scrollable", publicName: "scrollable", isSignal: true, isRequired: false, transformFunction: null }, scrollHeight: { classPropertyName: "scrollHeight", publicName: "scrollHeight", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, tableStyleClass: { classPropertyName: "tableStyleClass", publicName: "tableStyleClass", isSignal: true, isRequired: false, transformFunction: null }, paginator: { classPropertyName: "paginator", publicName: "paginator", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, first: { classPropertyName: "first", publicName: "first", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, sortField: { classPropertyName: "sortField", publicName: "sortField", isSignal: true, isRequired: false, transformFunction: null }, sortOrder: { classPropertyName: "sortOrder", publicName: "sortOrder", isSignal: true, isRequired: false, transformFunction: null }, rowHover: { classPropertyName: "rowHover", publicName: "rowHover", isSignal: true, isRequired: false, transformFunction: null }, showCurrentPageReport: { classPropertyName: "showCurrentPageReport", publicName: "showCurrentPageReport", isSignal: true, isRequired: false, transformFunction: null }, currentPageReportTemplate: { classPropertyName: "currentPageReportTemplate", publicName: "currentPageReportTemplate", isSignal: true, isRequired: false, transformFunction: null }, globalFilterFields: { classPropertyName: "globalFilterFields", publicName: "globalFilterFields", isSignal: true, isRequired: false, transformFunction: null }, filterMode: { classPropertyName: "filterMode", publicName: "filterMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selection: "selectionChange", rows: "rowsChange", first: "firstChange", sortField: "sortFieldChange", sortOrder: "sortOrderChange", nodeSelect: "nodeSelect", nodeUnselect: "nodeUnselect", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse", sorted: "sorted", page: "page" }, host: { classAttribute: "block overflow-hidden rounded-control 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: `
8749
+ @if (captionTemplate(); as tpl) {
8750
+ <div class="border-b border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8751
+ }
8752
+ <div class="relative overflow-auto" [style.max-height]="scrollable() ? scrollHeight() : null">
8753
+ <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() ?? ''">
8754
+ <thead>
8755
+ @if (headerTemplate(); as tpl) {
8756
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" />
8757
+ }
8758
+ </thead>
8759
+ <tbody>
8760
+ @for (row of pageRows(); track row.node.key ?? row.node) {
8761
+ <ng-container [ngTemplateOutlet]="bodyTemplate() ?? null" [ngTemplateOutletContext]="{ $implicit: row, rowNode: row, node: row.node, rowData: row.node.data, columns: columns() }" />
8762
+ } @empty {
8763
+ @if (!loading()) {
8764
+ <tr>
8765
+ <td [attr.colspan]="columns().length || 1" class="px-4 py-6 text-center text-ui-fg-muted">
8766
+ @if (emptyTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" /> } @else { {{ emptyMessage() }} }
8767
+ </td>
8768
+ </tr>
8769
+ }
8770
+ }
8771
+ </tbody>
8772
+ @if (footerTemplate(); as tpl) {
8773
+ <tfoot><ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" /></tfoot>
8774
+ }
8775
+ </table>
8776
+ @if (loading()) {
8777
+ <div class="absolute inset-0 flex items-center justify-center bg-ui-surface-1/60 text-ui-primary" role="status">
8778
+ <svg viewBox="0 0 50 50" class="h-8 w-8 animate-spin" fill="none" aria-hidden="true"><circle cx="25" cy="25" r="20" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-dasharray="90 150" /></svg>
8779
+ </div>
8780
+ }
8781
+ </div>
8782
+ @if (paginator()) {
8783
+ <ui-paginator class="border-t border-ui-line" [first]="first()" [rows]="rows()" [totalRecords]="rootCount()" [rowsPerPageOptions]="rowsPerPageOptions()" [showCurrentPageReport]="showCurrentPageReport()" [currentPageReportTemplate]="currentPageReportTemplate()" (firstChange)="first.set($event)" (rowsChange)="rows.set($event)" (pageChanged)="page.emit($event)" />
8784
+ }
8785
+ @if (summaryTemplate(); as tpl) {
8786
+ <div class="border-t border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8787
+ }
8788
+ `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SmzPaginatorComponent, selector: "ui-paginator", inputs: ["first", "rows", "totalRecords", "pageLinkSize", "rowsPerPageOptions", "showCurrentPageReport", "currentPageReportTemplate", "alwaysShow", "showPageLinks", "styleClass", "dropdownAppendTo", "showFirstLastIcon"], outputs: ["firstChange", "rowsChange", "pageChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
8789
+ }
8790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableComponent, decorators: [{
8791
+ type: Component,
8792
+ args: [{
8793
+ selector: 'ui-tree-table',
8794
+ changeDetection: ChangeDetectionStrategy.OnPush,
8795
+ imports: [NgTemplateOutlet, SmzPaginatorComponent],
8796
+ host: { class: 'block overflow-hidden rounded-control border border-ui-line bg-ui-surface-1 font-ui text-ui-md text-ui-fg' },
8797
+ template: `
8798
+ @if (captionTemplate(); as tpl) {
8799
+ <div class="border-b border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8800
+ }
8801
+ <div class="relative overflow-auto" [style.max-height]="scrollable() ? scrollHeight() : null">
8802
+ <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() ?? ''">
8803
+ <thead>
8804
+ @if (headerTemplate(); as tpl) {
8805
+ <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" />
8806
+ }
8807
+ </thead>
8808
+ <tbody>
8809
+ @for (row of pageRows(); track row.node.key ?? row.node) {
8810
+ <ng-container [ngTemplateOutlet]="bodyTemplate() ?? null" [ngTemplateOutletContext]="{ $implicit: row, rowNode: row, node: row.node, rowData: row.node.data, columns: columns() }" />
8811
+ } @empty {
8812
+ @if (!loading()) {
8813
+ <tr>
8814
+ <td [attr.colspan]="columns().length || 1" class="px-4 py-6 text-center text-ui-fg-muted">
8815
+ @if (emptyTemplate(); as tpl) { <ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" /> } @else { {{ emptyMessage() }} }
8816
+ </td>
8817
+ </tr>
8818
+ }
8819
+ }
8820
+ </tbody>
8821
+ @if (footerTemplate(); as tpl) {
8822
+ <tfoot><ng-container [ngTemplateOutlet]="tpl" [ngTemplateOutletContext]="{ $implicit: columns() }" /></tfoot>
8823
+ }
8824
+ </table>
8825
+ @if (loading()) {
8826
+ <div class="absolute inset-0 flex items-center justify-center bg-ui-surface-1/60 text-ui-primary" role="status">
8827
+ <svg viewBox="0 0 50 50" class="h-8 w-8 animate-spin" fill="none" aria-hidden="true"><circle cx="25" cy="25" r="20" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-dasharray="90 150" /></svg>
8828
+ </div>
8829
+ }
8830
+ </div>
8831
+ @if (paginator()) {
8832
+ <ui-paginator class="border-t border-ui-line" [first]="first()" [rows]="rows()" [totalRecords]="rootCount()" [rowsPerPageOptions]="rowsPerPageOptions()" [showCurrentPageReport]="showCurrentPageReport()" [currentPageReportTemplate]="currentPageReportTemplate()" (firstChange)="first.set($event)" (rowsChange)="rows.set($event)" (pageChanged)="page.emit($event)" />
8833
+ }
8834
+ @if (summaryTemplate(); as tpl) {
8835
+ <div class="border-t border-ui-line px-4 py-3"><ng-container [ngTemplateOutlet]="tpl" /></div>
8836
+ }
8837
+ `,
8838
+ }]
8839
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], selection: [{ type: i0.Input, args: [{ isSignal: true, alias: "selection", required: false }] }, { type: i0.Output, args: ["selectionChange"] }], propagateSelectionUp: [{ type: i0.Input, args: [{ isSignal: true, alias: "propagateSelectionUp", required: false }] }], propagateSelectionDown: [{ type: i0.Input, args: [{ isSignal: true, alias: "propagateSelectionDown", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], scrollable: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollable", required: false }] }], scrollHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollHeight", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], tableStyleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableStyleClass", required: false }] }], paginator: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginator", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }, { type: i0.Output, args: ["rowsChange"] }], first: [{ type: i0.Input, args: [{ isSignal: true, alias: "first", required: false }] }, { type: i0.Output, args: ["firstChange"] }], rowsPerPageOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPageOptions", required: false }] }], sortField: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortField", required: false }] }, { type: i0.Output, args: ["sortFieldChange"] }], sortOrder: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortOrder", required: false }] }, { type: i0.Output, args: ["sortOrderChange"] }], rowHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHover", required: false }] }], showCurrentPageReport: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCurrentPageReport", required: false }] }], currentPageReportTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPageReportTemplate", required: false }] }], globalFilterFields: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalFilterFields", required: false }] }], filterMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterMode", required: false }] }], nodeSelect: [{ type: i0.Output, args: ["nodeSelect"] }], nodeUnselect: [{ type: i0.Output, args: ["nodeUnselect"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCollapse: [{ type: i0.Output, args: ["nodeCollapse"] }], sorted: [{ type: i0.Output, args: ["sorted"] }], page: [{ type: i0.Output, args: ["page"] }], templates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SmzTemplateDirective), { isSignal: true }] }] } });
8840
+ function compareValues(a, b) {
8841
+ if (a == null && b == null)
8842
+ return 0;
8843
+ if (a == null)
8844
+ return -1;
8845
+ if (b == null)
8846
+ return 1;
8847
+ if (typeof a === 'string' && typeof b === 'string')
8848
+ return a.localeCompare(b);
8849
+ return a < b ? -1 : a > b ? 1 : 0;
8850
+ }
8851
+ /** Linha do corpo: `<tr [smzTtRow]="rowNode">`. Cuida de estilo, aria e selecao por clique. */
8852
+ class SmzTreeTableRowDirective {
8853
+ table = inject(SmzTreeTableComponent);
8854
+ rowNode = input.required({ ...(ngDevMode ? { debugName: "rowNode" } : {}), alias: 'smzTtRow' });
8855
+ classes = computed(() => {
8856
+ const mode = this.table.selectionMode();
8857
+ const selected = this.table.isSelected(this.rowNode().node);
8858
+ const hover = this.table.rowHover() ? 'hover:bg-ui-surface-3' : '';
8859
+ const interactive = mode && mode !== 'checkbox' ? `cursor-pointer ${hover}` : hover;
8860
+ return `${ROW_BASE} ${interactive} ${selected && mode !== 'checkbox' ? 'bg-ui-primary/10' : ''}`;
8861
+ }, ...(ngDevMode ? [{ debugName: "classes" }] : []));
8862
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableRowDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
8863
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: SmzTreeTableRowDirective, isStandalone: true, selector: "tr[smzTtRow]", inputs: { rowNode: { classPropertyName: "rowNode", publicName: "smzTtRow", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "table.onRowClick(rowNode(), $event)" }, properties: { "class": "classes()", "attr.aria-level": "rowNode().level + 1", "attr.aria-expanded": "rowNode().node.children?.length ? !!rowNode().node.expanded : null", "attr.aria-selected": "table.selectionMode() ? table.isSelected(rowNode().node) : null" } }, ngImport: i0 });
8864
+ }
8865
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableRowDirective, decorators: [{
8866
+ type: Directive,
8867
+ args: [{
8868
+ selector: 'tr[smzTtRow]',
8869
+ host: {
8870
+ '[class]': 'classes()',
8871
+ '[attr.aria-level]': 'rowNode().level + 1',
8872
+ '[attr.aria-expanded]': 'rowNode().node.children?.length ? !!rowNode().node.expanded : null',
8873
+ '[attr.aria-selected]': 'table.selectionMode() ? table.isSelected(rowNode().node) : null',
8874
+ '(click)': 'table.onRowClick(rowNode(), $event)',
8875
+ },
8876
+ }]
8877
+ }], propDecorators: { rowNode: [{ type: i0.Input, args: [{ isSignal: true, alias: "smzTtRow", required: true }] }] } });
8878
+ /** Seta de expandir/recolher com recuo por nivel: `<ui-tree-table-toggler [rowNode]="rowNode" />`. */
8879
+ class SmzTreeTableTogglerComponent {
8880
+ table = inject(SmzTreeTableComponent);
8881
+ rowNode = input.required(...(ngDevMode ? [{ debugName: "rowNode" }] : []));
8882
+ hasChildren() {
8883
+ const node = this.rowNode().node;
8884
+ return !node.leaf && (node.children?.length ?? 0) > 0;
8885
+ }
8886
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableTogglerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8887
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzTreeTableTogglerComponent, isStandalone: true, selector: "ui-tree-table-toggler", inputs: { rowNode: { classPropertyName: "rowNode", publicName: "rowNode", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "style.padding-left.rem": "rowNode().level * 1.5" }, classAttribute: "inline-flex items-center align-middle" }, ngImport: i0, template: `
8888
+ <button type="button" class="inline-flex h-6 w-6 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" [class.invisible]="!hasChildren()" [attr.aria-label]="rowNode().node.expanded ? 'Recolher' : 'Expandir'" (click)="$event.stopPropagation(); table.toggleNode(rowNode(), $event)">
8889
+ <svg viewBox="0 0 16 16" class="h-4 w-4 transition-transform duration-ui" [class.rotate-90]="rowNode().node.expanded" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" /></svg>
8890
+ </button>
8891
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
8892
+ }
8893
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableTogglerComponent, decorators: [{
8894
+ type: Component,
8895
+ args: [{
8896
+ selector: 'ui-tree-table-toggler',
8897
+ changeDetection: ChangeDetectionStrategy.OnPush,
8898
+ host: { class: 'inline-flex items-center align-middle', '[style.padding-left.rem]': 'rowNode().level * 1.5' },
8899
+ template: `
8900
+ <button type="button" class="inline-flex h-6 w-6 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" [class.invisible]="!hasChildren()" [attr.aria-label]="rowNode().node.expanded ? 'Recolher' : 'Expandir'" (click)="$event.stopPropagation(); table.toggleNode(rowNode(), $event)">
8901
+ <svg viewBox="0 0 16 16" class="h-4 w-4 transition-transform duration-ui" [class.rotate-90]="rowNode().node.expanded" fill="none" aria-hidden="true"><path d="M6 4l4 4-4 4" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" /></svg>
8902
+ </button>
8903
+ `,
8904
+ }]
8905
+ }], propDecorators: { rowNode: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowNode", required: true }] }] } });
8906
+ /** Checkbox de selecao da linha (modo `checkbox`): `<ui-tree-table-checkbox [value]="rowNode" />`. */
8907
+ class SmzTreeTableCheckboxComponent {
8908
+ table = inject(SmzTreeTableComponent);
8909
+ value = input.required(...(ngDevMode ? [{ debugName: "value" }] : []));
8910
+ state() {
8911
+ return this.table.selectionState(this.value().node);
8912
+ }
8913
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8914
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzTreeTableCheckboxComponent, isStandalone: true, selector: "ui-tree-table-checkbox", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "inline-flex align-middle" }, ngImport: i0, template: `
8915
+ <button type="button" role="checkbox" [attr.aria-checked]="state() === 'partial' ? 'mixed' : state() === 'checked'" class="inline-flex h-5 w-5 items-center justify-center rounded border transition-colors duration-ui focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" [class]="state() === 'unchecked' ? 'border-ui-line-strong bg-ui-surface-1' : 'border-ui-primary bg-ui-primary text-ui-on-primary'" (click)="$event.stopPropagation(); table.toggleCheckbox(value(), $event)">
8916
+ @if (state() === 'checked') { <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg> }
8917
+ @else if (state() === 'partial') { <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M4 8h8" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></svg> }
8918
+ </button>
8919
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
8920
+ }
8921
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableCheckboxComponent, decorators: [{
8922
+ type: Component,
8923
+ args: [{
8924
+ selector: 'ui-tree-table-checkbox',
8925
+ changeDetection: ChangeDetectionStrategy.OnPush,
8926
+ host: { class: 'inline-flex align-middle' },
8927
+ template: `
8928
+ <button type="button" role="checkbox" [attr.aria-checked]="state() === 'partial' ? 'mixed' : state() === 'checked'" class="inline-flex h-5 w-5 items-center justify-center rounded border transition-colors duration-ui focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" [class]="state() === 'unchecked' ? 'border-ui-line-strong bg-ui-surface-1' : 'border-ui-primary bg-ui-primary text-ui-on-primary'" (click)="$event.stopPropagation(); table.toggleCheckbox(value(), $event)">
8929
+ @if (state() === 'checked') { <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg> }
8930
+ @else if (state() === 'partial') { <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M4 8h8" stroke="currentColor" stroke-width="2" stroke-linecap="round" /></svg> }
8931
+ </button>
8932
+ `,
8933
+ }]
8934
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }] } });
8935
+ /** Checkbox do cabecalho: seleciona/limpa todos os nos. */
8936
+ class SmzTreeTableHeaderCheckboxComponent {
8937
+ table = inject(SmzTreeTableComponent);
8938
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableHeaderCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8939
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzTreeTableHeaderCheckboxComponent, isStandalone: true, selector: "ui-tree-table-header-checkbox", host: { classAttribute: "inline-flex align-middle" }, ngImport: i0, template: `
8940
+ <button type="button" role="checkbox" [attr.aria-checked]="table.allSelected()" class="inline-flex h-5 w-5 items-center justify-center rounded border transition-colors duration-ui focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" [class]="table.allSelected() ? 'border-ui-primary bg-ui-primary text-ui-on-primary' : 'border-ui-line-strong bg-ui-surface-1'" (click)="table.toggleAll(!table.allSelected())">
8941
+ @if (table.allSelected()) { <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg> }
8942
+ </button>
8943
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
8944
+ }
8945
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableHeaderCheckboxComponent, decorators: [{
8946
+ type: Component,
8947
+ args: [{
8948
+ selector: 'ui-tree-table-header-checkbox',
8949
+ changeDetection: ChangeDetectionStrategy.OnPush,
8950
+ host: { class: 'inline-flex align-middle' },
8951
+ template: `
8952
+ <button type="button" role="checkbox" [attr.aria-checked]="table.allSelected()" class="inline-flex h-5 w-5 items-center justify-center rounded border transition-colors duration-ui focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus" [class]="table.allSelected() ? 'border-ui-primary bg-ui-primary text-ui-on-primary' : 'border-ui-line-strong bg-ui-surface-1'" (click)="table.toggleAll(!table.allSelected())">
8953
+ @if (table.allSelected()) { <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-6.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg> }
8954
+ </button>
8955
+ `,
8956
+ }]
8957
+ }] });
8958
+ /** Cabecalho ordenavel: `<th [smzTtSortableColumn]="'nome'">Nome <ui-tree-table-sort-icon field="nome" /></th>`. */
8959
+ class SmzTreeTableSortableColumnDirective {
8960
+ table = inject(SmzTreeTableComponent);
8961
+ field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}), alias: 'smzTtSortableColumn' });
8962
+ ariaSort() {
8963
+ return this.table.sortField() === this.field() ? (this.table.sortOrder() === 1 ? 'ascending' : 'descending') : 'none';
8964
+ }
8965
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableSortableColumnDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
8966
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.1", type: SmzTreeTableSortableColumnDirective, isStandalone: true, selector: "th[smzTtSortableColumn]", inputs: { field: { classPropertyName: "field", publicName: "smzTtSortableColumn", isSignal: true, isRequired: true, transformFunction: null } }, host: { listeners: { "click": "table.sortBy(field())" }, properties: { "attr.aria-sort": "ariaSort()" }, classAttribute: "cursor-pointer select-none" }, ngImport: i0 });
8967
+ }
8968
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableSortableColumnDirective, decorators: [{
8969
+ type: Directive,
8970
+ args: [{
8971
+ selector: 'th[smzTtSortableColumn]',
8972
+ host: { class: 'cursor-pointer select-none', '(click)': 'table.sortBy(field())', '[attr.aria-sort]': 'ariaSort()' },
8973
+ }]
8974
+ }], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "smzTtSortableColumn", required: true }] }] } });
8975
+ class SmzTreeTableSortIconComponent {
8976
+ table = inject(SmzTreeTableComponent);
8977
+ field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
8978
+ dir() {
8979
+ return this.table.sortField() === this.field() ? this.table.sortOrder() : 0;
8980
+ }
8981
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableSortIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
8982
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.1", type: SmzTreeTableSortIconComponent, isStandalone: true, selector: "ui-tree-table-sort-icon", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "ml-1 inline-flex align-middle text-ui-fg-muted" }, ngImport: i0, template: `
8983
+ <svg viewBox="0 0 16 16" class="h-3.5 w-3.5" fill="none" aria-hidden="true">
8984
+ <path d="M5 6l3-3 3 3" [attr.stroke]="dir() === 1 ? 'rgb(var(--smz-color-primary))' : 'currentColor'" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
8985
+ <path d="M5 10l3 3 3-3" [attr.stroke]="dir() === -1 ? 'rgb(var(--smz-color-primary))' : 'currentColor'" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
8986
+ </svg>
8987
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
8988
+ }
8989
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzTreeTableSortIconComponent, decorators: [{
8990
+ type: Component,
8991
+ args: [{
8992
+ selector: 'ui-tree-table-sort-icon',
8993
+ changeDetection: ChangeDetectionStrategy.OnPush,
8994
+ host: { class: 'ml-1 inline-flex align-middle text-ui-fg-muted' },
8995
+ template: `
8996
+ <svg viewBox="0 0 16 16" class="h-3.5 w-3.5" fill="none" aria-hidden="true">
8997
+ <path d="M5 6l3-3 3 3" [attr.stroke]="dir() === 1 ? 'rgb(var(--smz-color-primary))' : 'currentColor'" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
8998
+ <path d="M5 10l3 3 3-3" [attr.stroke]="dir() === -1 ? 'rgb(var(--smz-color-primary))' : 'currentColor'" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
8999
+ </svg>
9000
+ `,
9001
+ }]
9002
+ }], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }] } });
9003
+ const SMZ_TREE_TABLE = [
9004
+ SmzTreeTableComponent,
9005
+ SmzTreeTableRowDirective,
9006
+ SmzTreeTableTogglerComponent,
9007
+ SmzTreeTableCheckboxComponent,
9008
+ SmzTreeTableHeaderCheckboxComponent,
9009
+ SmzTreeTableSortableColumnDirective,
9010
+ SmzTreeTableSortIconComponent,
9011
+ SmzTemplateDirective,
9012
+ ];
9013
+
9014
+ /* eslint-disable max-len -- classes Tailwind nos templates */
9015
+ class SmzConfirmContentComponent {
9016
+ options = inject(SmzDialogConfig).data;
9017
+ ref = inject((SmzDialogRef));
9018
+ close(accepted) {
9019
+ this.ref.close(accepted);
9020
+ }
9021
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzConfirmContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9022
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzConfirmContentComponent, isStandalone: true, selector: "ui-confirm-content", ngImport: i0, template: `
9023
+ <div class="flex items-start gap-3 font-ui text-ui-md text-ui-fg">
9024
+ @if (options.icon) {
9025
+ <i [class]="options.icon + ' mt-0.5 text-ui-xl text-ui-warning'" aria-hidden="true"></i>
9026
+ }
9027
+ <p class="m-0 flex-1">{{ options.message }}</p>
9028
+ </div>
9029
+ <div class="mt-5 flex justify-end gap-2">
9030
+ @if (options.rejectVisible !== false) {
9031
+ <button smzButton type="button" severity="secondary" variant="outlined" [label]="options.rejectLabel ?? 'Não'" (click)="close(false)"></button>
9032
+ }
9033
+ @if (options.acceptVisible !== false) {
9034
+ <button smzButton type="button" [severity]="options.acceptSeverity ?? 'primary'" [label]="options.acceptLabel ?? 'Sim'" (click)="close(true)"></button>
9035
+ }
9036
+ </div>
9037
+ `, isInline: true, dependencies: [{ kind: "component", type: SmzButtonComponent, selector: "button[smzButton], a[smzButton]", inputs: ["label", "icon", "iconPosition", "severity", "variant", "size", "text", "outlined", "rounded", "loading", "styleClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
9038
+ }
9039
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzConfirmContentComponent, decorators: [{
9040
+ type: Component,
9041
+ args: [{
9042
+ selector: 'ui-confirm-content',
9043
+ changeDetection: ChangeDetectionStrategy.OnPush,
9044
+ imports: [SmzButtonComponent],
9045
+ template: `
9046
+ <div class="flex items-start gap-3 font-ui text-ui-md text-ui-fg">
9047
+ @if (options.icon) {
9048
+ <i [class]="options.icon + ' mt-0.5 text-ui-xl text-ui-warning'" aria-hidden="true"></i>
9049
+ }
9050
+ <p class="m-0 flex-1">{{ options.message }}</p>
9051
+ </div>
9052
+ <div class="mt-5 flex justify-end gap-2">
9053
+ @if (options.rejectVisible !== false) {
9054
+ <button smzButton type="button" severity="secondary" variant="outlined" [label]="options.rejectLabel ?? 'Não'" (click)="close(false)"></button>
9055
+ }
9056
+ @if (options.acceptVisible !== false) {
9057
+ <button smzButton type="button" [severity]="options.acceptSeverity ?? 'primary'" [label]="options.acceptLabel ?? 'Sim'" (click)="close(true)"></button>
9058
+ }
9059
+ </div>
9060
+ `,
9061
+ }]
9062
+ }] });
9063
+ /**
9064
+ * Confirmacao modal. Substitui o `ConfirmationService` + `<p-confirmdialog>` do PrimeNG
9065
+ * (nao ha componente a declarar no template).
9066
+ *
9067
+ * confirm.confirm({ message: 'Excluir?', header: 'Confirmacao', icon: 'fa-solid fa-triangle-exclamation', accept: () => ..., reject: () => ... });
9068
+ */
9069
+ class SmzConfirmationService {
9070
+ dialogs = inject(SmzDialogService);
9071
+ confirm(confirmation) {
9072
+ const ref = this.dialogs.open(SmzConfirmContentComponent, {
9073
+ header: confirmation.header ?? 'Confirmação',
9074
+ width: confirmation.width ?? '28rem',
9075
+ closeOnEscape: confirmation.closeOnEscape ?? true,
9076
+ data: confirmation,
9077
+ });
9078
+ ref.onClose.subscribe((accepted) => {
9079
+ if (accepted === true)
9080
+ confirmation.accept?.();
9081
+ else
9082
+ confirmation.reject?.();
9083
+ });
9084
+ return ref;
9085
+ }
9086
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzConfirmationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
9087
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzConfirmationService, providedIn: 'root' });
9088
+ }
9089
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzConfirmationService, decorators: [{
9090
+ type: Injectable,
9091
+ args: [{ providedIn: 'root' }]
9092
+ }] });
9093
+
9094
+ /* eslint-disable max-len -- classes Tailwind nos templates */
9095
+ /**
9096
+ * Selecao de arquivos com area de arrastar e soltar e lista de escolhidos.
9097
+ * Substitui o `p-fileupload` (modo `basic`/`advanced` sem envio automatico): o envio ao servidor
9098
+ * fica a cargo do app (ex.: `HttpClient` no handler de `(selected)`).
9099
+ *
9100
+ * <ui-file-upload accept="image/*" [multiple]="true" [maxFileSize]="1000000" (selected)="enviar($event.files)" />
9101
+ */
9102
+ class SmzFileUploadComponent {
9103
+ accept = input('', ...(ngDevMode ? [{ debugName: "accept" }] : []));
9104
+ multiple = input(false, { ...(ngDevMode ? { debugName: "multiple" } : {}), transform: booleanAttribute });
9105
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}), transform: booleanAttribute });
9106
+ /** Tamanho maximo por arquivo, em bytes. */
9107
+ maxFileSize = input(null, ...(ngDevMode ? [{ debugName: "maxFileSize" }] : []));
9108
+ chooseLabel = input('Escolher arquivo', ...(ngDevMode ? [{ debugName: "chooseLabel" }] : []));
9109
+ dropLabel = input('ou arraste aqui', ...(ngDevMode ? [{ debugName: "dropLabel" }] : []));
9110
+ selected = output();
9111
+ removed = output();
9112
+ rejected = output();
9113
+ files = signal([], ...(ngDevMode ? [{ debugName: "files" }] : []));
9114
+ dragging = signal(false, ...(ngDevMode ? [{ debugName: "dragging" }] : []));
9115
+ fileInput = viewChild.required('picker');
9116
+ /** Limpa a lista (equivale a `clear()` do `p-fileupload`). */
9117
+ clear() {
9118
+ this.files.set([]);
9119
+ this.fileInput().nativeElement.value = '';
9120
+ }
9121
+ onPick(event) {
9122
+ const target = event.target;
9123
+ this.add(Array.from(target.files ?? []), event);
9124
+ target.value = '';
9125
+ }
9126
+ onDragOver(event) {
9127
+ if (this.disabled())
9128
+ return;
9129
+ event.preventDefault();
9130
+ this.dragging.set(true);
9131
+ }
9132
+ onDrop(event) {
9133
+ event.preventDefault();
9134
+ this.dragging.set(false);
9135
+ if (this.disabled())
9136
+ return;
9137
+ this.add(Array.from(event.dataTransfer?.files ?? []), event);
9138
+ }
9139
+ remove(file) {
9140
+ this.files.update((list) => list.filter((entry) => entry !== file));
9141
+ this.removed.emit({ file });
9142
+ }
9143
+ size(file) {
9144
+ return file.size < 1024 * 1024 ? `${Math.max(1, Math.round(file.size / 1024))} KB` : `${(file.size / 1024 / 1024).toFixed(1)} MB`;
9145
+ }
9146
+ add(incoming, event) {
9147
+ const accepted = [];
9148
+ for (const file of incoming) {
9149
+ if (!this.matchesAccept(file))
9150
+ this.rejected.emit({ file, reason: 'type' });
9151
+ else if (this.maxFileSize() != null && file.size > this.maxFileSize())
9152
+ this.rejected.emit({ file, reason: 'size' });
9153
+ else
9154
+ accepted.push(file);
9155
+ }
9156
+ if (accepted.length === 0)
9157
+ return;
9158
+ const next = this.multiple() ? [...this.files(), ...accepted] : [accepted[0]];
9159
+ this.files.set(next);
9160
+ this.selected.emit({ files: next, originalEvent: event });
9161
+ }
9162
+ matchesAccept(file) {
9163
+ const accept = (this.accept() ?? '').trim();
9164
+ if (!accept)
9165
+ return true;
9166
+ return accept.split(',').map((rule) => rule.trim().toLowerCase()).some((rule) => {
9167
+ if (rule.startsWith('.'))
9168
+ return file.name.toLowerCase().endsWith(rule);
9169
+ if (rule.endsWith('/*'))
9170
+ return file.type.toLowerCase().startsWith(rule.slice(0, -1));
9171
+ return file.type.toLowerCase() === rule;
9172
+ });
9173
+ }
9174
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzFileUploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9175
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: SmzFileUploadComponent, isStandalone: true, selector: "ui-file-upload", inputs: { accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, chooseLabel: { classPropertyName: "chooseLabel", publicName: "chooseLabel", isSignal: true, isRequired: false, transformFunction: null }, dropLabel: { classPropertyName: "dropLabel", publicName: "dropLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected", removed: "removed", rejected: "rejected" }, host: { classAttribute: "block font-ui text-ui-md text-ui-fg" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["picker"], descendants: true, isSignal: true }], ngImport: i0, template: `
9176
+ <input #picker type="file" class="sr-only" [accept]="accept() ?? ''" [multiple]="multiple()" [disabled]="disabled()" (change)="onPick($event)" />
9177
+ <div
9178
+ class="flex flex-col items-center justify-center gap-2 rounded-card border-2 border-dashed p-6 text-center transition-colors duration-ui"
9179
+ [class]="dragging() ? 'border-ui-primary bg-ui-primary/10' : 'border-ui-line-strong bg-ui-surface-1'"
9180
+ [class.opacity-50]="disabled()"
9181
+ (dragover)="onDragOver($event)"
9182
+ (dragleave)="dragging.set(false)"
9183
+ (drop)="onDrop($event)"
9184
+ >
9185
+ <button type="button" class="rounded-control border border-ui-line-strong px-control-x py-2 font-medium transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus disabled:pointer-events-none" [disabled]="disabled()" (click)="picker.click()">{{ chooseLabel() }}</button>
9186
+ <span class="text-ui-sm text-ui-fg-muted">{{ dropLabel() }}</span>
9187
+ </div>
9188
+ @if (files().length > 0) {
9189
+ <ul class="m-0 mt-3 flex list-none flex-col gap-2 p-0">
9190
+ @for (file of files(); track file) {
9191
+ <li class="flex items-center justify-between gap-2 rounded-control border border-ui-line px-3 py-2">
9192
+ <span class="min-w-0 flex-1 truncate">{{ file.name }} <span class="text-ui-sm text-ui-fg-muted">({{ size(file) }})</span></span>
9193
+ <button type="button" class="inline-flex h-6 w-6 items-center justify-center rounded-full text-ui-fg-muted hover:bg-ui-surface-3" aria-label="Remover" (click)="remove(file)">
9194
+ <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" /></svg>
9195
+ </button>
9196
+ </li>
9197
+ }
9198
+ </ul>
9199
+ }
9200
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
9201
+ }
9202
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: SmzFileUploadComponent, decorators: [{
9203
+ type: Component,
9204
+ args: [{
9205
+ selector: 'ui-file-upload',
9206
+ changeDetection: ChangeDetectionStrategy.OnPush,
9207
+ host: { class: 'block font-ui text-ui-md text-ui-fg' },
9208
+ template: `
9209
+ <input #picker type="file" class="sr-only" [accept]="accept() ?? ''" [multiple]="multiple()" [disabled]="disabled()" (change)="onPick($event)" />
9210
+ <div
9211
+ class="flex flex-col items-center justify-center gap-2 rounded-card border-2 border-dashed p-6 text-center transition-colors duration-ui"
9212
+ [class]="dragging() ? 'border-ui-primary bg-ui-primary/10' : 'border-ui-line-strong bg-ui-surface-1'"
9213
+ [class.opacity-50]="disabled()"
9214
+ (dragover)="onDragOver($event)"
9215
+ (dragleave)="dragging.set(false)"
9216
+ (drop)="onDrop($event)"
9217
+ >
9218
+ <button type="button" class="rounded-control border border-ui-line-strong px-control-x py-2 font-medium transition-colors duration-ui hover:bg-ui-surface-3 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ui-focus disabled:pointer-events-none" [disabled]="disabled()" (click)="picker.click()">{{ chooseLabel() }}</button>
9219
+ <span class="text-ui-sm text-ui-fg-muted">{{ dropLabel() }}</span>
9220
+ </div>
9221
+ @if (files().length > 0) {
9222
+ <ul class="m-0 mt-3 flex list-none flex-col gap-2 p-0">
9223
+ @for (file of files(); track file) {
9224
+ <li class="flex items-center justify-between gap-2 rounded-control border border-ui-line px-3 py-2">
9225
+ <span class="min-w-0 flex-1 truncate">{{ file.name }} <span class="text-ui-sm text-ui-fg-muted">({{ size(file) }})</span></span>
9226
+ <button type="button" class="inline-flex h-6 w-6 items-center justify-center rounded-full text-ui-fg-muted hover:bg-ui-surface-3" aria-label="Remover" (click)="remove(file)">
9227
+ <svg viewBox="0 0 16 16" class="h-3 w-3" fill="none" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" /></svg>
9228
+ </button>
9229
+ </li>
9230
+ }
9231
+ </ul>
9232
+ }
9233
+ `,
9234
+ }]
9235
+ }], propDecorators: { accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], chooseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "chooseLabel", required: false }] }], dropLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dropLabel", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }], removed: [{ type: i0.Output, args: ["removed"] }], rejected: [{ type: i0.Output, args: ["rejected"] }], fileInput: [{ type: i0.ViewChild, args: ['picker', { isSignal: true }] }] } });
9236
+
7994
9237
  /**
7995
9238
  * Generated bundle index. Do not edit.
7996
9239
  */
7997
9240
 
7998
- export { SMZ_DIALOG_CONTENT, SMZ_SOFT_TONE, SMZ_SOLID_TONE, SmzAccordionComponent, SmzAccordionContentComponent, SmzAccordionHeaderComponent, SmzAccordionPanelComponent, SmzAnchoredPanel, SmzAutoCompleteComponent, SmzAutoFocusDirective, SmzBadgeComponent, SmzBadgeDirective, SmzBlockUiComponent, SmzButtonComponent, SmzCheckboxComponent, SmzColorPickerComponent, SmzConnectedOverlayScrollHandler, SmzDataViewComponent, SmzDatePickerComponent, SmzDialogComponent, SmzDialogConfig, SmzDialogFrameComponent, SmzDialogRef, SmzDialogService, SmzDividerComponent, SmzDomHandler, SmzDrawerComponent, SmzFilterMatchMode, SmzFilterOperator, SmzFilterService, SmzIconComponent, SmzIconFieldComponent, SmzInputGroupAddonComponent, SmzInputGroupComponent, SmzInputIconComponent, SmzInputMaskComponent, SmzInputNumberComponent, SmzInputTextDirective, SmzListboxComponent, SmzLocaleService, SmzMenuListComponent, SmzMessageComponent, SmzMessageService, SmzMultiSelectComponent, SmzObjectUtils, SmzPaginatorComponent, SmzPasswordComponent, SmzPickListComponent, SmzPopoverComponent, SmzProgressBarComponent, SmzRadioButtonComponent, SmzRippleDirective, SmzSelectButtonComponent, SmzSelectComponent, SmzSkeletonComponent, SmzStyleClassDirective, SmzTabComponent, SmzTabListComponent, SmzTabPanelComponent, SmzTabPanelsComponent, SmzTabsComponent, SmzTagComponent, SmzTemplateDirective, SmzTextareaDirective, SmzThemeService, SmzToastContainerComponent, SmzToggleSwitchComponent, SmzToolbarComponent, SmzTooltipComponent, SmzTooltipDirective, SmzTranslationKeys, SmzTreeSelectComponent, SmzUiTimelineComponent, SmzUiTreeComponent, SmzValueAccessor, SmzZIndex, filterOptions, optionDisabled, optionLabel, optionValue, sameValue, smzCalendarStart, smzCx, smzFindTemplate, smzFormatDate, smzMergeClasses, smzNormalizeSeverity, smzNormalizeStyleClass, smzParseButtonStyleClass, smzParseDate, smzSameDay, smzStartOfDay, smzStaticHostClass, smzTwoDigits, smzUniqueId, smzVariants };
9241
+ export { SMZ_DIALOG_CONTENT, SMZ_SOFT_TONE, SMZ_SOLID_TONE, SMZ_TREE_TABLE, SmzAccordionComponent, SmzAccordionContentComponent, SmzAccordionHeaderComponent, SmzAccordionPanelComponent, SmzAnchoredPanel, SmzAutoCompleteComponent, SmzAutoFocusDirective, SmzBadgeComponent, SmzBadgeDirective, SmzBlockUiComponent, SmzButtonComponent, SmzCardComponent, SmzCheckboxComponent, SmzColorPickerComponent, SmzConfirmContentComponent, SmzConfirmationService, SmzConnectedOverlayScrollHandler, SmzDataViewComponent, SmzDatePickerComponent, SmzDialogComponent, SmzDialogConfig, SmzDialogFrameComponent, SmzDialogRef, SmzDialogService, SmzDividerComponent, SmzDomHandler, SmzDrawerComponent, SmzFileUploadComponent, SmzFilterMatchMode, SmzFilterOperator, SmzFilterService, SmzFloatLabelComponent, SmzIconComponent, SmzIconFieldComponent, SmzInputGroupAddonComponent, SmzInputGroupComponent, SmzInputIconComponent, SmzInputMaskComponent, SmzInputNumberComponent, SmzInputTextDirective, SmzListboxComponent, SmzLocaleService, SmzMenuListComponent, SmzMessageComponent, SmzMessageService, SmzMultiSelectComponent, SmzObjectUtils, SmzPaginatorComponent, SmzPanelComponent, SmzPasswordComponent, SmzPickListComponent, SmzPopoverComponent, SmzProgressBarComponent, SmzProgressSpinnerComponent, SmzRadioButtonComponent, SmzRippleDirective, SmzSelectButtonComponent, SmzSelectComponent, SmzSkeletonComponent, SmzSplitterComponent, SmzSplitterPanelComponent, SmzStyleClassDirective, SmzTabComponent, SmzTabListComponent, SmzTabPanelComponent, SmzTabPanelsComponent, SmzTabsComponent, SmzTagComponent, SmzTemplateDirective, SmzTextareaDirective, SmzThemeService, SmzToastContainerComponent, SmzToggleSwitchComponent, SmzToolbarComponent, SmzTooltipComponent, SmzTooltipDirective, SmzTranslationKeys, SmzTreeSelectComponent, SmzTreeTableCheckboxComponent, SmzTreeTableComponent, SmzTreeTableHeaderCheckboxComponent, SmzTreeTableRowDirective, SmzTreeTableSortIconComponent, SmzTreeTableSortableColumnDirective, SmzTreeTableTogglerComponent, SmzUiTimelineComponent, SmzUiTreeComponent, SmzValueAccessor, SmzZIndex, filterOptions, optionDisabled, optionLabel, optionValue, sameValue, smzCalendarStart, smzCx, smzFindTemplate, smzFormatDate, smzMergeClasses, smzNormalizeSeverity, smzNormalizeStyleClass, smzParseButtonStyleClass, smzParseDate, smzSameDay, smzStartOfDay, smzStaticHostClass, smzTwoDigits, smzUniqueId, smzVariants };
7999
9242
  //# sourceMappingURL=ngx-smz-ui-kit.mjs.map