@ajuarezso/sui-design-system 0.18.3 → 0.18.7

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 { InjectionToken, input, computed, ChangeDetectionStrategy, Component, inject, TemplateRef, Directive, model, signal, contentChild, viewChild, effect, untracked, output, ElementRef, forwardRef, ViewContainerRef, DestroyRef, ContentChild, ViewChild, ViewEncapsulation, Renderer2, DOCUMENT, HostListener, viewChildren, afterNextRender, ContentChildren, ViewChildren, Injector, Injectable } from '@angular/core';
2
+ import { InjectionToken, input, computed, ChangeDetectionStrategy, Component, inject, TemplateRef, Directive, model, signal, contentChild, viewChild, effect, untracked, output, ElementRef, forwardRef, ViewContainerRef, DestroyRef, ContentChild, ViewChild, ViewEncapsulation, Renderer2, DOCUMENT, HostListener, RendererStyleFlags2, viewChildren, afterNextRender, ContentChildren, ViewChildren, Injector, Injectable } from '@angular/core';
3
3
  import { NgTemplateOutlet, DOCUMENT as DOCUMENT$1, NgOptimizedImage } from '@angular/common';
4
4
  import { Router, RouterLink, RouterLinkActive } from '@angular/router';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
@@ -10059,6 +10059,23 @@ class SuiInput {
10059
10059
  return;
10060
10060
  if (recibeTexto(target))
10061
10061
  return;
10062
+ /* 3. El target no puede ser un ANCESTRO del host. Tocar el `body` no es
10063
+ tocar fuera del campo: el campo está adentro del body.
10064
+
10065
+ Es el tercer caso que se nos escapó (después de 0.14.3 y 0.15.3), y
10066
+ el que impedía SELECCIONAR TEXTO en iOS. Al mantener el dedo sobre el
10067
+ texto, WebKit levanta la lupa y emite eventos del gesto cuyo `target`
10068
+ es un ancestro —`body` o `html`— y no el campo. Ese evento pasaba los
10069
+ dos guards de arriba, y como el foco SÍ vive en este host, el
10070
+ componente se hacía blur A SÍ MISMO: el teclado se cerraba, el gesto
10071
+ se cancelaba y la selección nunca llegaba a agarrar. */
10072
+ if (target.contains?.(host))
10073
+ return;
10074
+ /* 4. Con una selección viva no se toca el foco: es un gesto en curso, y
10075
+ quitarle el foco al campo la descarta. */
10076
+ const sel = document.getSelection();
10077
+ if (sel && !sel.isCollapsed)
10078
+ return;
10062
10079
  const active = document.activeElement;
10063
10080
  if (active && host.contains(active))
10064
10081
  active.blur();
@@ -10816,6 +10833,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
10816
10833
  * contenido desde scrollTop 0 (solo por handle). Aquí SÍ soportamos ese
10817
10834
  * handoff (patrón Apple Maps nativo) vía touchmove no-pasivo + takeover.
10818
10835
  *
10836
+ * ── Modelo de movimiento (2026-09) ──────────────────────────────────────────
10837
+ *
10838
+ * Dos capas: `.sui-sheet` es un marco FIJO de alto constante
10839
+ * H = min(contenido, maxBreakpoint·100dvh, viewport − safe-top − 16px), anclado
10840
+ * abajo, que recorta (radius + squircle) y no captura toques; adentro,
10841
+ * `.sui-sheet__panel` (fondo, asa y body) es lo único que se mueve, con la
10842
+ * propiedad `translate` (compositor):
10843
+ *
10844
+ * y(p) = max(0, H − p·vh) visible(p) = min(H, p·vh)
10845
+ *
10846
+ * donde vh es el alto del viewport en px. Así al 25% se ven 25dvh del sheet, la
10847
+ * parte que baja queda recortada por el marco (las esquinas inferiores
10848
+ * redondeadas siguen a la vista, como antes) y el área libre del viewport sigue
10849
+ * siendo del contenido de fondo. Misma semántica que la versión anterior, que
10850
+ * animaba `max-height`, pero sin layout por frame: durante el drag no se toca
10851
+ * ningún signal ni binding — el `translate` del panel y la opacidad del
10852
+ * backdrop se escriben directo en el DOM dentro de un requestAnimationFrame
10853
+ * coalescido (una escritura por frame, gana el último pointermove). Los signals
10854
+ * `progress`, `currentBreakpoint` y `dragging` cambian al empezar/terminar el
10855
+ * drag y al snap, no por movimiento.
10856
+ *
10857
+ * Se usa `translate` (propiedad individual) y NO `transform`, y sobre el panel
10858
+ * y no sobre `.sui-sheet`: un consumer puede seguir escribiendo su propio
10859
+ * `transform`/`left`/`width` sobre `.sui-sheet` (ej. centrarlo en desktop) sin
10860
+ * pisar el movimiento.
10861
+ *
10819
10862
  * Uso típico para tracking de pedido con mapa abajo:
10820
10863
  * ```html
10821
10864
  * <sui-modal-sheet
@@ -10831,6 +10874,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
10831
10874
  */
10832
10875
  class SuiModalSheet {
10833
10876
  doc = inject(DOCUMENT$1);
10877
+ renderer = inject(Renderer2);
10834
10878
  navbarVisibility = inject(SUI_NAVBAR_VISIBILITY, { optional: true });
10835
10879
  /** ID único por instancia para el counter centralizado del navbar. */
10836
10880
  _sheetId = `sui-modal-sheet-${Math.random().toString(36).slice(2, 11)}`;
@@ -10860,66 +10904,101 @@ class SuiModalSheet {
10860
10904
  closed = output();
10861
10905
  breakpointChange = output();
10862
10906
  // ── Refs ──────────────────────────────────────────────────────────────────
10907
+ /** Marco fijo que recorta; se mide acá (alto H). */
10863
10908
  containerRef;
10909
+ /** Capa que se mueve (`translate`). */
10910
+ panelRef;
10911
+ backdropRef;
10864
10912
  handleRef;
10865
10913
  bodyRef;
10866
10914
  // ── State ─────────────────────────────────────────────────────────────────
10867
10915
  /** Breakpoint actual (0-1). Cambia al snap, no durante el drag. */
10868
10916
  currentBreakpoint = signal(0, ...(ngDevMode ? [{ debugName: "currentBreakpoint" }] : /* istanbul ignore next */ []));
10869
- /** Progress en vivo durante el drag (0-1). Expuesto como readonly al
10870
- template (binding `--sheet-progress`) y al public para que el consumer
10871
- pueda leerlo si quiere reaccionar. */
10872
- liveProgress = signal(0, ...(ngDevMode ? [{ debugName: "liveProgress" }] : /* istanbul ignore next */ []));
10873
- progress = this.liveProgress.asReadonly();
10874
- /** True mientras el usuario está arrastrando. Desactiva CSS transition. */
10917
+ /** Progress EN REPOSO (0-1): el breakpoint al que el sheet está o hacia el
10918
+ que va. Durante el drag NO se actualiza (el movimiento vive en el DOM,
10919
+ ver header): cambia al soltar y al snap. Expuesto al template como
10920
+ `--sheet-progress` y al consumer como `progress`. */
10921
+ restProgress = signal(0, ...(ngDevMode ? [{ debugName: "restProgress" }] : /* istanbul ignore next */ []));
10922
+ progress = this.restProgress.asReadonly();
10923
+ /** True mientras el usuario está arrastrando. Se setea al arrancar y al
10924
+ soltar; la clase CSS que apaga la transición se maneja imperativa en el
10925
+ mismo tick que la escritura del `translate` (ver `beginDrag`/`snapTo`). */
10875
10926
  dragging = signal(false, ...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
10876
- /** Opacity del backdrop calculada según el progress vivo. */
10877
- backdropOpacity = computed(() => this.computeBackdropOpacity(this.liveProgress()), ...(ngDevMode ? [{ debugName: "backdropOpacity" }] : /* istanbul ignore next */ []));
10927
+ /** Opacity del backdrop para el progress en reposo. La opacidad viva del
10928
+ drag se escribe directo en el DOM; este computed queda como API. */
10929
+ backdropOpacity = computed(() => this.computeBackdropOpacity(this.restProgress()), ...(ngDevMode ? [{ debugName: "backdropOpacity" }] : /* istanbul ignore next */ []));
10878
10930
  /** True si el backdrop debe capturar pointer events (current > backdropBreakpoint). */
10879
- backdropInteractive = computed(() => this.liveProgress() > this.backdropBreakpoint(), ...(ngDevMode ? [{ debugName: "backdropInteractive" }] : /* istanbul ignore next */ []));
10880
- /** CAP de altura del sheet — `min(progress·100dvh, viewport - safe-top - 16)`.
10881
- Se bindea como max-height con `height: max-content` en el scss: el sheet
10882
- NUNCA mide más que su contenido (sin espacio vacío al final cuando el
10883
- contenido termina antes del breakpoint), y el breakpoint actúa como techo.
10884
- Cuando progress=0.25 el sheet ocupa a lo sumo 25dvh y el resto del
10885
- viewport queda VACÍO → contenido detrás (mapa) interactivo. */
10886
- heightCss = computed(() => `min(${this.liveProgress() * 100}dvh, calc(100dvh - env(safe-area-inset-top, 0px) - 16px))`, ...(ngDevMode ? [{ debugName: "heightCss" }] : /* istanbul ignore next */ []));
10931
+ backdropInteractive = computed(() => this.restProgress() > this.backdropBreakpoint(), ...(ngDevMode ? [{ debugName: "backdropInteractive" }] : /* istanbul ignore next */ []));
10932
+ /** Breakpoint máximo del array (1 si está vacío). */
10933
+ maxBreakpoint = computed(() => {
10934
+ const bps = this.breakpoints();
10935
+ return bps.length ? Math.max(...bps) : 1;
10936
+ }, ...(ngDevMode ? [{ debugName: "maxBreakpoint" }] : /* istanbul ignore next */ []));
10937
+ /** CAP ESTÁTICO de altura — `min(maxBp·100dvh, viewport − safe-top − 16)`.
10938
+ Con `height: max-content` en el scss el sheet mide su contenido y este
10939
+ techo lo acota. Depende solo de `breakpoints`: no cambia por drag ni por
10940
+ snap, así que no fuerza layout durante el gesto. */
10941
+ maxHeightCss = computed(() => `min(${this.maxBreakpoint() * 100}dvh, calc(100dvh - env(safe-area-inset-top, 0px) - 16px))`, ...(ngDevMode ? [{ debugName: "maxHeightCss" }] : /* istanbul ignore next */ []));
10887
10942
  /** True cuando el sheet está al breakpoint máximo del array. En ese punto
10888
10943
  habilitamos scroll del body (touch-action: pan-y) — el user ya no puede
10889
10944
  expandir más, así que se prioriza ver el contenido sobre el drag. En el
10890
10945
  resto de breakpoints el body actúa como handle gigante (touch-action:
10891
- none) y solo el drag controla la altura del sheet. */
10946
+ none) y solo el drag controla la posición del sheet. */
10892
10947
  atMaxBreakpoint = computed(() => {
10893
10948
  const bps = this.breakpoints();
10894
10949
  if (bps.length === 0)
10895
10950
  return false;
10896
- const maxBp = Math.max(...bps);
10897
- return this.currentBreakpoint() >= maxBp;
10951
+ return this.currentBreakpoint() >= this.maxBreakpoint();
10898
10952
  }, ...(ngDevMode ? [{ debugName: "atMaxBreakpoint" }] : /* istanbul ignore next */ []));
10899
- // ── Drag state (no signals, se manejan imperativamente) ───────────────────
10953
+ // ── Geometría / drag (imperativo, sin signals) ───────────────────────────
10954
+ /** Alto medido del sheet (px). Se mide al abrir, al empezar un drag y
10955
+ cuando el contenido cambia de tamaño (ResizeObserver). */
10956
+ sheetHeight = 0;
10957
+ /** Alto del viewport (px) = 1 unidad de progress. */
10958
+ viewportHeight = 0;
10900
10959
  dragStartY = 0;
10901
10960
  dragStartProgress = 0;
10902
- wrapperHeight = 0;
10903
10961
  pointerId = null;
10904
10962
  /** Para calcular velocity al final */
10905
10963
  lastMoveTime = 0;
10906
10964
  lastMoveY = 0;
10907
10965
  velocityY = 0;
10966
+ /** Último progress pedido por el dedo; lo consume el rAF. */
10967
+ pendingProgress = null;
10968
+ frameId = null;
10908
10969
  /** Flag para distinguir drag iniciado en body (scroll-then-drag) vs en handle.
10909
10970
  En body, el drag NO arranca con pointerdown — sólo si pointermove
10910
10971
  excede un threshold y la condición de scroll lo permite. Sirve para no
10911
10972
  robar tap/click a buttons internos. */
10912
10973
  bodyDragArmed = false;
10913
10974
  /** Threshold de movimiento (px) para decidir que un pointermove en body es
10914
- drag (no tap). Patrón iOS estándar ~6-10px. */
10915
- /* 5px = más sensible que el iOS canon de 8px. El user pidió "como nativo"
10916
- pero el threshold default del 8px sentía que tardaba en activar.
10917
- Trade-off: 5px puede activar drag con micro-movements al hacer tap, pero
10918
- la heurística shouldIgnoreBodyDrag protege inputs/select/option. */
10975
+ drag (no tap). 5px = más sensible que el iOS canon de 8px: el dueño pidió
10976
+ "como nativo" y el 8 sentía que tardaba en activar. Trade-off: 5px puede
10977
+ activar drag con micro-movements al hacer tap, pero la heurística
10978
+ shouldIgnoreBodyDrag protege inputs/select/option. */
10919
10979
  static BODY_DRAG_THRESHOLD_PX = 5;
10980
+ /** Lookahead de velocidad al soltar (ms): predice dónde estaría el dedo y
10981
+ snapea ahí. Permite que un swipe rápido brinque breakpoints sin saltarse
10982
+ los intermedios. 80ms validado en device: a 150 se saltaba el 0.7 entre
10983
+ 0.5 y 1; a 0 el sheet se sentía pesado. */
10984
+ static VELOCITY_LOOKAHEAD_MS = 80;
10985
+ /** Duración del snap: se acota entre estos dos valores según distancia
10986
+ restante / velocidad del dedo (ver `snapDuration`). */
10987
+ static SNAP_MIN_MS = 180;
10988
+ static SNAP_MAX_MS = 350;
10989
+ static CLASS_PANEL_DRAGGING = 'sui-sheet__panel--dragging';
10990
+ static CLASS_BACKDROP_DRAGGING = 'sui-sheet__backdrop--dragging';
10991
+ /** Cerrado = el panel baja todo su alto y el marco lo recorta entero. Se usa
10992
+ `100%` (y no el H medido) para que el cierre quede bien aunque el
10993
+ contenido cambie de tamaño a mitad de camino. */
10994
+ static TRANSLATE_CLOSED = '0 100%';
10920
10995
  // ── Lifecycle ─────────────────────────────────────────────────────────────
10921
10996
  wasOpen = false;
10922
10997
  escapeHandler;
10998
+ closeTimer = null;
10999
+ closeTransitionHandler;
11000
+ resizeObserver;
11001
+ windowResizeHandler;
10923
11002
  constructor() {
10924
11003
  effect(() => {
10925
11004
  const isOpen = this.open();
@@ -10935,6 +11014,9 @@ class SuiModalSheet {
10935
11014
  ngOnDestroy() {
10936
11015
  this.removeEscapeHandler();
10937
11016
  this.detachTouchSuppressor();
11017
+ this.stopObservingSize();
11018
+ this.cancelPendingClose();
11019
+ this.cancelFrame();
10938
11020
  this.unlockBodyScroll();
10939
11021
  if (this.wasOpen) {
10940
11022
  this.navbarVisibility?.release(this._sheetId);
@@ -10958,20 +11040,29 @@ class SuiModalSheet {
10958
11040
  this.lockBodyScroll();
10959
11041
  this.navbarVisibility?.requestHide(this._sheetId);
10960
11042
  this.attachEscapeHandler();
10961
- /* Setear initial breakpoint en el siguiente tick (después del render para
10962
- que el container ya tenga clientHeight). */
11043
+ /* Snap al initial breakpoint en el siguiente tick (después del render,
11044
+ cuando el container ya existe y mide). El panel nace en `translate:
11045
+ 0 100%` (scss) y la lectura de offsetHeight dentro de `snapTo` fuerza
11046
+ el recálculo de estilo que hace que la escritura del destino
11047
+ transicione: la entrada se ve deslizando desde abajo. */
10963
11048
  setTimeout(() => {
10964
- const initial = this.initialBreakpoint();
10965
- this.snapTo(initial, false);
11049
+ this.snapTo(this.initialBreakpoint(), true);
10966
11050
  this.attachTouchSuppressor();
11051
+ this.observeSize();
10967
11052
  }, 0);
10968
11053
  }
10969
11054
  onClose() {
10970
11055
  this.removeEscapeHandler();
10971
11056
  this.detachTouchSuppressor();
11057
+ this.stopObservingSize();
11058
+ this.cancelPendingClose();
11059
+ this.cancelFrame();
10972
11060
  this.unlockBodyScroll();
10973
11061
  this.navbarVisibility?.release(this._sheetId);
10974
- this.liveProgress.set(0);
11062
+ this.pointerId = null;
11063
+ this.bodyDragArmed = false;
11064
+ this.dragging.set(false);
11065
+ this.restProgress.set(0);
10975
11066
  this.currentBreakpoint.set(0);
10976
11067
  this.closed.emit();
10977
11068
  }
@@ -10988,6 +11079,8 @@ class SuiModalSheet {
10988
11079
  // Con el default prevenido, el scroll nativo nunca arranca y los pointer
10989
11080
  // events siguen fluyendo hacia la lógica de drag existente. Los touch
10990
11081
  // handlers de Angular son pasivos por default — por eso se atachan a mano.
11082
+ // El touchstart sí es pasivo (no previene nada). Los pointer events no son
11083
+ // scroll-blocking, así que `passive` no les aplica.
10991
11084
  touchStartY = 0;
10992
11085
  touchStartHandler;
10993
11086
  touchMoveHandler;
@@ -11030,43 +11123,220 @@ class SuiModalSheet {
11030
11123
  this.touchStartHandler = undefined;
11031
11124
  this.touchMoveHandler = undefined;
11032
11125
  }
11033
- // ── Drag gesture ──────────────────────────────────────────────────────────
11034
- onPointerDown(event) {
11035
- /* Solo eventos primarios (un dedo, click izquierdo). Multi-touch zoom etc.
11036
- no inicia drag. */
11037
- if (!event.isPrimary)
11126
+ // ── Medición ──────────────────────────────────────────────────────────────
11127
+ /** Mide alto del sheet y del viewport. Devuelve false si todavía no hay
11128
+ layout (container sin render o entorno sin medidas, ej. jsdom). Es la
11129
+ ÚNICA lectura de layout del gesto: se hace al abrir, al pointerdown y
11130
+ cuando cambia el tamaño — nunca por pointermove. */
11131
+ measure() {
11132
+ const container = this.containerRef?.nativeElement;
11133
+ const win = this.doc.defaultView;
11134
+ if (!container || !win)
11135
+ return false;
11136
+ this.sheetHeight = container.offsetHeight;
11137
+ this.viewportHeight = win.innerHeight || this.doc.documentElement.clientHeight;
11138
+ return this.sheetHeight > 0 && this.viewportHeight > 0;
11139
+ }
11140
+ /** Desplazamiento vertical (px) para un progress: `max(0, H − p·vh)`. */
11141
+ yFor(progress) {
11142
+ if (progress <= 0)
11143
+ return this.sheetHeight;
11144
+ return Math.max(0, this.sheetHeight - progress * this.viewportHeight);
11145
+ }
11146
+ /** Valor de `translate` para un progress. */
11147
+ translateFor(progress) {
11148
+ if (progress <= 0)
11149
+ return SuiModalSheet.TRANSLATE_CLOSED;
11150
+ return `0 ${this.yFor(progress)}px`;
11151
+ }
11152
+ /** Progress EFECTIVO de un breakpoint: el que corresponde al y que el sheet
11153
+ muestra de verdad. Con contenido corto varios breakpoints valen y = 0 y
11154
+ su progress efectivo es H/vh, no el nominal — es el punto de partida
11155
+ correcto para que el dedo mueva 1:1 desde ahí. */
11156
+ effectiveProgress(breakpoint) {
11157
+ if (this.viewportHeight === 0)
11158
+ return breakpoint;
11159
+ const p = (this.sheetHeight - this.yFor(breakpoint)) / this.viewportHeight;
11160
+ return Math.max(0, Math.min(1, p));
11161
+ }
11162
+ /** Progress real del sheet leyendo el `translate` computado del panel —
11163
+ sirve para agarrarlo a mitad de una transición sin que salte al
11164
+ breakpoint de destino. Si no se puede leer (jsdom, valor no numérico,
11165
+ un calc() a mitad de la entrada) cae al progress efectivo del
11166
+ `currentBreakpoint`. */
11167
+ progressFromDom() {
11168
+ const fallback = this.effectiveProgress(this.currentBreakpoint());
11169
+ const panel = this.panelRef?.nativeElement;
11170
+ const win = this.doc.defaultView;
11171
+ if (!panel || !win || this.viewportHeight === 0)
11172
+ return fallback;
11173
+ const raw = win.getComputedStyle(panel).translate;
11174
+ const parts = raw ? raw.trim().split(/\s+/) : [];
11175
+ const yPart = parts[1] ?? parts[0];
11176
+ if (!yPart || !yPart.endsWith('px'))
11177
+ return fallback;
11178
+ const y = parseFloat(yPart);
11179
+ if (!Number.isFinite(y))
11180
+ return fallback;
11181
+ const p = (this.sheetHeight - y) / this.viewportHeight;
11182
+ return Math.max(0, Math.min(1, p));
11183
+ }
11184
+ // ── Escrituras al DOM (sin signals) ───────────────────────────────────────
11185
+ writeTranslate(progress) {
11186
+ const panel = this.panelRef?.nativeElement;
11187
+ if (!panel)
11188
+ return;
11189
+ this.renderer.setStyle(panel, 'translate', this.translateFor(progress), RendererStyleFlags2.DashCase);
11190
+ }
11191
+ writeBackdropOpacity(progress) {
11192
+ const backdrop = this.backdropRef?.nativeElement;
11193
+ if (!backdrop)
11194
+ return;
11195
+ this.renderer.setStyle(backdrop, 'opacity', String(this.computeBackdropOpacity(progress)));
11196
+ }
11197
+ setTransitionDuration(ms) {
11198
+ const value = `${ms}ms`;
11199
+ const panel = this.panelRef?.nativeElement;
11200
+ const backdrop = this.backdropRef?.nativeElement;
11201
+ if (panel)
11202
+ this.renderer.setStyle(panel, 'transition-duration', value, RendererStyleFlags2.DashCase);
11203
+ if (backdrop)
11204
+ this.renderer.setStyle(backdrop, 'transition-duration', value, RendererStyleFlags2.DashCase);
11205
+ }
11206
+ setDraggingClasses(on) {
11207
+ const panel = this.panelRef?.nativeElement;
11208
+ const backdrop = this.backdropRef?.nativeElement;
11209
+ const op = on ? 'addClass' : 'removeClass';
11210
+ if (panel)
11211
+ this.renderer[op](panel, SuiModalSheet.CLASS_PANEL_DRAGGING);
11212
+ if (backdrop)
11213
+ this.renderer[op](backdrop, SuiModalSheet.CLASS_BACKDROP_DRAGGING);
11214
+ }
11215
+ /** Coalesce: guarda el último progress y escribe UNA vez por frame. */
11216
+ scheduleFrame(progress) {
11217
+ this.pendingProgress = progress;
11218
+ if (this.frameId !== null)
11219
+ return;
11220
+ const win = this.doc.defaultView;
11221
+ if (!win || typeof win.requestAnimationFrame !== 'function') {
11222
+ this.flushFrame();
11223
+ return;
11224
+ }
11225
+ this.frameId = win.requestAnimationFrame(() => {
11226
+ this.frameId = null;
11227
+ this.flushFrame();
11228
+ });
11229
+ }
11230
+ flushFrame() {
11231
+ if (this.pendingProgress === null)
11232
+ return;
11233
+ const p = this.pendingProgress;
11234
+ this.pendingProgress = null;
11235
+ this.writeTranslate(p);
11236
+ this.writeBackdropOpacity(p);
11237
+ }
11238
+ cancelFrame() {
11239
+ if (this.frameId !== null) {
11240
+ this.doc.defaultView?.cancelAnimationFrame(this.frameId);
11241
+ this.frameId = null;
11242
+ }
11243
+ this.pendingProgress = null;
11244
+ }
11245
+ // ── Tamaño del contenido / viewport ───────────────────────────────────────
11246
+ //
11247
+ // El alto H entra en la fórmula del translate. Si el contenido crece después
11248
+ // de abrir (datos async, un acordeón que se expande) o el viewport cambia
11249
+ // (rotación, teclado en Android), el y viejo dejaría al sheet mostrando más
11250
+ // o menos de lo que dice su breakpoint. Se re-deriva la posición en reposo
11251
+ // sin transición.
11252
+ observeSize() {
11253
+ const container = this.containerRef?.nativeElement;
11254
+ const win = this.doc.defaultView;
11255
+ if (!container || !win)
11256
+ return;
11257
+ if (typeof ResizeObserver !== 'undefined' && !this.resizeObserver) {
11258
+ this.resizeObserver = new ResizeObserver(() => this.onSizeChange());
11259
+ this.resizeObserver.observe(container);
11260
+ }
11261
+ if (!this.windowResizeHandler) {
11262
+ this.windowResizeHandler = () => this.onSizeChange();
11263
+ win.addEventListener('resize', this.windowResizeHandler, { passive: true });
11264
+ }
11265
+ }
11266
+ stopObservingSize() {
11267
+ this.resizeObserver?.disconnect();
11268
+ this.resizeObserver = undefined;
11269
+ if (this.windowResizeHandler) {
11270
+ this.doc.defaultView?.removeEventListener('resize', this.windowResizeHandler);
11271
+ this.windowResizeHandler = undefined;
11272
+ }
11273
+ }
11274
+ onSizeChange() {
11275
+ if (this.dragging() || !this.open())
11276
+ return;
11277
+ const prevH = this.sheetHeight;
11278
+ const prevVh = this.viewportHeight;
11279
+ if (!this.measure())
11280
+ return;
11281
+ if (prevH === this.sheetHeight && prevVh === this.viewportHeight)
11038
11282
  return;
11039
- this.wrapperHeight = this.containerRef?.nativeElement?.clientHeight ?? 0;
11040
- if (this.wrapperHeight === 0)
11283
+ const p = this.restProgress();
11284
+ if (p <= 0)
11041
11285
  return;
11286
+ this.setTransitionDuration(0);
11287
+ this.writeTranslate(p);
11288
+ this.writeBackdropOpacity(p);
11289
+ }
11290
+ // ── Drag gesture ──────────────────────────────────────────────────────────
11291
+ /** Arranque común del drag (handle o body ya armado): congela la transición
11292
+ en curso, lee la posición real y marca `dragging`. */
11293
+ beginDrag(event) {
11294
+ this.cancelPendingClose();
11295
+ this.cancelFrame();
11042
11296
  this.pointerId = event.pointerId;
11043
11297
  this.dragStartY = event.clientY;
11044
- this.dragStartProgress = this.currentBreakpoint();
11298
+ this.dragStartProgress = this.progressFromDom();
11045
11299
  this.lastMoveY = event.clientY;
11046
11300
  this.lastMoveTime = performance.now();
11047
11301
  this.velocityY = 0;
11302
+ /* Congelar donde está: la clase apaga la transición y el translate se
11303
+ fija en el valor actual (si se agarró a mitad de un snap). */
11304
+ this.setDraggingClasses(true);
11305
+ this.writeTranslate(this.dragStartProgress);
11306
+ this.writeBackdropOpacity(this.dragStartProgress);
11048
11307
  this.dragging.set(true);
11308
+ }
11309
+ onPointerDown(event) {
11310
+ /* Solo eventos primarios (un dedo, click izquierdo). Multi-touch zoom etc.
11311
+ no inicia drag. */
11312
+ if (!event.isPrimary)
11313
+ return;
11314
+ if (!this.measure())
11315
+ return;
11316
+ this.beginDrag(event);
11049
11317
  /* setPointerCapture en el handle hace que pointermove/pointerup sigan
11050
11318
  llegando aunque el dedo salga del elemento original. Sin esto, swipes
11051
11319
  largos pierden eventos. */
11052
11320
  const handle = this.handleRef?.nativeElement;
11053
- handle?.setPointerCapture(event.pointerId);
11321
+ try {
11322
+ handle?.setPointerCapture(event.pointerId);
11323
+ }
11324
+ catch { /* noop */ }
11054
11325
  event.preventDefault();
11055
11326
  }
11056
11327
  onPointerMove(event) {
11057
11328
  if (this.pointerId !== event.pointerId || !this.dragging())
11058
11329
  return;
11059
11330
  const deltaY = event.clientY - this.dragStartY;
11060
- /* Convertir deltaY a delta de progress: arrastrar hacia abajo (deltaY+)
11061
- reduce el progress (sheet baja). */
11062
- const deltaProgress = -deltaY / this.wrapperHeight;
11063
- const next = this.dragStartProgress + deltaProgress;
11331
+ /* 1:1 con el dedo: 1 unidad de progress = el alto del viewport. Arrastrar
11332
+ hacia abajo (deltaY+) reduce el progress (sheet baja). */
11333
+ const next = this.dragStartProgress - deltaY / this.viewportHeight;
11064
11334
  /* Clamp al rango del array de breakpoints. Min = primer breakpoint del
11065
11335
  array — si el array no incluye 0, el sheet NUNCA puede cerrarse por
11066
11336
  gesture (Apple Maps style). Max acotado a 1. */
11067
11337
  const minBp = this.breakpoints()[0] ?? 0;
11068
11338
  const clamped = Math.max(minBp, Math.min(1, next));
11069
- this.liveProgress.set(clamped);
11339
+ this.scheduleFrame(clamped);
11070
11340
  /* Velocity tracking para boost del snap */
11071
11341
  const now = performance.now();
11072
11342
  const dt = now - this.lastMoveTime;
@@ -11085,7 +11355,6 @@ class SuiModalSheet {
11085
11355
  const wasDragging = this.dragging();
11086
11356
  this.pointerId = null;
11087
11357
  this.bodyDragArmed = false;
11088
- this.dragging.set(false);
11089
11358
  const handle = this.handleRef?.nativeElement;
11090
11359
  const body = this.bodyRef?.nativeElement;
11091
11360
  try {
@@ -11098,28 +11367,32 @@ class SuiModalSheet {
11098
11367
  catch { /* noop */ }
11099
11368
  if (!wasDragging)
11100
11369
  return;
11101
- /* Aplicar boost de velocity al progress final antes de snappear. Velocity
11102
- en px/ms × (1/wrapperHeight) = progress/ms. Multiplicamos por una
11103
- constante "lookahead" que predice ~80ms en el futuro — esto permite
11104
- swipes rápidos brincar breakpoints SIN saltarse breakpoints intermedios
11105
- (ej. 0.7 entre 0.5 y 1.0). 80ms es el sweet spot validado: a 150ms se
11106
- saltaba el 0.7 con cualquier swipe medio-rápido; a 0ms el sheet se
11107
- sentía pesado y nunca brincaba breakpoints. */
11108
- const lookaheadMs = 80;
11109
- const velocityProgress = -(this.velocityY * lookaheadMs) / this.wrapperHeight;
11110
- const projected = Math.max(0, Math.min(1, this.liveProgress() + velocityProgress));
11111
- const snapBp = this.findClosestBreakpoint(projected);
11112
- this.snapTo(snapBp, true);
11370
+ /* El último move pendiente define dónde quedó el dedo. */
11371
+ const released = this.pendingProgress ?? this.progressFromDom();
11372
+ this.cancelFrame();
11373
+ /* Boost de velocity: predice ~80ms en el futuro (px/ms × ms) y snapea al
11374
+ breakpoint más cercano de ESE punto. Se decide en PÍXELES y no en
11375
+ progress: con contenido corto varios breakpoints comparten y = 0 (el
11376
+ sheet no puede mostrar más que su alto) y medir en progress cerraba el
11377
+ sheet con un arrastre mínimo desde el máximo. */
11378
+ const yReleased = this.yFor(released);
11379
+ const yProjected = Math.max(0, Math.min(this.sheetHeight, yReleased + this.velocityY * SuiModalSheet.VELOCITY_LOOKAHEAD_MS));
11380
+ const snapBp = this.closestBreakpointByY(yProjected);
11381
+ this.dragging.set(false);
11382
+ this.snapTo(snapBp, true, released, Math.abs(this.velocityY));
11113
11383
  }
11114
11384
  onPointerCancel(event) {
11115
11385
  /* Si el browser cancela el pointer (ej. scroll fight, otra app), volvemos
11116
11386
  al currentBreakpoint sin animar agresivo. */
11117
11387
  if (this.pointerId !== event.pointerId)
11118
11388
  return;
11389
+ const wasDragging = this.dragging();
11119
11390
  this.pointerId = null;
11120
11391
  this.bodyDragArmed = false;
11392
+ const released = wasDragging ? (this.pendingProgress ?? this.progressFromDom()) : this.currentBreakpoint();
11393
+ this.cancelFrame();
11121
11394
  this.dragging.set(false);
11122
- this.snapTo(this.currentBreakpoint(), true);
11395
+ this.snapTo(this.currentBreakpoint(), true, released);
11123
11396
  }
11124
11397
  // ── Body drag (scroll-then-drag canon iOS) ───────────────────────────────
11125
11398
  //
@@ -11134,8 +11407,8 @@ class SuiModalSheet {
11134
11407
  // hacia arriba: scroll body.
11135
11408
  //
11136
11409
  // Importante: el drag NO arranca en pointerdown — lo armamos pero esperamos
11137
- // a que pointermove supere un threshold (8px) antes de marcar `dragging`.
11138
- // Esto evita robarle el click/tap a buttons del body.
11410
+ // a que pointermove supere el threshold antes de marcar `dragging`. Esto
11411
+ // evita robarle el click/tap a buttons del body.
11139
11412
  onBodyPointerDown(event) {
11140
11413
  if (!event.isPrimary)
11141
11414
  return;
@@ -11144,14 +11417,12 @@ class SuiModalSheet {
11144
11417
  const target = event.target;
11145
11418
  if (this.shouldIgnoreBodyDrag(target))
11146
11419
  return;
11147
- this.wrapperHeight = this.containerRef?.nativeElement?.clientHeight ?? 0;
11148
- if (this.wrapperHeight === 0)
11420
+ if (!this.measure())
11149
11421
  return;
11150
11422
  /* Solo armamos — el drag real arranca cuando pointermove supere threshold. */
11151
11423
  this.bodyDragArmed = true;
11152
11424
  this.pointerId = event.pointerId;
11153
11425
  this.dragStartY = event.clientY;
11154
- this.dragStartProgress = this.currentBreakpoint();
11155
11426
  this.lastMoveY = event.clientY;
11156
11427
  this.lastMoveTime = performance.now();
11157
11428
  this.velocityY = 0;
@@ -11171,9 +11442,7 @@ class SuiModalSheet {
11171
11442
  const deltaY = event.clientY - this.dragStartY;
11172
11443
  if (Math.abs(deltaY) < SuiModalSheet.BODY_DRAG_THRESHOLD_PX)
11173
11444
  return;
11174
- /* Track velocity instantánea para detectar "fling down" — patrón canon
11175
- iOS / Apple Maps / Twitter X: un swipe rápido hacia abajo colapsa el
11176
- sheet incluso si el body está scrolleado en medio del contenido. */
11445
+ /* Track velocity instantánea. */
11177
11446
  const now = performance.now();
11178
11447
  const dt = now - this.lastMoveTime;
11179
11448
  if (dt > 0) {
@@ -11207,14 +11476,14 @@ class SuiModalSheet {
11207
11476
  }
11208
11477
  }
11209
11478
  this.bodyDragArmed = false;
11210
- this.dragging.set(true);
11479
+ /* El drag arranca DESDE la posición actual del dedo (touch slop, como
11480
+ UIKit): los primeros 5px no mueven el sheet en vez de hacerlo saltar. */
11481
+ this.beginDrag(event);
11211
11482
  try {
11212
11483
  body?.setPointerCapture(event.pointerId);
11213
11484
  }
11214
11485
  catch { /* noop */ }
11215
11486
  event.preventDefault();
11216
- /* Forwardear este move ya en modo drag para no perder el delta. */
11217
- this.onPointerMove(event);
11218
11487
  }
11219
11488
  /** Heurística: ignorar drag si el target es un input/textarea/select/button
11220
11489
  interactivo. El user está intentando interactuar, no arrastrar. */
@@ -11232,18 +11501,41 @@ class SuiModalSheet {
11232
11501
  return false;
11233
11502
  }
11234
11503
  // ── Snap ──────────────────────────────────────────────────────────────────
11235
- snapTo(breakpoint, animated) {
11236
- /* Si el snap es a 0, animamos pero después emitimos close. La animación de
11237
- cierre la maneja el CSS transition (350ms). */
11238
- this.liveProgress.set(breakpoint);
11504
+ /** Duración del snap en función de la distancia restante y la velocidad del
11505
+ dedo (px/ms): un fling rápido cierra la distancia en poco tiempo; un
11506
+ release lento o un snap programático usa la duración larga. Acotado a
11507
+ [180, 350] ms. */
11508
+ snapDuration(distancePx, velocityPxMs) {
11509
+ const speed = Math.max(velocityPxMs, 0.5);
11510
+ const raw = distancePx / speed;
11511
+ return Math.round(Math.max(SuiModalSheet.SNAP_MIN_MS, Math.min(SuiModalSheet.SNAP_MAX_MS, raw)));
11512
+ }
11513
+ /**
11514
+ * Lleva el sheet a `breakpoint`.
11515
+ * @param fromProgress progress desde el que sale (default: el de reposo);
11516
+ * solo influye en la duración.
11517
+ * @param velocityPxMs velocidad del dedo al soltar, para acortar el snap.
11518
+ */
11519
+ snapTo(breakpoint, animated, fromProgress, velocityPxMs = 0) {
11520
+ this.cancelPendingClose();
11521
+ this.cancelFrame();
11522
+ const measured = this.measure();
11523
+ const from = fromProgress ?? this.restProgress();
11524
+ const distance = measured ? Math.abs(this.yFor(breakpoint) - this.yFor(from)) : 0;
11525
+ const duration = animated ? this.snapDuration(distance, velocityPxMs) : 0;
11526
+ /* Todo en el mismo tick: sacar la clase que apaga la transición, fijar la
11527
+ duración y escribir el destino. El recálculo de estilo ve las tres
11528
+ cosas juntas y la transición arranca con la duración nueva. */
11529
+ this.setDraggingClasses(false);
11530
+ this.setTransitionDuration(duration);
11531
+ this.writeTranslate(breakpoint);
11532
+ this.writeBackdropOpacity(breakpoint);
11533
+ this.restProgress.set(breakpoint);
11239
11534
  if (breakpoint === 0) {
11240
- /* Esperar la transición antes de emit close para que el sheet se vea
11535
+ /* Emitir close cuando termina la transición (transitionend del
11536
+ translate) con fallback por timeout, para que el sheet se vea
11241
11537
  deslizando hacia abajo. Si !animated saltamos directo. */
11242
- const wait = animated ? 350 : 0;
11243
- setTimeout(() => {
11244
- this.currentBreakpoint.set(0);
11245
- this.open.set(false);
11246
- }, wait);
11538
+ this.scheduleClose(duration);
11247
11539
  return;
11248
11540
  }
11249
11541
  if (this.currentBreakpoint() !== breakpoint) {
@@ -11251,9 +11543,53 @@ class SuiModalSheet {
11251
11543
  this.breakpointChange.emit(breakpoint);
11252
11544
  }
11253
11545
  }
11254
- findClosestBreakpoint(progress) {
11546
+ scheduleClose(durationMs) {
11547
+ const finish = () => {
11548
+ this.cancelPendingClose();
11549
+ this.currentBreakpoint.set(0);
11550
+ this.open.set(false);
11551
+ };
11552
+ const panel = this.panelRef?.nativeElement;
11553
+ if (durationMs > 0 && panel) {
11554
+ this.closeTransitionHandler = (e) => {
11555
+ if (e.target === panel && e.propertyName === 'translate')
11556
+ finish();
11557
+ };
11558
+ panel.addEventListener('transitionend', this.closeTransitionHandler);
11559
+ }
11560
+ this.closeTimer = setTimeout(finish, durationMs > 0 ? durationMs + 80 : 0);
11561
+ }
11562
+ cancelPendingClose() {
11563
+ if (this.closeTimer !== null) {
11564
+ clearTimeout(this.closeTimer);
11565
+ this.closeTimer = null;
11566
+ }
11567
+ if (this.closeTransitionHandler) {
11568
+ this.panelRef?.nativeElement.removeEventListener('transitionend', this.closeTransitionHandler);
11569
+ this.closeTransitionHandler = undefined;
11570
+ }
11571
+ }
11572
+ /** Breakpoint cuyo desplazamiento (`yFor`) queda más cerca de `y`. Varios
11573
+ breakpoints pueden compartir el mismo y (todos los que superan el alto
11574
+ del contenido valen 0): en ese empate gana el actual si está entre
11575
+ ellos, si no el mayor — así un toque-arrastre al máximo no cambia de
11576
+ breakpoint ni apaga el scroll del body. */
11577
+ closestBreakpointByY(y) {
11255
11578
  const bps = this.breakpoints();
11256
- return bps.reduce((closest, bp) => Math.abs(bp - progress) < Math.abs(closest - progress) ? bp : closest);
11579
+ const current = this.currentBreakpoint();
11580
+ let best = bps[0] ?? 0;
11581
+ let bestDist = Infinity;
11582
+ for (const bp of bps) {
11583
+ const d = Math.abs(this.yFor(bp) - y);
11584
+ if (d < bestDist - 0.5) {
11585
+ best = bp;
11586
+ bestDist = d;
11587
+ }
11588
+ else if (Math.abs(d - bestDist) <= 0.5 && (bp === current || (best !== current && bp > best))) {
11589
+ best = bp;
11590
+ }
11591
+ }
11592
+ return best;
11257
11593
  }
11258
11594
  // ── Backdrop ──────────────────────────────────────────────────────────────
11259
11595
  /** Fórmula linear entre (backdropBreakpoint, 0) y (1, 1). Igual que Ionic. */
@@ -11297,16 +11633,22 @@ class SuiModalSheet {
11297
11633
  }
11298
11634
  }
11299
11635
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiModalSheet, deps: [], target: i0.ɵɵFactoryTarget.Component });
11300
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiModalSheet, isStandalone: true, selector: "sui-modal-sheet", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, breakpoints: { classPropertyName: "breakpoints", publicName: "breakpoints", isSignal: true, isRequired: false, transformFunction: null }, initialBreakpoint: { classPropertyName: "initialBreakpoint", publicName: "initialBreakpoint", isSignal: true, isRequired: false, transformFunction: null }, backdropBreakpoint: { classPropertyName: "backdropBreakpoint", publicName: "backdropBreakpoint", isSignal: true, isRequired: false, transformFunction: null }, showHandle: { classPropertyName: "showHandle", publicName: "showHandle", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, fullBody: { classPropertyName: "fullBody", publicName: "fullBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", closed: "closed", breakpointChange: "breakpointChange" }, host: { properties: { "attr.data-sui-sheet-open": "open() ? \"\" : null" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true }, { propertyName: "handleRef", first: true, predicate: ["handle"], descendants: true }, { propertyName: "bodyRef", first: true, predicate: ["body"], descendants: true }], ngImport: i0, template: "@if (open()) {\n <!-- Backdrop con opacity din\u00E1mica.\n pointer-events: none cuando current \u2264 backdropBreakpoint para dejar\n interactivo el contenido debajo (ej. mapa). -->\n <div\n class=\"sui-sheet__backdrop\"\n [style.opacity]=\"backdropOpacity()\"\n [style.pointer-events]=\"backdropInteractive() ? 'auto' : 'none'\"\n (click)=\"onBackdropClick()\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Sheet container \u2014 anclado al bottom, altura din\u00E1mica.\n Usar `height` en vez de transform para que el \u00E1rea \"no cubierta\" del\n viewport (donde se ve el mapa) NO sea parte del DOM del sheet \u2014\n contenido de fondo autom\u00E1ticamente interactivo, scroll del body\n respeta la altura visible (no fantasma). -->\n <div\n #container\n class=\"sui-sheet\"\n role=\"dialog\"\n aria-modal=\"true\"\n [class.sui-sheet--dragging]=\"dragging()\"\n [style.max-height]=\"heightCss()\"\n [style.--sheet-progress]=\"liveProgress()\"\n >\n @if (showHandle()) {\n <!-- Drag handle (pill). Solo este elemento captura los pointer events\n del drag \u2014 el resto del sheet permite scroll/clicks normales. -->\n <div\n #handle\n class=\"sui-sheet__handle\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <div class=\"sui-sheet__handle-pill\"></div>\n </div>\n }\n\n <!-- Body con scroll interno. Consumer proyecta su contenido aqu\u00ED.\n Acepta drag con patr\u00F3n scroll-then-drag (iOS canon):\n - Si el body est\u00E1 scrolleado (scrollTop > 0), el drag se ignora y\n el touch hace scroll normal.\n - Si est\u00E1 en top (scrollTop === 0) y el user arrastra hacia abajo,\n se inicia drag del sheet.\n - Si est\u00E1 en max breakpoint y user arrastra hacia abajo, se inicia\n drag (incluso con scrollTop === 0 ya cubre eso).\n - Drag hacia arriba siempre permite scroll del body (no roba el gesto). -->\n <div\n #body\n class=\"sui-sheet__body\"\n [class.sui-sheet__body--full]=\"fullBody()\"\n [class.sui-sheet__body--scrollable]=\"atMaxBreakpoint()\"\n (pointerdown)=\"onBodyPointerDown($event)\"\n (pointermove)=\"onBodyPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <ng-content />\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-sheet__backdrop{position:fixed;inset:0;z-index:1000;background-color:#3333333d;transition:opacity .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging~.sui-sheet__backdrop,:host([data-sui-sheet-open]) .sui-sheet--dragging+.sui-sheet__backdrop{transition:none}.sui-sheet{position:fixed;bottom:8px;left:8px;right:8px;z-index:1001;display:flex;flex-direction:column;box-sizing:border-box;height:max-content;background:var(--sui-bg-white-0, #ffffff);border-radius:36px 36px 54px 54px;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet{--sq-t: 45px;--sq-b: 68px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to calc(100% - var(--sq-b)),curve to calc(100% - var(--sq-b)) 100% with 100% 100%/100% 100%,hline to var(--sq-b),curve to 0 calc(100% - var(--sq-b)) with 0 100%/0 100%,close);box-shadow:none!important;filter:none}}.sui-sheet{box-shadow:none;overflow:hidden;overscroll-behavior:contain;will-change:max-height;transition:max-height .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging{transition:none}:host-context(html.platform-android) .sui-sheet{border-radius:var(--sui-radius-20, 20px);--sq-t: 25px;--sq-b: 25px}.sui-sheet__handle{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:12px 0 8px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}.sui-sheet__handle:active{cursor:grabbing}.sui-sheet__handle-pill{width:36px;height:5px;border-radius:999px;background:var(--sui-bg-soft-200, #d4d4d8)}.sui-sheet__body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:none;padding:0 20px 20px}.sui-sheet__body--scrollable{touch-action:pan-y;overscroll-behavior-y:contain}.sui-sheet__body--full{padding:0}@media(max-width:767px){.sui-sheet__body{scrollbar-width:none}.sui-sheet__body::-webkit-scrollbar{display:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11636
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiModalSheet, isStandalone: true, selector: "sui-modal-sheet", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, breakpoints: { classPropertyName: "breakpoints", publicName: "breakpoints", isSignal: true, isRequired: false, transformFunction: null }, initialBreakpoint: { classPropertyName: "initialBreakpoint", publicName: "initialBreakpoint", isSignal: true, isRequired: false, transformFunction: null }, backdropBreakpoint: { classPropertyName: "backdropBreakpoint", publicName: "backdropBreakpoint", isSignal: true, isRequired: false, transformFunction: null }, showHandle: { classPropertyName: "showHandle", publicName: "showHandle", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, fullBody: { classPropertyName: "fullBody", publicName: "fullBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", closed: "closed", breakpointChange: "breakpointChange" }, host: { properties: { "attr.data-sui-sheet-open": "open() ? \"\" : null" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true }, { propertyName: "panelRef", first: true, predicate: ["panel"], descendants: true }, { propertyName: "backdropRef", first: true, predicate: ["backdrop"], descendants: true }, { propertyName: "handleRef", first: true, predicate: ["handle"], descendants: true }, { propertyName: "bodyRef", first: true, predicate: ["body"], descendants: true }], ngImport: i0, template: "@if (open()) {\n <!-- Backdrop. Su opacidad la escribe el componente directo en el DOM (en\n reposo y por frame durante el drag), no un binding: as\u00ED el drag no\n dispara change detection. pointer-events: none cuando current \u2264\n backdropBreakpoint para dejar interactivo el contenido debajo (ej. mapa). -->\n <div\n #backdrop\n class=\"sui-sheet__backdrop\"\n [style.pointer-events]=\"backdropInteractive() ? 'auto' : 'none'\"\n (click)=\"onBackdropClick()\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Marco del sheet \u2014 alto FIJO (contenido acotado por el breakpoint m\u00E1ximo,\n `max-height` est\u00E1tico) anclado al bottom. No se mueve ni captura\n toques: recorta (radius/squircle) al panel de adentro, que es el que se\n traslada. El \u00E1rea del marco que el panel deja libre es transparente y\n deja pasar los toques al contenido de fondo (mapa interactivo). -->\n <div\n #container\n class=\"sui-sheet\"\n role=\"dialog\"\n aria-modal=\"true\"\n [style.max-height]=\"maxHeightCss()\"\n [style.--sheet-progress]=\"progress()\"\n >\n <!-- Panel \u2014 lo \u00FAnico que se mueve, con `translate` (compositor) escrito\n imperativamente por el componente (en reposo y por frame en el drag). -->\n <div #panel class=\"sui-sheet__panel\">\n @if (showHandle()) {\n <!-- Drag handle (pill). Solo este elemento captura los pointer events\n del drag \u2014 el resto del sheet permite scroll/clicks normales. -->\n <div\n #handle\n class=\"sui-sheet__handle\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <div class=\"sui-sheet__handle-pill\"></div>\n </div>\n }\n\n <!-- Body con scroll interno. Consumer proyecta su contenido aqu\u00ED.\n Acepta drag con patr\u00F3n scroll-then-drag (iOS canon):\n - Si el body est\u00E1 scrolleado (scrollTop > 0), el drag se ignora y\n el touch hace scroll normal.\n - Si est\u00E1 en top (scrollTop === 0) y el user arrastra hacia abajo,\n se inicia drag del sheet.\n - Si est\u00E1 en max breakpoint y user arrastra hacia abajo, se inicia\n drag (incluso con scrollTop === 0 ya cubre eso).\n - Drag hacia arriba siempre permite scroll del body (no roba el gesto). -->\n <div\n #body\n class=\"sui-sheet__body\"\n [class.sui-sheet__body--full]=\"fullBody()\"\n [class.sui-sheet__body--scrollable]=\"atMaxBreakpoint()\"\n (pointerdown)=\"onBodyPointerDown($event)\"\n (pointermove)=\"onBodyPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <ng-content />\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-sheet__backdrop{position:fixed;inset:0;z-index:1000;background-color:#3333333d;opacity:0;will-change:opacity;transition-property:opacity;transition-duration:.35s;transition-timing-function:cubic-bezier(.32,.72,0,1)}.sui-sheet__backdrop--dragging{transition:none}.sui-sheet{position:fixed;bottom:8px;left:8px;right:8px;z-index:1001;display:flex;flex-direction:column;box-sizing:border-box;height:max-content;pointer-events:none;border-radius:36px 36px 54px 54px;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet{--sq-t: 45px;--sq-b: 68px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to calc(100% - var(--sq-b)),curve to calc(100% - var(--sq-b)) 100% with 100% 100%/100% 100%,hline to var(--sq-b),curve to 0 calc(100% - var(--sq-b)) with 0 100%/0 100%,close);box-shadow:none!important;filter:none}}.sui-sheet{box-shadow:none;overflow:hidden;contain:layout paint}:host-context(html.platform-android) .sui-sheet{border-radius:var(--sui-radius-20, 20px);--sq-t: 25px;--sq-b: 25px}.sui-sheet__panel{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;box-sizing:border-box;pointer-events:auto;background:var(--sui-bg-white-0, #ffffff);border-radius:36px 36px 0 0;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet__panel{--sq-t: 45px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to 100%,hline to 0,close)}}.sui-sheet__panel{overflow:hidden;overscroll-behavior:contain;translate:0 100%;will-change:transform,translate;transition-property:translate;transition-duration:.35s;transition-timing-function:cubic-bezier(.32,.72,0,1)}.sui-sheet__panel--dragging{transition:none}:host-context(html.platform-android) .sui-sheet__panel{border-radius:var(--sui-radius-20, 20px) var(--sui-radius-20, 20px) 0 0;--sq-t: 25px}.sui-sheet__handle{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:12px 0 8px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}.sui-sheet__handle:active{cursor:grabbing}.sui-sheet__handle-pill{width:36px;height:5px;border-radius:999px;background:var(--sui-bg-soft-200, #d4d4d8)}.sui-sheet__body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:none;padding:0 20px 20px}.sui-sheet__body--scrollable{touch-action:pan-y;overscroll-behavior-y:contain}.sui-sheet__body--full{padding:0}@media(max-width:767px){.sui-sheet__body{scrollbar-width:none}.sui-sheet__body::-webkit-scrollbar{display:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11301
11637
  }
11302
11638
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiModalSheet, decorators: [{
11303
11639
  type: Component,
11304
11640
  args: [{ selector: 'sui-modal-sheet', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, host: {
11305
11641
  '[attr.data-sui-sheet-open]': 'open() ? "" : null',
11306
- }, template: "@if (open()) {\n <!-- Backdrop con opacity din\u00E1mica.\n pointer-events: none cuando current \u2264 backdropBreakpoint para dejar\n interactivo el contenido debajo (ej. mapa). -->\n <div\n class=\"sui-sheet__backdrop\"\n [style.opacity]=\"backdropOpacity()\"\n [style.pointer-events]=\"backdropInteractive() ? 'auto' : 'none'\"\n (click)=\"onBackdropClick()\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Sheet container \u2014 anclado al bottom, altura din\u00E1mica.\n Usar `height` en vez de transform para que el \u00E1rea \"no cubierta\" del\n viewport (donde se ve el mapa) NO sea parte del DOM del sheet \u2014\n contenido de fondo autom\u00E1ticamente interactivo, scroll del body\n respeta la altura visible (no fantasma). -->\n <div\n #container\n class=\"sui-sheet\"\n role=\"dialog\"\n aria-modal=\"true\"\n [class.sui-sheet--dragging]=\"dragging()\"\n [style.max-height]=\"heightCss()\"\n [style.--sheet-progress]=\"liveProgress()\"\n >\n @if (showHandle()) {\n <!-- Drag handle (pill). Solo este elemento captura los pointer events\n del drag \u2014 el resto del sheet permite scroll/clicks normales. -->\n <div\n #handle\n class=\"sui-sheet__handle\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <div class=\"sui-sheet__handle-pill\"></div>\n </div>\n }\n\n <!-- Body con scroll interno. Consumer proyecta su contenido aqu\u00ED.\n Acepta drag con patr\u00F3n scroll-then-drag (iOS canon):\n - Si el body est\u00E1 scrolleado (scrollTop > 0), el drag se ignora y\n el touch hace scroll normal.\n - Si est\u00E1 en top (scrollTop === 0) y el user arrastra hacia abajo,\n se inicia drag del sheet.\n - Si est\u00E1 en max breakpoint y user arrastra hacia abajo, se inicia\n drag (incluso con scrollTop === 0 ya cubre eso).\n - Drag hacia arriba siempre permite scroll del body (no roba el gesto). -->\n <div\n #body\n class=\"sui-sheet__body\"\n [class.sui-sheet__body--full]=\"fullBody()\"\n [class.sui-sheet__body--scrollable]=\"atMaxBreakpoint()\"\n (pointerdown)=\"onBodyPointerDown($event)\"\n (pointermove)=\"onBodyPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <ng-content />\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-sheet__backdrop{position:fixed;inset:0;z-index:1000;background-color:#3333333d;transition:opacity .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging~.sui-sheet__backdrop,:host([data-sui-sheet-open]) .sui-sheet--dragging+.sui-sheet__backdrop{transition:none}.sui-sheet{position:fixed;bottom:8px;left:8px;right:8px;z-index:1001;display:flex;flex-direction:column;box-sizing:border-box;height:max-content;background:var(--sui-bg-white-0, #ffffff);border-radius:36px 36px 54px 54px;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet{--sq-t: 45px;--sq-b: 68px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to calc(100% - var(--sq-b)),curve to calc(100% - var(--sq-b)) 100% with 100% 100%/100% 100%,hline to var(--sq-b),curve to 0 calc(100% - var(--sq-b)) with 0 100%/0 100%,close);box-shadow:none!important;filter:none}}.sui-sheet{box-shadow:none;overflow:hidden;overscroll-behavior:contain;will-change:max-height;transition:max-height .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging{transition:none}:host-context(html.platform-android) .sui-sheet{border-radius:var(--sui-radius-20, 20px);--sq-t: 25px;--sq-b: 25px}.sui-sheet__handle{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:12px 0 8px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}.sui-sheet__handle:active{cursor:grabbing}.sui-sheet__handle-pill{width:36px;height:5px;border-radius:999px;background:var(--sui-bg-soft-200, #d4d4d8)}.sui-sheet__body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:none;padding:0 20px 20px}.sui-sheet__body--scrollable{touch-action:pan-y;overscroll-behavior-y:contain}.sui-sheet__body--full{padding:0}@media(max-width:767px){.sui-sheet__body{scrollbar-width:none}.sui-sheet__body::-webkit-scrollbar{display:none}}\n"] }]
11642
+ }, template: "@if (open()) {\n <!-- Backdrop. Su opacidad la escribe el componente directo en el DOM (en\n reposo y por frame durante el drag), no un binding: as\u00ED el drag no\n dispara change detection. pointer-events: none cuando current \u2264\n backdropBreakpoint para dejar interactivo el contenido debajo (ej. mapa). -->\n <div\n #backdrop\n class=\"sui-sheet__backdrop\"\n [style.pointer-events]=\"backdropInteractive() ? 'auto' : 'none'\"\n (click)=\"onBackdropClick()\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Marco del sheet \u2014 alto FIJO (contenido acotado por el breakpoint m\u00E1ximo,\n `max-height` est\u00E1tico) anclado al bottom. No se mueve ni captura\n toques: recorta (radius/squircle) al panel de adentro, que es el que se\n traslada. El \u00E1rea del marco que el panel deja libre es transparente y\n deja pasar los toques al contenido de fondo (mapa interactivo). -->\n <div\n #container\n class=\"sui-sheet\"\n role=\"dialog\"\n aria-modal=\"true\"\n [style.max-height]=\"maxHeightCss()\"\n [style.--sheet-progress]=\"progress()\"\n >\n <!-- Panel \u2014 lo \u00FAnico que se mueve, con `translate` (compositor) escrito\n imperativamente por el componente (en reposo y por frame en el drag). -->\n <div #panel class=\"sui-sheet__panel\">\n @if (showHandle()) {\n <!-- Drag handle (pill). Solo este elemento captura los pointer events\n del drag \u2014 el resto del sheet permite scroll/clicks normales. -->\n <div\n #handle\n class=\"sui-sheet__handle\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <div class=\"sui-sheet__handle-pill\"></div>\n </div>\n }\n\n <!-- Body con scroll interno. Consumer proyecta su contenido aqu\u00ED.\n Acepta drag con patr\u00F3n scroll-then-drag (iOS canon):\n - Si el body est\u00E1 scrolleado (scrollTop > 0), el drag se ignora y\n el touch hace scroll normal.\n - Si est\u00E1 en top (scrollTop === 0) y el user arrastra hacia abajo,\n se inicia drag del sheet.\n - Si est\u00E1 en max breakpoint y user arrastra hacia abajo, se inicia\n drag (incluso con scrollTop === 0 ya cubre eso).\n - Drag hacia arriba siempre permite scroll del body (no roba el gesto). -->\n <div\n #body\n class=\"sui-sheet__body\"\n [class.sui-sheet__body--full]=\"fullBody()\"\n [class.sui-sheet__body--scrollable]=\"atMaxBreakpoint()\"\n (pointerdown)=\"onBodyPointerDown($event)\"\n (pointermove)=\"onBodyPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <ng-content />\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-sheet__backdrop{position:fixed;inset:0;z-index:1000;background-color:#3333333d;opacity:0;will-change:opacity;transition-property:opacity;transition-duration:.35s;transition-timing-function:cubic-bezier(.32,.72,0,1)}.sui-sheet__backdrop--dragging{transition:none}.sui-sheet{position:fixed;bottom:8px;left:8px;right:8px;z-index:1001;display:flex;flex-direction:column;box-sizing:border-box;height:max-content;pointer-events:none;border-radius:36px 36px 54px 54px;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet{--sq-t: 45px;--sq-b: 68px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to calc(100% - var(--sq-b)),curve to calc(100% - var(--sq-b)) 100% with 100% 100%/100% 100%,hline to var(--sq-b),curve to 0 calc(100% - var(--sq-b)) with 0 100%/0 100%,close);box-shadow:none!important;filter:none}}.sui-sheet{box-shadow:none;overflow:hidden;contain:layout paint}:host-context(html.platform-android) .sui-sheet{border-radius:var(--sui-radius-20, 20px);--sq-t: 25px;--sq-b: 25px}.sui-sheet__panel{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;box-sizing:border-box;pointer-events:auto;background:var(--sui-bg-white-0, #ffffff);border-radius:36px 36px 0 0;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet__panel{--sq-t: 45px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to 100%,hline to 0,close)}}.sui-sheet__panel{overflow:hidden;overscroll-behavior:contain;translate:0 100%;will-change:transform,translate;transition-property:translate;transition-duration:.35s;transition-timing-function:cubic-bezier(.32,.72,0,1)}.sui-sheet__panel--dragging{transition:none}:host-context(html.platform-android) .sui-sheet__panel{border-radius:var(--sui-radius-20, 20px) var(--sui-radius-20, 20px) 0 0;--sq-t: 25px}.sui-sheet__handle{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:12px 0 8px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}.sui-sheet__handle:active{cursor:grabbing}.sui-sheet__handle-pill{width:36px;height:5px;border-radius:999px;background:var(--sui-bg-soft-200, #d4d4d8)}.sui-sheet__body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:none;padding:0 20px 20px}.sui-sheet__body--scrollable{touch-action:pan-y;overscroll-behavior-y:contain}.sui-sheet__body--full{padding:0}@media(max-width:767px){.sui-sheet__body{scrollbar-width:none}.sui-sheet__body::-webkit-scrollbar{display:none}}\n"] }]
11307
11643
  }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], breakpoints: [{ type: i0.Input, args: [{ isSignal: true, alias: "breakpoints", required: false }] }], initialBreakpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialBreakpoint", required: false }] }], backdropBreakpoint: [{ type: i0.Input, args: [{ isSignal: true, alias: "backdropBreakpoint", required: false }] }], showHandle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showHandle", required: false }] }], closeOnBackdrop: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnBackdrop", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], fullBody: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullBody", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], breakpointChange: [{ type: i0.Output, args: ["breakpointChange"] }], containerRef: [{
11308
11644
  type: ViewChild,
11309
11645
  args: ['container']
11646
+ }], panelRef: [{
11647
+ type: ViewChild,
11648
+ args: ['panel']
11649
+ }], backdropRef: [{
11650
+ type: ViewChild,
11651
+ args: ['backdrop']
11310
11652
  }], handleRef: [{
11311
11653
  type: ViewChild,
11312
11654
  args: ['handle']
@@ -14624,7 +14966,7 @@ class SuiSelect {
14624
14966
  useExisting: forwardRef(() => SuiSelect),
14625
14967
  multi: true,
14626
14968
  },
14627
- ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "_menu", first: true, predicate: SuiDropdownMenu, descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <sui-form-label\n [label]=\"label()!\"\n [sublabel]=\"sublabel()\"\n [required]=\"required()\"\n [tooltip]=\"tooltip()\"\n [size]=\"labelSize()\"\n class=\"sui-select__label-host\"\n (click)=\"toggleOpen()\"\n />\n}\n\n<div\n #triggerEl\n class=\"sui-select__trigger\"\n [class.sui-select__trigger--error]=\"error()\"\n [class.sui-select__trigger--disabled]=\"isDisabled()\"\n [class.sui-select__trigger--open]=\"isOpen()\"\n [class.sui-select__trigger--filled]=\"selectedLabel() !== null\"\n role=\"combobox\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.tabindex]=\"isDisabled() ? '-1' : '0'\"\n (click)=\"toggleOpen()\"\n>\n <!--\n Left decoration (Figma Select[1.1] Type variant). Prioridad:\n 1. slot proyectado [slot=leading] (custom total)\n 2. imageUrl (avatar/logo del filled state)\n 3. flag (type=country, SOLO con selecci\u00F3n hecha \u2014 vac\u00EDo muestra globo)\n 4. RemixIcon por type (leadingIcon=true) o custom (leadingIcon=string)\n Solo se renderea si leadingIcon est\u00E1 activo O hay imageUrl/flag.\n -->\n @if (showLeading()) {\n <span class=\"sui-select__leading\">\n <ng-content select=\"[slot=leading]\" />\n @if (showLeadingImage()) {\n @if (type() === 'avatar') {\n <sui-avatar size=\"xs\" [src]=\"imageUrl()\" />\n } @else {\n <img class=\"sui-select__leading-img\" [src]=\"imageUrl()\" alt=\"\" />\n }\n } @else if (type() === 'country' && flag() && selectedLabel() !== null) {\n <sui-flag class=\"sui-select__leading-flag\" [name]=\"flag()!\" size=\"md\" />\n } @else {\n <sui-icon class=\"sui-select__leading-icon\" [name]=\"leadingIconName()\" [size]=\"20\" />\n }\n </span>\n }\n\n <span class=\"sui-select__value\">\n @if (selectedLabel()) {\n {{ selectedLabel() }}\n } @else {\n <span class=\"sui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n\n <!-- Badge inline opcional (Figma: entre value y chevron). sui-badge real \u2014\n defaults orange/lighter/medium replican el chip del Figma (brand naranja). -->\n @if (badgeCfg(); as bcfg) {\n <sui-badge\n class=\"sui-select__badge\"\n [color]=\"bcfg.color ?? 'orange'\"\n [variant]=\"bcfg.variant ?? 'lighter'\"\n [size]=\"bcfg.size ?? 'medium'\"\n >{{ bcfg.label }}</sui-badge>\n }\n\n <!-- Figma: arrow-down-s-line at 20\u00D720 (size-[20px]) \u2014 verified nodeId 270:1091 -->\n <sui-icon\n class=\"sui-select__chevron\"\n name=\"arrow-down-s-line\"\n [size]=\"20\"\n aria-hidden=\"true\"\n />\n</div>\n\n@if (error() ? errorMessage() : hint()) {\n <sui-form-hint\n [message]=\"error() ? errorMessage() : hint()\"\n [variant]=\"error() ? 'error' : 'neutral'\"\n class=\"sui-select__hint-host\"\n />\n}\n\n<!--\n Overlay menu \u2014 delegado a sui-dropdown-menu via [origin]=triggerEl.\n El sui-dropdown-menu encapsula CDK Overlay, positioning, backdrop,\n ResizeObserver y detachments. El trigger lo maneja este componente.\n-->\n<sui-dropdown-menu\n [origin]=\"triggerEl\"\n [disabled]=\"isDisabled()\"\n [matchWidth]=\"true\"\n panelClass=\"sui-select__overlay-pane\"\n (openedChange)=\"onMenuOpenedChange($event)\"\n>\n <ng-template suiDropdownPanel>\n <div\n class=\"sui-select__panel\"\n [class.sui-select__panel--xsmall]=\"size() === 'xsmall'\"\n [class.sui-select__panel--small]=\"size() === 'small'\"\n [class.sui-select__panel--medium]=\"size() === 'medium'\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || placeholder()\"\n >\n @for (option of options(); track option.value; let i = $index) {\n <sui-dropdown-item\n mode=\"option\"\n [label]=\"option.label\"\n [selected]=\"option.value === value()\"\n [highlighted]=\"highlightedIndex() === i\"\n [disabled]=\"!!option.disabled\"\n (clicked)=\"select(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n />\n }\n </div>\n </ng-template>\n</sui-dropdown-menu>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--sui-font-sans)}.sui-select__label-host{display:block;margin-bottom:4px;cursor:default}.sui-select__trigger{display:flex;align-items:center;max-width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);cursor:pointer;-webkit-user-select:none;user-select:none;transition:border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),box-shadow var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-size=xsmall]) .sui-select__trigger{gap:6px;padding:5px 6px 5px 8px;border-radius:var(--sui-radius-8);min-height:32px}:host([data-sui-size=small]) .sui-select__trigger{gap:8px;padding:7px 8px 7px 10px;border-radius:var(--sui-radius-8);min-height:36px}:host([data-sui-size=medium]) .sui-select__trigger,:host(:not([data-sui-size])) .sui-select__trigger{gap:8px;padding:9px 10px 9px 12px;border-radius:var(--sui-radius-10);min-height:40px}:host([data-sui-size=large]) .sui-select__trigger{gap:10px;padding:11px 12px 11px 14px;border-radius:var(--sui-radius-12);min-height:48px}:host([data-sui-size=xlarge]) .sui-select__trigger{gap:10px;padding:13px 14px 13px 16px;border-radius:var(--sui-radius-12);min-height:52px}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):hover{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):focus,.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error).sui-select__trigger--open{outline:none;border-color:var(--sui-stroke-strong-950);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-slate-alpha-16)}.sui-select__trigger--error{border-color:var(--sui-state-error-base);box-shadow:none}.sui-select__trigger--error:not(.sui-select__trigger--disabled):hover{border-color:var(--sui-state-error-base)}.sui-select__trigger--error:not(.sui-select__trigger--disabled):focus,.sui-select__trigger--error:not(.sui-select__trigger--disabled).sui-select__trigger--open{border-color:var(--sui-state-error-base);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-red-alpha-16)}.sui-select__trigger--disabled{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none;cursor:not-allowed;pointer-events:none}.sui-select__leading{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600)}:host([data-sui-disabled]) .sui-select__leading{color:var(--sui-icon-disabled-300);opacity:.48}.sui-select__leading-icon{display:inline-flex}.sui-select__leading-img{width:100%;height:100%;object-fit:cover;border-radius:var(--sui-radius-full)}.sui-select__leading-flag,.sui-select__badge{flex-shrink:0}:host([data-sui-disabled]) .sui-select__badge{opacity:.48}.sui-select__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}:host([data-sui-disabled]) .sui-select__value{color:var(--sui-text-disabled-300)}.sui-select__placeholder{color:var(--sui-text-sub-600)}:host([data-sui-disabled]) .sui-select__placeholder{color:var(--sui-text-disabled-300)}.sui-select__chevron{flex-shrink:0;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-select__chevron{transform:rotate(180deg)}:host([data-sui-disabled]) .sui-select__chevron{color:var(--sui-icon-disabled-300)}.sui-select__hint-host{display:block;margin-top:4px}\n"], dependencies: [{ kind: "component", type: SuiFormLabel, selector: "sui-form-label", inputs: ["label", "sublabel", "required", "tooltip", "link", "size", "disabled", "for"], outputs: ["linkClick"] }, { kind: "component", type: SuiFormHint, selector: "sui-form-hint", inputs: ["message", "variant", "icon"] }, { kind: "component", type: SuiDropdownMenu, selector: "sui-dropdown-menu", inputs: ["matchWidth", "flexibleDimensions", "push", "minWidth", "position", "viewportMargin", "panelClass", "disabled", "popupRole", "origin"], outputs: ["openedChange"], exportAs: ["suiDropdownMenu"] }, { kind: "directive", type: SuiDropdownPanel, selector: "ng-template[suiDropdownPanel]" }, { kind: "component", type: SuiDropdownItem, selector: "sui-dropdown-item", inputs: ["label", "sublabel", "description", "size", "leadingFramed", "mode", "selected", "highlighted", "disabled", "shortcut"], outputs: ["clicked"] }, { kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "component", type: SuiFlag, selector: "sui-flag", inputs: ["name", "size", "ariaLabel"] }, { kind: "component", type: SuiAvatar, selector: "sui-avatar", inputs: ["size", "src", "alt", "initials", "color", "status", "memojiSrc", "illustrationSrc", "icon", "companyLogoSrc", "topBadge", "bgColor"] }, { kind: "component", type: SuiBadge, selector: "sui-badge", inputs: ["color", "variant", "size", "type", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
14969
+ ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "_menu", first: true, predicate: SuiDropdownMenu, descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <sui-form-label\n [label]=\"label()!\"\n [sublabel]=\"sublabel()\"\n [required]=\"required()\"\n [tooltip]=\"tooltip()\"\n [size]=\"labelSize()\"\n class=\"sui-select__label-host\"\n (click)=\"toggleOpen()\"\n />\n}\n\n<div\n #triggerEl\n class=\"sui-select__trigger\"\n [class.sui-select__trigger--error]=\"error()\"\n [class.sui-select__trigger--disabled]=\"isDisabled()\"\n [class.sui-select__trigger--open]=\"isOpen()\"\n [class.sui-select__trigger--filled]=\"selectedLabel() !== null\"\n role=\"combobox\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.tabindex]=\"isDisabled() ? '-1' : '0'\"\n (click)=\"toggleOpen()\"\n>\n <!--\n Left decoration (Figma Select[1.1] Type variant). Prioridad:\n 1. slot proyectado [slot=leading] (custom total)\n 2. imageUrl (avatar/logo del filled state)\n 3. flag (type=country, SOLO con selecci\u00F3n hecha \u2014 vac\u00EDo muestra globo)\n 4. RemixIcon por type (leadingIcon=true) o custom (leadingIcon=string)\n Solo se renderea si leadingIcon est\u00E1 activo O hay imageUrl/flag.\n -->\n @if (showLeading()) {\n <span class=\"sui-select__leading\">\n <ng-content select=\"[slot=leading]\" />\n @if (showLeadingImage()) {\n @if (type() === 'avatar') {\n <sui-avatar size=\"xs\" [src]=\"imageUrl()\" />\n } @else {\n <img class=\"sui-select__leading-img\" [src]=\"imageUrl()\" alt=\"\" />\n }\n } @else if (type() === 'country' && flag() && selectedLabel() !== null) {\n <sui-flag class=\"sui-select__leading-flag\" [name]=\"flag()!\" size=\"md\" />\n } @else {\n <sui-icon class=\"sui-select__leading-icon\" [name]=\"leadingIconName()\" [size]=\"20\" />\n }\n </span>\n }\n\n <span class=\"sui-select__value\">\n @if (selectedLabel()) {\n {{ selectedLabel() }}\n } @else {\n <span class=\"sui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n\n <!-- Badge inline opcional (Figma: entre value y chevron). sui-badge real \u2014\n defaults orange/lighter/medium replican el chip del Figma (brand naranja). -->\n @if (badgeCfg(); as bcfg) {\n <sui-badge\n class=\"sui-select__badge\"\n [color]=\"bcfg.color ?? 'orange'\"\n [variant]=\"bcfg.variant ?? 'lighter'\"\n [size]=\"bcfg.size ?? 'medium'\"\n >{{ bcfg.label }}</sui-badge>\n }\n\n <!-- Figma: arrow-down-s-line at 20\u00D720 (size-[20px]) \u2014 verified nodeId 270:1091 -->\n <sui-icon\n class=\"sui-select__chevron\"\n name=\"arrow-down-s-line\"\n [size]=\"20\"\n aria-hidden=\"true\"\n />\n</div>\n\n@if (error() ? errorMessage() : hint()) {\n <sui-form-hint\n [message]=\"error() ? errorMessage() : hint()\"\n [variant]=\"error() ? 'error' : 'neutral'\"\n class=\"sui-select__hint-host\"\n />\n}\n\n<!--\n Overlay menu \u2014 delegado a sui-dropdown-menu via [origin]=triggerEl.\n El sui-dropdown-menu encapsula CDK Overlay, positioning, backdrop,\n ResizeObserver y detachments. El trigger lo maneja este componente.\n-->\n<sui-dropdown-menu\n [origin]=\"triggerEl\"\n [disabled]=\"isDisabled()\"\n [matchWidth]=\"true\"\n panelClass=\"sui-select__overlay-pane\"\n (openedChange)=\"onMenuOpenedChange($event)\"\n>\n <ng-template suiDropdownPanel>\n <div\n class=\"sui-select__panel\"\n [class.sui-select__panel--xsmall]=\"size() === 'xsmall'\"\n [class.sui-select__panel--small]=\"size() === 'small'\"\n [class.sui-select__panel--medium]=\"size() === 'medium'\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || placeholder()\"\n >\n @for (option of options(); track option.value; let i = $index) {\n <sui-dropdown-item\n mode=\"option\"\n [label]=\"option.label\"\n [selected]=\"option.value === value()\"\n [highlighted]=\"highlightedIndex() === i\"\n [disabled]=\"!!option.disabled\"\n (clicked)=\"select(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n />\n }\n </div>\n </ng-template>\n</sui-dropdown-menu>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--sui-font-sans)}.sui-select__label-host{display:block;margin-bottom:4px;cursor:default}.sui-select__trigger{display:flex;align-items:center;max-width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);cursor:pointer;-webkit-user-select:none;user-select:none;transition:border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),box-shadow var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-size=xsmall]) .sui-select__trigger{gap:6px;padding:5px 6px 5px 8px;border-radius:var(--sui-radius-8);min-height:20px}:host([data-sui-size=small]) .sui-select__trigger{gap:8px;padding:7px 8px 7px 10px;border-radius:var(--sui-radius-8);min-height:20px}:host([data-sui-size=medium]) .sui-select__trigger,:host(:not([data-sui-size])) .sui-select__trigger{gap:8px;padding:9px 10px 9px 12px;border-radius:var(--sui-radius-10);min-height:20px}:host([data-sui-size=large]) .sui-select__trigger{gap:10px;padding:11px 12px 11px 14px;border-radius:var(--sui-radius-12);min-height:24px}:host([data-sui-size=xlarge]) .sui-select__trigger{gap:10px;padding:13px 14px 13px 16px;border-radius:var(--sui-radius-12);min-height:24px}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):hover{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):focus,.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error).sui-select__trigger--open{outline:none;border-color:var(--sui-stroke-strong-950);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-slate-alpha-16)}.sui-select__trigger--error{border-color:var(--sui-state-error-base);box-shadow:none}.sui-select__trigger--error:not(.sui-select__trigger--disabled):hover{border-color:var(--sui-state-error-base)}.sui-select__trigger--error:not(.sui-select__trigger--disabled):focus,.sui-select__trigger--error:not(.sui-select__trigger--disabled).sui-select__trigger--open{border-color:var(--sui-state-error-base);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-red-alpha-16)}.sui-select__trigger--disabled{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none;cursor:not-allowed;pointer-events:none}.sui-select__leading{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600)}:host([data-sui-disabled]) .sui-select__leading{color:var(--sui-icon-disabled-300);opacity:.48}.sui-select__leading-icon{display:inline-flex}.sui-select__leading-img{width:100%;height:100%;object-fit:cover;border-radius:var(--sui-radius-full)}.sui-select__leading-flag,.sui-select__badge{flex-shrink:0}:host([data-sui-disabled]) .sui-select__badge{opacity:.48}.sui-select__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}:host([data-sui-disabled]) .sui-select__value{color:var(--sui-text-disabled-300)}.sui-select__placeholder{color:var(--sui-text-sub-600)}:host([data-sui-disabled]) .sui-select__placeholder{color:var(--sui-text-disabled-300)}.sui-select__chevron{flex-shrink:0;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-select__chevron{transform:rotate(180deg)}:host([data-sui-disabled]) .sui-select__chevron{color:var(--sui-icon-disabled-300)}.sui-select__hint-host{display:block;margin-top:4px}\n"], dependencies: [{ kind: "component", type: SuiFormLabel, selector: "sui-form-label", inputs: ["label", "sublabel", "required", "tooltip", "link", "size", "disabled", "for"], outputs: ["linkClick"] }, { kind: "component", type: SuiFormHint, selector: "sui-form-hint", inputs: ["message", "variant", "icon"] }, { kind: "component", type: SuiDropdownMenu, selector: "sui-dropdown-menu", inputs: ["matchWidth", "flexibleDimensions", "push", "minWidth", "position", "viewportMargin", "panelClass", "disabled", "popupRole", "origin"], outputs: ["openedChange"], exportAs: ["suiDropdownMenu"] }, { kind: "directive", type: SuiDropdownPanel, selector: "ng-template[suiDropdownPanel]" }, { kind: "component", type: SuiDropdownItem, selector: "sui-dropdown-item", inputs: ["label", "sublabel", "description", "size", "leadingFramed", "mode", "selected", "highlighted", "disabled", "shortcut"], outputs: ["clicked"] }, { kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "component", type: SuiFlag, selector: "sui-flag", inputs: ["name", "size", "ariaLabel"] }, { kind: "component", type: SuiAvatar, selector: "sui-avatar", inputs: ["size", "src", "alt", "initials", "color", "status", "memojiSrc", "illustrationSrc", "icon", "companyLogoSrc", "topBadge", "bgColor"] }, { kind: "component", type: SuiBadge, selector: "sui-badge", inputs: ["color", "variant", "size", "type", "disabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
14628
14970
  }
14629
14971
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiSelect, decorators: [{
14630
14972
  type: Component,
@@ -14652,7 +14994,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
14652
14994
  '[attr.data-sui-error]': 'error() ? "" : null',
14653
14995
  '[attr.data-sui-disabled]': 'isDisabled() ? "" : null',
14654
14996
  '[attr.data-sui-open]': 'isOpen() ? "" : null',
14655
- }, template: "@if (label()) {\n <sui-form-label\n [label]=\"label()!\"\n [sublabel]=\"sublabel()\"\n [required]=\"required()\"\n [tooltip]=\"tooltip()\"\n [size]=\"labelSize()\"\n class=\"sui-select__label-host\"\n (click)=\"toggleOpen()\"\n />\n}\n\n<div\n #triggerEl\n class=\"sui-select__trigger\"\n [class.sui-select__trigger--error]=\"error()\"\n [class.sui-select__trigger--disabled]=\"isDisabled()\"\n [class.sui-select__trigger--open]=\"isOpen()\"\n [class.sui-select__trigger--filled]=\"selectedLabel() !== null\"\n role=\"combobox\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.tabindex]=\"isDisabled() ? '-1' : '0'\"\n (click)=\"toggleOpen()\"\n>\n <!--\n Left decoration (Figma Select[1.1] Type variant). Prioridad:\n 1. slot proyectado [slot=leading] (custom total)\n 2. imageUrl (avatar/logo del filled state)\n 3. flag (type=country, SOLO con selecci\u00F3n hecha \u2014 vac\u00EDo muestra globo)\n 4. RemixIcon por type (leadingIcon=true) o custom (leadingIcon=string)\n Solo se renderea si leadingIcon est\u00E1 activo O hay imageUrl/flag.\n -->\n @if (showLeading()) {\n <span class=\"sui-select__leading\">\n <ng-content select=\"[slot=leading]\" />\n @if (showLeadingImage()) {\n @if (type() === 'avatar') {\n <sui-avatar size=\"xs\" [src]=\"imageUrl()\" />\n } @else {\n <img class=\"sui-select__leading-img\" [src]=\"imageUrl()\" alt=\"\" />\n }\n } @else if (type() === 'country' && flag() && selectedLabel() !== null) {\n <sui-flag class=\"sui-select__leading-flag\" [name]=\"flag()!\" size=\"md\" />\n } @else {\n <sui-icon class=\"sui-select__leading-icon\" [name]=\"leadingIconName()\" [size]=\"20\" />\n }\n </span>\n }\n\n <span class=\"sui-select__value\">\n @if (selectedLabel()) {\n {{ selectedLabel() }}\n } @else {\n <span class=\"sui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n\n <!-- Badge inline opcional (Figma: entre value y chevron). sui-badge real \u2014\n defaults orange/lighter/medium replican el chip del Figma (brand naranja). -->\n @if (badgeCfg(); as bcfg) {\n <sui-badge\n class=\"sui-select__badge\"\n [color]=\"bcfg.color ?? 'orange'\"\n [variant]=\"bcfg.variant ?? 'lighter'\"\n [size]=\"bcfg.size ?? 'medium'\"\n >{{ bcfg.label }}</sui-badge>\n }\n\n <!-- Figma: arrow-down-s-line at 20\u00D720 (size-[20px]) \u2014 verified nodeId 270:1091 -->\n <sui-icon\n class=\"sui-select__chevron\"\n name=\"arrow-down-s-line\"\n [size]=\"20\"\n aria-hidden=\"true\"\n />\n</div>\n\n@if (error() ? errorMessage() : hint()) {\n <sui-form-hint\n [message]=\"error() ? errorMessage() : hint()\"\n [variant]=\"error() ? 'error' : 'neutral'\"\n class=\"sui-select__hint-host\"\n />\n}\n\n<!--\n Overlay menu \u2014 delegado a sui-dropdown-menu via [origin]=triggerEl.\n El sui-dropdown-menu encapsula CDK Overlay, positioning, backdrop,\n ResizeObserver y detachments. El trigger lo maneja este componente.\n-->\n<sui-dropdown-menu\n [origin]=\"triggerEl\"\n [disabled]=\"isDisabled()\"\n [matchWidth]=\"true\"\n panelClass=\"sui-select__overlay-pane\"\n (openedChange)=\"onMenuOpenedChange($event)\"\n>\n <ng-template suiDropdownPanel>\n <div\n class=\"sui-select__panel\"\n [class.sui-select__panel--xsmall]=\"size() === 'xsmall'\"\n [class.sui-select__panel--small]=\"size() === 'small'\"\n [class.sui-select__panel--medium]=\"size() === 'medium'\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || placeholder()\"\n >\n @for (option of options(); track option.value; let i = $index) {\n <sui-dropdown-item\n mode=\"option\"\n [label]=\"option.label\"\n [selected]=\"option.value === value()\"\n [highlighted]=\"highlightedIndex() === i\"\n [disabled]=\"!!option.disabled\"\n (clicked)=\"select(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n />\n }\n </div>\n </ng-template>\n</sui-dropdown-menu>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--sui-font-sans)}.sui-select__label-host{display:block;margin-bottom:4px;cursor:default}.sui-select__trigger{display:flex;align-items:center;max-width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);cursor:pointer;-webkit-user-select:none;user-select:none;transition:border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),box-shadow var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-size=xsmall]) .sui-select__trigger{gap:6px;padding:5px 6px 5px 8px;border-radius:var(--sui-radius-8);min-height:32px}:host([data-sui-size=small]) .sui-select__trigger{gap:8px;padding:7px 8px 7px 10px;border-radius:var(--sui-radius-8);min-height:36px}:host([data-sui-size=medium]) .sui-select__trigger,:host(:not([data-sui-size])) .sui-select__trigger{gap:8px;padding:9px 10px 9px 12px;border-radius:var(--sui-radius-10);min-height:40px}:host([data-sui-size=large]) .sui-select__trigger{gap:10px;padding:11px 12px 11px 14px;border-radius:var(--sui-radius-12);min-height:48px}:host([data-sui-size=xlarge]) .sui-select__trigger{gap:10px;padding:13px 14px 13px 16px;border-radius:var(--sui-radius-12);min-height:52px}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):hover{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):focus,.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error).sui-select__trigger--open{outline:none;border-color:var(--sui-stroke-strong-950);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-slate-alpha-16)}.sui-select__trigger--error{border-color:var(--sui-state-error-base);box-shadow:none}.sui-select__trigger--error:not(.sui-select__trigger--disabled):hover{border-color:var(--sui-state-error-base)}.sui-select__trigger--error:not(.sui-select__trigger--disabled):focus,.sui-select__trigger--error:not(.sui-select__trigger--disabled).sui-select__trigger--open{border-color:var(--sui-state-error-base);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-red-alpha-16)}.sui-select__trigger--disabled{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none;cursor:not-allowed;pointer-events:none}.sui-select__leading{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600)}:host([data-sui-disabled]) .sui-select__leading{color:var(--sui-icon-disabled-300);opacity:.48}.sui-select__leading-icon{display:inline-flex}.sui-select__leading-img{width:100%;height:100%;object-fit:cover;border-radius:var(--sui-radius-full)}.sui-select__leading-flag,.sui-select__badge{flex-shrink:0}:host([data-sui-disabled]) .sui-select__badge{opacity:.48}.sui-select__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}:host([data-sui-disabled]) .sui-select__value{color:var(--sui-text-disabled-300)}.sui-select__placeholder{color:var(--sui-text-sub-600)}:host([data-sui-disabled]) .sui-select__placeholder{color:var(--sui-text-disabled-300)}.sui-select__chevron{flex-shrink:0;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-select__chevron{transform:rotate(180deg)}:host([data-sui-disabled]) .sui-select__chevron{color:var(--sui-icon-disabled-300)}.sui-select__hint-host{display:block;margin-top:4px}\n"] }]
14997
+ }, template: "@if (label()) {\n <sui-form-label\n [label]=\"label()!\"\n [sublabel]=\"sublabel()\"\n [required]=\"required()\"\n [tooltip]=\"tooltip()\"\n [size]=\"labelSize()\"\n class=\"sui-select__label-host\"\n (click)=\"toggleOpen()\"\n />\n}\n\n<div\n #triggerEl\n class=\"sui-select__trigger\"\n [class.sui-select__trigger--error]=\"error()\"\n [class.sui-select__trigger--disabled]=\"isDisabled()\"\n [class.sui-select__trigger--open]=\"isOpen()\"\n [class.sui-select__trigger--filled]=\"selectedLabel() !== null\"\n role=\"combobox\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.tabindex]=\"isDisabled() ? '-1' : '0'\"\n (click)=\"toggleOpen()\"\n>\n <!--\n Left decoration (Figma Select[1.1] Type variant). Prioridad:\n 1. slot proyectado [slot=leading] (custom total)\n 2. imageUrl (avatar/logo del filled state)\n 3. flag (type=country, SOLO con selecci\u00F3n hecha \u2014 vac\u00EDo muestra globo)\n 4. RemixIcon por type (leadingIcon=true) o custom (leadingIcon=string)\n Solo se renderea si leadingIcon est\u00E1 activo O hay imageUrl/flag.\n -->\n @if (showLeading()) {\n <span class=\"sui-select__leading\">\n <ng-content select=\"[slot=leading]\" />\n @if (showLeadingImage()) {\n @if (type() === 'avatar') {\n <sui-avatar size=\"xs\" [src]=\"imageUrl()\" />\n } @else {\n <img class=\"sui-select__leading-img\" [src]=\"imageUrl()\" alt=\"\" />\n }\n } @else if (type() === 'country' && flag() && selectedLabel() !== null) {\n <sui-flag class=\"sui-select__leading-flag\" [name]=\"flag()!\" size=\"md\" />\n } @else {\n <sui-icon class=\"sui-select__leading-icon\" [name]=\"leadingIconName()\" [size]=\"20\" />\n }\n </span>\n }\n\n <span class=\"sui-select__value\">\n @if (selectedLabel()) {\n {{ selectedLabel() }}\n } @else {\n <span class=\"sui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n\n <!-- Badge inline opcional (Figma: entre value y chevron). sui-badge real \u2014\n defaults orange/lighter/medium replican el chip del Figma (brand naranja). -->\n @if (badgeCfg(); as bcfg) {\n <sui-badge\n class=\"sui-select__badge\"\n [color]=\"bcfg.color ?? 'orange'\"\n [variant]=\"bcfg.variant ?? 'lighter'\"\n [size]=\"bcfg.size ?? 'medium'\"\n >{{ bcfg.label }}</sui-badge>\n }\n\n <!-- Figma: arrow-down-s-line at 20\u00D720 (size-[20px]) \u2014 verified nodeId 270:1091 -->\n <sui-icon\n class=\"sui-select__chevron\"\n name=\"arrow-down-s-line\"\n [size]=\"20\"\n aria-hidden=\"true\"\n />\n</div>\n\n@if (error() ? errorMessage() : hint()) {\n <sui-form-hint\n [message]=\"error() ? errorMessage() : hint()\"\n [variant]=\"error() ? 'error' : 'neutral'\"\n class=\"sui-select__hint-host\"\n />\n}\n\n<!--\n Overlay menu \u2014 delegado a sui-dropdown-menu via [origin]=triggerEl.\n El sui-dropdown-menu encapsula CDK Overlay, positioning, backdrop,\n ResizeObserver y detachments. El trigger lo maneja este componente.\n-->\n<sui-dropdown-menu\n [origin]=\"triggerEl\"\n [disabled]=\"isDisabled()\"\n [matchWidth]=\"true\"\n panelClass=\"sui-select__overlay-pane\"\n (openedChange)=\"onMenuOpenedChange($event)\"\n>\n <ng-template suiDropdownPanel>\n <div\n class=\"sui-select__panel\"\n [class.sui-select__panel--xsmall]=\"size() === 'xsmall'\"\n [class.sui-select__panel--small]=\"size() === 'small'\"\n [class.sui-select__panel--medium]=\"size() === 'medium'\"\n role=\"listbox\"\n [attr.aria-label]=\"label() || placeholder()\"\n >\n @for (option of options(); track option.value; let i = $index) {\n <sui-dropdown-item\n mode=\"option\"\n [label]=\"option.label\"\n [selected]=\"option.value === value()\"\n [highlighted]=\"highlightedIndex() === i\"\n [disabled]=\"!!option.disabled\"\n (clicked)=\"select(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n />\n }\n </div>\n </ng-template>\n</sui-dropdown-menu>\n", styles: ["@charset \"UTF-8\";:host{display:block;font-family:var(--sui-font-sans)}.sui-select__label-host{display:block;margin-bottom:4px;cursor:default}.sui-select__trigger{display:flex;align-items:center;max-width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);cursor:pointer;-webkit-user-select:none;user-select:none;transition:border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),box-shadow var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-size=xsmall]) .sui-select__trigger{gap:6px;padding:5px 6px 5px 8px;border-radius:var(--sui-radius-8);min-height:20px}:host([data-sui-size=small]) .sui-select__trigger{gap:8px;padding:7px 8px 7px 10px;border-radius:var(--sui-radius-8);min-height:20px}:host([data-sui-size=medium]) .sui-select__trigger,:host(:not([data-sui-size])) .sui-select__trigger{gap:8px;padding:9px 10px 9px 12px;border-radius:var(--sui-radius-10);min-height:20px}:host([data-sui-size=large]) .sui-select__trigger{gap:10px;padding:11px 12px 11px 14px;border-radius:var(--sui-radius-12);min-height:24px}:host([data-sui-size=xlarge]) .sui-select__trigger{gap:10px;padding:13px 14px 13px 16px;border-radius:var(--sui-radius-12);min-height:24px}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):hover{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none}.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error):focus,.sui-select__trigger:not(.sui-select__trigger--disabled):not(.sui-select__trigger--error).sui-select__trigger--open{outline:none;border-color:var(--sui-stroke-strong-950);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-slate-alpha-16)}.sui-select__trigger--error{border-color:var(--sui-state-error-base);box-shadow:none}.sui-select__trigger--error:not(.sui-select__trigger--disabled):hover{border-color:var(--sui-state-error-base)}.sui-select__trigger--error:not(.sui-select__trigger--disabled):focus,.sui-select__trigger--error:not(.sui-select__trigger--disabled).sui-select__trigger--open{border-color:var(--sui-state-error-base);box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-red-alpha-16)}.sui-select__trigger--disabled{background:var(--sui-bg-weak-50);border-color:transparent;box-shadow:none;cursor:not-allowed;pointer-events:none}.sui-select__leading{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600)}:host([data-sui-disabled]) .sui-select__leading{color:var(--sui-icon-disabled-300);opacity:.48}.sui-select__leading-icon{display:inline-flex}.sui-select__leading-img{width:100%;height:100%;object-fit:cover;border-radius:var(--sui-radius-full)}.sui-select__leading-flag,.sui-select__badge{flex-shrink:0}:host([data-sui-disabled]) .sui-select__badge{opacity:.48}.sui-select__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}:host([data-sui-disabled]) .sui-select__value{color:var(--sui-text-disabled-300)}.sui-select__placeholder{color:var(--sui-text-sub-600)}:host([data-sui-disabled]) .sui-select__placeholder{color:var(--sui-text-disabled-300)}.sui-select__chevron{flex-shrink:0;width:var(--sui-icon-size-md);height:var(--sui-icon-size-md);color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-select__chevron{transform:rotate(180deg)}:host([data-sui-disabled]) .sui-select__chevron{color:var(--sui-icon-disabled-300)}.sui-select__hint-host{display:block;margin-top:4px}\n"] }]
14656
14998
  }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], leadingIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadingIcon", required: false }] }], flag: [{ type: i0.Input, args: [{ isSignal: true, alias: "flag", required: false }] }], imageUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageUrl", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], sublabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sublabel", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], tooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], triggerEl: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], _menu: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SuiDropdownMenu), { isSignal: true }] }], onKeydown: [{
14657
14999
  type: HostListener,
14658
15000
  args: ['keydown', ['$event']]
@@ -16826,7 +17168,7 @@ class SuiTable {
16826
17168
  return this.columns().map((_, i) => i);
16827
17169
  }
16828
17170
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
16829
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiTable, isStandalone: true, selector: "sui-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, selectedRows: { classPropertyName: "selectedRows", publicName: "selectedRows", isSignal: true, isRequired: false, transformFunction: null }, sortKey: { classPropertyName: "sortKey", publicName: "sortKey", isSignal: true, isRequired: false, transformFunction: null }, sortDir: { classPropertyName: "sortDir", publicName: "sortDir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedRows: "selectedRowsChange", sortKey: "sortKeyChange", sortDir: "sortDirChange", rowClicked: "rowClicked", sortChanged: "sortChanged" }, host: { properties: { "attr.data-sui-size": "size()", "attr.data-sui-striped": "striped() ? \"\" : null", "attr.data-sui-selectable": "selectable() ? \"\" : null", "attr.data-sui-loading": "loading() ? \"\" : null", "attr.data-sui-sticky": "hasStickyColumn() ? \"\" : null" } }, queries: [{ propertyName: "cellTemplates", predicate: SuiTableCellDirective }], viewQueries: [{ propertyName: "scrollEl", first: true, predicate: ["scrollEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \u2550\u2550 SUI Table \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<div class=\"sui-table\" #scrollEl>\n\n <!-- Header -->\n <div class=\"sui-table__header\">\n <!-- Checkbox header (selectable mode) \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__header-cell sui-table__header-cell--checkbox\">\n <sui-checkbox\n [checked]=\"allSelected\"\n [indeterminate]=\"partialSelected\"\n (checkedChange)=\"toggleAll()\"\n (click)=\"$event.stopPropagation()\"\n aria-label=\"Seleccionar todas las filas\"\n />\n </div>\n }\n\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__header-cell\"\n [class.sui-table__header-cell--sortable]=\"col.sortable && !col.disabled\"\n [class.sui-table__header-cell--sorted]=\"isSortActive(col.key)\"\n [class.sui-table__header-cell--disabled]=\"col.disabled\"\n [class.sui-table__header-cell--center]=\"col.align === 'center'\"\n [class.sui-table__header-cell--right]=\"col.align === 'right'\"\n [class.sui-table__header-cell--empty]=\"!col.label\"\n [class.sui-table__header-cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n (click)=\"!col.disabled && onSort(col)\"\n [attr.tabindex]=\"col.sortable && !col.disabled ? '0' : null\"\n [attr.role]=\"col.sortable ? 'columnheader' : null\"\n [attr.aria-disabled]=\"col.disabled ? 'true' : null\"\n [attr.aria-sort]=\"col.sortable ? (isSortActive(col.key) ? (sortDir() === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\n (keydown.enter)=\"!col.disabled && onSort(col)\"\n (keydown.space)=\"$event.preventDefault(); !col.disabled && onSort(col)\"\n >\n @if (col.label) {\n <span class=\"sui-table__header-label\">{{ col.label }}</span>\n }\n @if (col.sortable) {\n <span class=\"sui-table__sort-icon\" [class.sui-table__sort-icon--active]=\"isSortActive(col.key)\">\n @if (!isSortActive(col.key)) {\n <sui-icon name=\"expand-up-down-line\" [size]=\"20\" />\n } @else if (sortDir() === 'asc') {\n <sui-icon name=\"arrow-up-s-fill\" [size]=\"20\" />\n } @else {\n <sui-icon name=\"arrow-down-s-fill\" [size]=\"20\" />\n }\n </span>\n }\n </div>\n }\n </div>\n\n <!-- Body: Loading skeleton -->\n @if (loading()) {\n <div class=\"sui-table__body\">\n @for (sk of skeletonRows; track sk) {\n <div class=\"sui-table__row sui-table__row--skeleton\">\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\">\n <span class=\"sui-table__skeleton-box sui-table__skeleton-box--sm\"></span>\n </div>\n }\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <span class=\"sui-table__skeleton-box\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Body: Empty state -->\n @else if (rows().length === 0) {\n <div class=\"sui-table__empty\">\n <sui-icon name=\"inbox-line\" [size]=\"40\" class=\"sui-table__empty-icon\" />\n <p class=\"sui-table__empty-msg\">{{ emptyMessage() }}</p>\n </div>\n }\n\n <!-- Body: Data rows -->\n @else {\n <div class=\"sui-table__body\">\n @for (row of rows(); track getRowKey(row, $index); let i = $index) {\n <div\n class=\"sui-table__row\"\n [class.sui-table__row--selected]=\"selectedRows().has(getRowKey(row, i))\"\n [class.sui-table__row--striped]=\"striped() && i % 2 === 1\"\n (click)=\"rowClicked.emit(row)\"\n >\n <!-- Checkbox column \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\" (click)=\"$event.stopPropagation()\">\n <sui-checkbox\n [checked]=\"selectedRows().has(getRowKey(row, i))\"\n (checkedChange)=\"toggleRow(row, i)\"\n aria-label=\"Seleccionar fila\"\n />\n </div>\n }\n\n <!-- Data columns -->\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--center]=\"col.align === 'center'\"\n [class.sui-table__cell--right]=\"col.align === 'right'\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [class.sui-table__cell--leading]=\"cellPriority(col) === 'leading'\"\n [class.sui-table__cell--passive]=\"cellPriority(col) === 'passive'\"\n [class.sui-table__cell--none]=\"cellPriority(col) === 'none'\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <!-- Custom template via SuiTableCellDirective -->\n @if (getTemplate(col.key); as tmpl) {\n <ng-container *ngTemplateOutlet=\"tmpl.templateRef; context: { $implicit: row }\"></ng-container>\n } @else if (getCellDescription(row, col); as desc) {\n <!-- Texto + sub-texto (Figma Priority=Leading, 2da l\u00EDnea XSmall) -->\n <span class=\"sui-table__cell-block\">\n <span\n class=\"sui-table__cell-text\"\n [class.sui-table__cell-text--truncate]=\"col.truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n <span class=\"sui-table__cell-desc\">{{ desc }}</span>\n </span>\n } @else if (col.truncate) {\n <!-- Texto truncado + tooltip con el valor completo -->\n <span\n class=\"sui-table__cell-text sui-table__cell-text--truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n } @else {\n <!-- Default text rendering -->\n <span class=\"sui-table__cell-text\">{{ getCellValue(row, col.key) }}</span>\n }\n </div>\n }\n </div>\n\n <!-- Row divider (not after last row) -->\n @if (i < rows().length - 1) {\n <div class=\"sui-table__divider\"></div>\n }\n }\n </div>\n }\n\n</div>\n", styles: ["@charset \"UTF-8\";.mp-badge{display:inline-flex;align-items:center;height:24px;padding:0 10px;border-radius:6px;font-size:12px;font-weight:600;white-space:nowrap;border:1px solid transparent;line-height:1}.mp-badge--green{background:var(--admin-success-bg, #dcfce7);color:var(--admin-success, #16a34a)}.mp-badge--red{background:var(--admin-error-bg, #fee2e2);color:var(--admin-error, #ef4444)}.mp-badge--orange{background:#fff7ed;color:#c2410c;border-color:#fed7aa}.mp-badge--blue{background:var(--admin-info-bg, #dbeafe);color:#2563eb}.mp-badge--gray{background:var(--admin-bg-tertiary, #f3f4f6);color:var(--admin-text-tertiary, #6b7280)}.mp-badge--sm{height:20px;padding:0 8px;font-size:11px}.mp-action-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:30px;padding:0 12px;border-radius:6px;border:1px solid transparent;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;white-space:nowrap;transition:all .15s ease}.mp-action-btn:disabled{opacity:.5;cursor:not-allowed}.mp-action-btn--activate{background:var(--admin-success, #16a34a);color:#fff}.mp-action-btn--activate:hover{background:#15803d}.mp-action-btn--renew{background:var(--admin-info, #3b82f6);color:#fff}.mp-action-btn--renew:hover{background:#2563eb}.mp-action-btn--suspend{background:var(--admin-bg-primary, #fff);color:var(--admin-error, #ef4444);border-color:#fca5a5}.mp-action-btn--suspend:hover{background:var(--admin-error-bg, #fee2e2)}.mp-action-btn--danger{background:#dc2626;color:#fff;border:none}.mp-action-btn--danger:hover{background:#b91c1c}.mp-action-btn--outline{background:var(--admin-bg-primary, #fff);color:var(--admin-text-secondary, #374151);border-color:var(--admin-border-primary, #e5e7eb)}.mp-action-btn--outline:hover{background:var(--admin-bg-hover, #f9fafb)}.mp-action-btn--icon{width:28px;height:28px;padding:0;background:transparent;color:var(--admin-text-muted, #9ca3af);border:none}.mp-action-btn--icon:hover{background:var(--admin-bg-hover, #f9fafb);color:var(--admin-text-primary, #171717)}.mp-action-btn--icon-danger{width:28px;height:28px;padding:0;background:transparent;color:#dc2626;border:none}.mp-action-btn--icon-danger:hover{background:var(--admin-error-bg, #fee2e2);color:#dc2626}:host{display:block;width:100%}.sui-table{display:flex;flex-direction:column;width:100%;overflow:hidden;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0;font-optical-sizing:auto}:host([data-sui-sticky]) .sui-table__header,:host([data-sui-sticky]) .sui-table__row{overflow:visible}@media(max-width:767px){.sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none}}@media(max-width:767px)and (max-width:767px){.sui-table{scrollbar-width:none}.sui-table::-webkit-scrollbar{display:none;width:0;height:0}}@media(max-width:767px){.sui-table .sui-table__header,.sui-table .sui-table__body{min-width:max-content}.sui-table .sui-table__cell,.sui-table .sui-table__header-cell{min-width:120px}.sui-table .sui-table__cell--checkbox,.sui-table .sui-table__header-cell--checkbox{min-width:44px}.sui-table .sui-table__header-cell--empty{min-width:0}}:host([data-sui-sticky]) .sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none}@media(max-width:767px){:host([data-sui-sticky]) .sui-table{scrollbar-width:none}:host([data-sui-sticky]) .sui-table::-webkit-scrollbar{display:none;width:0;height:0}}:host([data-sui-sticky]) .sui-table .sui-table__header,:host([data-sui-sticky]) .sui-table .sui-table__body{min-width:max-content}:host([data-sui-sticky]) .sui-table .sui-table__cell,:host([data-sui-sticky]) .sui-table .sui-table__header-cell{min-width:120px}:host([data-sui-sticky]) .sui-table .sui-table__cell--checkbox,:host([data-sui-sticky]) .sui-table .sui-table__header-cell--checkbox{min-width:44px}:host([data-sui-sticky]) .sui-table .sui-table__header-cell--empty{min-width:0}.sui-table__header{display:flex;align-items:flex-start;background:var(--sui-bg-weak-50);border-radius:var(--sui-radius-8);overflow:hidden;min-height:36px;flex-shrink:0}.sui-table__header-cell{display:flex;align-items:center;gap:2px;padding:8px 12px;min-width:0;box-sizing:border-box;white-space:nowrap;overflow:hidden;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-sub-600)}.sui-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sui-table__header-cell--sortable:hover{color:var(--sui-text-strong-950)}.sui-table__header-cell--sortable:hover .sui-table__sort-icon{opacity:1}.sui-table__header-cell--sortable:focus-visible{outline:2px solid var(--sui-primary-alpha-10);outline-offset:-2px;border-radius:var(--sui-radius-4)}.sui-table__header-cell--sorted{color:var(--sui-text-strong-950)}.sui-table__header-cell--disabled{cursor:default;pointer-events:none;color:var(--sui-text-disabled-300)}.sui-table__header-cell--disabled .sui-table__sort-icon{color:var(--sui-text-disabled-300);opacity:1}.sui-table__header-cell--empty{flex-shrink:0;padding:0}.sui-table__header-cell--center{justify-content:center}.sui-table__header-cell--right{justify-content:flex-end}.sui-table__header-cell--checkbox{flex:0 0 44px;justify-content:center}.sui-table__header-cell--sticky{position:sticky;left:0;z-index:2;background:var(--sui-bg-weak-50)}.sui-table__header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.sui-table__sort-icon{display:inline-flex;align-items:center;flex-shrink:0;color:var(--sui-text-soft-400);opacity:.6;transition:opacity var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-table__sort-icon--active{color:var(--sui-text-strong-950);opacity:1}.sui-table__body{display:flex;flex-direction:column;width:100%}.sui-table__row{display:flex;align-items:center;width:100%;border-radius:var(--sui-radius-12);overflow:hidden;cursor:pointer;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);box-sizing:border-box}.sui-table__row:hover,.sui-table__row:hover .sui-table__cell,.sui-table__row:active,.sui-table__row:active .sui-table__cell{background:var(--sui-bg-weak-50)}.sui-table__row--selected{background:var(--sui-primary-alpha-10)}.sui-table__row--selected:hover{background:var(--sui-primary-alpha-16)}.sui-table__row--striped{background:var(--sui-bg-weak-50)}.sui-table__row--skeleton{pointer-events:none;cursor:default}.sui-table__row--skeleton:hover{background:transparent}.sui-table__row--skeleton:hover .sui-table__cell{background:var(--sui-bg-white-0)}:host([data-sui-size=medium]) .sui-table__cell{min-height:64px;padding:12px 20px 12px 12px}:host([data-sui-size=small]) .sui-table__cell{min-height:48px;padding:8px 16px 8px 12px}:host([data-sui-size=large]) .sui-table__cell{min-height:80px;padding:16px 20px 16px 12px}:host([data-sui-size=xlarge]) .sui-table__cell{min-height:96px;padding:20px 20px 20px 12px}.sui-table__cell{display:flex;align-items:center;gap:12px;min-width:0;overflow:hidden;box-sizing:border-box;background:var(--sui-bg-white-0);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}.sui-table__cell--center{justify-content:center}.sui-table__cell--right{justify-content:flex-end}.sui-table__cell--checkbox{flex:0 0 44px;justify-content:center;padding:0 12px}.sui-table__cell--leading{font-weight:var(--sui-type-label-sm-weight);color:var(--sui-text-strong-950)}.sui-table__cell--passive{color:var(--sui-text-sub-600);font-weight:var(--sui-type-paragraph-sm-weight)}.sui-table__cell--sticky{position:sticky;left:0;z-index:1;background:var(--sui-bg-white-0)}.sui-table__row--selected .sui-table__cell{background:transparent}.sui-table__row--selected .sui-table__cell.sui-table__cell--sticky{background:var(--sui-primary-alpha-10)}.sui-table__cell-text{min-width:0}.sui-table__cell-text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;display:block}.sui-table__cell-block{display:flex;flex-direction:column;min-width:0}.sui-table__cell-desc{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-xs-size);font-weight:var(--sui-type-paragraph-xs-weight);line-height:var(--sui-type-paragraph-xs-line);letter-spacing:var(--sui-type-paragraph-xs-spacing);color:var(--sui-text-sub-600)}.sui-table__cell--leading .sui-table__cell-text{font-weight:var(--sui-type-label-sm-weight)}.sui-table__cell--passive .sui-table__cell-text{font-weight:inherit;color:inherit}:host ::ng-deep .sui-table__leading-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:40px;height:40px;padding:10px;box-sizing:border-box;border-radius:var(--sui-radius-full);background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);color:var(--sui-text-sub-600)}:host([data-sui-size=small]) ::ng-deep .sui-table__leading-icon{width:32px;height:32px;padding:6px}.sui-table__divider{width:100%;padding:1.5px 0;flex-shrink:0;background:var(--sui-bg-white-0)}.sui-table__divider:after{content:\"\";display:block;height:1px;background:var(--sui-stroke-soft-200)}.sui-table__empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;gap:12px;text-align:center}.sui-table__empty-icon{color:var(--sui-text-disabled-300)}.sui-table__empty-msg{margin:0;font-size:var(--sui-type-paragraph-sm-size);line-height:var(--sui-type-paragraph-sm-line);color:var(--sui-text-sub-600)}.sui-table__skeleton-box{display:block;height:14px;width:100%;max-width:180px;border-radius:var(--sui-radius-4);background:linear-gradient(90deg,var(--sui-bg-soft-200) 25%,var(--sui-bg-weak-50) 50%,var(--sui-bg-soft-200) 75%);background-size:400% 100%;animation:sui-skeleton-pulse 1.4s ease-in-out infinite}.sui-table__skeleton-box--sm{width:20px;max-width:20px;height:20px;border-radius:var(--sui-radius-4)}@keyframes sui-skeleton-pulse{0%{background-position:100% 50%}to{background-position:0% 50%}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SuiCheckbox, selector: "sui-checkbox", inputs: ["size", "checked", "indeterminate", "disabled"], outputs: ["checkedChange"] }, { kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "directive", type: SuiTooltip, selector: "[suiTooltip], [suiTooltipLarge]", inputs: ["suiTooltip", "suiTooltipLarge", "position", "suiTooltipSize", "theme", "delay", "disabled", "showArrow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
17171
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiTable, isStandalone: true, selector: "sui-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, emptyMessage: { classPropertyName: "emptyMessage", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, rowKey: { classPropertyName: "rowKey", publicName: "rowKey", isSignal: true, isRequired: false, transformFunction: null }, selectedRows: { classPropertyName: "selectedRows", publicName: "selectedRows", isSignal: true, isRequired: false, transformFunction: null }, sortKey: { classPropertyName: "sortKey", publicName: "sortKey", isSignal: true, isRequired: false, transformFunction: null }, sortDir: { classPropertyName: "sortDir", publicName: "sortDir", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedRows: "selectedRowsChange", sortKey: "sortKeyChange", sortDir: "sortDirChange", rowClicked: "rowClicked", sortChanged: "sortChanged" }, host: { properties: { "attr.data-sui-size": "size()", "attr.data-sui-striped": "striped() ? \"\" : null", "attr.data-sui-selectable": "selectable() ? \"\" : null", "attr.data-sui-loading": "loading() ? \"\" : null", "attr.data-sui-sticky": "hasStickyColumn() ? \"\" : null" } }, queries: [{ propertyName: "cellTemplates", predicate: SuiTableCellDirective }], viewQueries: [{ propertyName: "scrollEl", first: true, predicate: ["scrollEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \u2550\u2550 SUI Table \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<div class=\"sui-table\" #scrollEl>\n\n <!-- Header -->\n <div class=\"sui-table__header\">\n <!-- Checkbox header (selectable mode) \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__header-cell sui-table__header-cell--checkbox\">\n <sui-checkbox\n [checked]=\"allSelected\"\n [indeterminate]=\"partialSelected\"\n (checkedChange)=\"toggleAll()\"\n (click)=\"$event.stopPropagation()\"\n aria-label=\"Seleccionar todas las filas\"\n />\n </div>\n }\n\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__header-cell\"\n [class.sui-table__header-cell--sortable]=\"col.sortable && !col.disabled\"\n [class.sui-table__header-cell--sorted]=\"isSortActive(col.key)\"\n [class.sui-table__header-cell--disabled]=\"col.disabled\"\n [class.sui-table__header-cell--center]=\"col.align === 'center'\"\n [class.sui-table__header-cell--right]=\"col.align === 'right'\"\n [class.sui-table__header-cell--empty]=\"!col.label\"\n [class.sui-table__header-cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n (click)=\"!col.disabled && onSort(col)\"\n [attr.tabindex]=\"col.sortable && !col.disabled ? '0' : null\"\n [attr.role]=\"col.sortable ? 'columnheader' : null\"\n [attr.aria-disabled]=\"col.disabled ? 'true' : null\"\n [attr.aria-sort]=\"col.sortable ? (isSortActive(col.key) ? (sortDir() === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\n (keydown.enter)=\"!col.disabled && onSort(col)\"\n (keydown.space)=\"$event.preventDefault(); !col.disabled && onSort(col)\"\n >\n @if (col.label) {\n <span class=\"sui-table__header-label\">{{ col.label }}</span>\n }\n @if (col.sortable) {\n <span class=\"sui-table__sort-icon\" [class.sui-table__sort-icon--active]=\"isSortActive(col.key)\">\n @if (!isSortActive(col.key)) {\n <sui-icon name=\"expand-up-down-line\" [size]=\"20\" />\n } @else if (sortDir() === 'asc') {\n <sui-icon name=\"arrow-up-s-fill\" [size]=\"20\" />\n } @else {\n <sui-icon name=\"arrow-down-s-fill\" [size]=\"20\" />\n }\n </span>\n }\n </div>\n }\n </div>\n\n <!-- Body: Loading skeleton -->\n @if (loading()) {\n <div class=\"sui-table__body\">\n @for (sk of skeletonRows; track sk) {\n <div class=\"sui-table__row sui-table__row--skeleton\">\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\">\n <span class=\"sui-table__skeleton-box sui-table__skeleton-box--sm\"></span>\n </div>\n }\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <span class=\"sui-table__skeleton-box\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Body: Empty state -->\n @else if (rows().length === 0) {\n <div class=\"sui-table__empty\">\n <sui-icon name=\"inbox-line\" [size]=\"40\" class=\"sui-table__empty-icon\" />\n <p class=\"sui-table__empty-msg\">{{ emptyMessage() }}</p>\n </div>\n }\n\n <!-- Body: Data rows -->\n @else {\n <div class=\"sui-table__body\">\n @for (row of rows(); track getRowKey(row, $index); let i = $index) {\n <div\n class=\"sui-table__row\"\n [class.sui-table__row--selected]=\"selectedRows().has(getRowKey(row, i))\"\n [class.sui-table__row--striped]=\"striped() && i % 2 === 1\"\n (click)=\"rowClicked.emit(row)\"\n >\n <!-- Checkbox column \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\" (click)=\"$event.stopPropagation()\">\n <sui-checkbox\n [checked]=\"selectedRows().has(getRowKey(row, i))\"\n (checkedChange)=\"toggleRow(row, i)\"\n aria-label=\"Seleccionar fila\"\n />\n </div>\n }\n\n <!-- Data columns -->\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--center]=\"col.align === 'center'\"\n [class.sui-table__cell--right]=\"col.align === 'right'\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [class.sui-table__cell--leading]=\"cellPriority(col) === 'leading'\"\n [class.sui-table__cell--passive]=\"cellPriority(col) === 'passive'\"\n [class.sui-table__cell--none]=\"cellPriority(col) === 'none'\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <!-- Custom template via SuiTableCellDirective -->\n @if (getTemplate(col.key); as tmpl) {\n <ng-container *ngTemplateOutlet=\"tmpl.templateRef; context: { $implicit: row }\"></ng-container>\n } @else if (getCellDescription(row, col); as desc) {\n <!-- Texto + sub-texto (Figma Priority=Leading, 2da l\u00EDnea XSmall) -->\n <span class=\"sui-table__cell-block\">\n <span\n class=\"sui-table__cell-text\"\n [class.sui-table__cell-text--truncate]=\"col.truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n <span class=\"sui-table__cell-desc\">{{ desc }}</span>\n </span>\n } @else if (col.truncate) {\n <!-- Texto truncado + tooltip con el valor completo -->\n <span\n class=\"sui-table__cell-text sui-table__cell-text--truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n } @else {\n <!-- Default text rendering -->\n <span class=\"sui-table__cell-text\">{{ getCellValue(row, col.key) }}</span>\n }\n </div>\n }\n </div>\n\n <!-- Row divider (not after last row) -->\n @if (i < rows().length - 1) {\n <div class=\"sui-table__divider\"></div>\n }\n }\n </div>\n }\n\n</div>\n", styles: ["@charset \"UTF-8\";.mp-badge{display:inline-flex;align-items:center;height:24px;padding:0 10px;border-radius:6px;font-size:12px;font-weight:600;white-space:nowrap;border:1px solid transparent;line-height:1}.mp-badge--green{background:var(--admin-success-bg, #dcfce7);color:var(--admin-success, #16a34a)}.mp-badge--red{background:var(--admin-error-bg, #fee2e2);color:var(--admin-error, #ef4444)}.mp-badge--orange{background:#fff7ed;color:#c2410c;border-color:#fed7aa}.mp-badge--blue{background:var(--admin-info-bg, #dbeafe);color:#2563eb}.mp-badge--gray{background:var(--admin-bg-tertiary, #f3f4f6);color:var(--admin-text-tertiary, #6b7280)}.mp-badge--sm{height:20px;padding:0 8px;font-size:11px}.mp-action-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:30px;padding:0 12px;border-radius:6px;border:1px solid transparent;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;white-space:nowrap;transition:all .15s ease}.mp-action-btn:disabled{opacity:.5;cursor:not-allowed}.mp-action-btn--activate{background:var(--admin-success, #16a34a);color:#fff}.mp-action-btn--activate:hover{background:#15803d}.mp-action-btn--renew{background:var(--admin-info, #3b82f6);color:#fff}.mp-action-btn--renew:hover{background:#2563eb}.mp-action-btn--suspend{background:var(--admin-bg-primary, #fff);color:var(--admin-error, #ef4444);border-color:#fca5a5}.mp-action-btn--suspend:hover{background:var(--admin-error-bg, #fee2e2)}.mp-action-btn--danger{background:#dc2626;color:#fff;border:none}.mp-action-btn--danger:hover{background:#b91c1c}.mp-action-btn--outline{background:var(--admin-bg-primary, #fff);color:var(--admin-text-secondary, #374151);border-color:var(--admin-border-primary, #e5e7eb)}.mp-action-btn--outline:hover{background:var(--admin-bg-hover, #f9fafb)}.mp-action-btn--icon{width:28px;height:28px;padding:0;background:transparent;color:var(--admin-text-muted, #9ca3af);border:none}.mp-action-btn--icon:hover{background:var(--admin-bg-hover, #f9fafb);color:var(--admin-text-primary, #171717)}.mp-action-btn--icon-danger{width:28px;height:28px;padding:0;background:transparent;color:#dc2626;border:none}.mp-action-btn--icon-danger:hover{background:var(--admin-error-bg, #fee2e2);color:#dc2626}:host{display:block;width:100%}.sui-table{display:flex;flex-direction:column;width:100%;overflow:hidden;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0;font-optical-sizing:auto}:host([data-sui-sticky]) .sui-table__header,:host([data-sui-sticky]) .sui-table__row{overflow:visible}@media(max-width:767px){.sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none;display:grid;grid-template-columns:max-content}}@media(max-width:767px)and (max-width:767px){.sui-table{scrollbar-width:none}.sui-table::-webkit-scrollbar{display:none;width:0;height:0}}@media(max-width:767px){.sui-table .sui-table__header,.sui-table .sui-table__body{min-width:100%}.sui-table .sui-table__cell,.sui-table .sui-table__header-cell{min-width:120px}.sui-table .sui-table__cell--checkbox,.sui-table .sui-table__header-cell--checkbox{min-width:44px}.sui-table .sui-table__header-cell--empty{min-width:0}}:host([data-sui-sticky]) .sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none}@media(max-width:767px){:host([data-sui-sticky]) .sui-table{scrollbar-width:none}:host([data-sui-sticky]) .sui-table::-webkit-scrollbar{display:none;width:0;height:0}}:host([data-sui-sticky]) .sui-table{display:grid;grid-template-columns:max-content}:host([data-sui-sticky]) .sui-table .sui-table__header,:host([data-sui-sticky]) .sui-table .sui-table__body{min-width:100%}:host([data-sui-sticky]) .sui-table .sui-table__cell,:host([data-sui-sticky]) .sui-table .sui-table__header-cell{min-width:120px}:host([data-sui-sticky]) .sui-table .sui-table__cell--checkbox,:host([data-sui-sticky]) .sui-table .sui-table__header-cell--checkbox{min-width:44px}:host([data-sui-sticky]) .sui-table .sui-table__header-cell--empty{min-width:0}.sui-table__header{display:flex;align-items:flex-start;background:var(--sui-bg-weak-50);border-radius:var(--sui-radius-8);overflow:hidden;min-height:36px;flex-shrink:0}.sui-table__header-cell{display:flex;align-items:center;gap:2px;padding:8px 12px;min-width:0;box-sizing:border-box;white-space:nowrap;overflow:hidden;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-sub-600)}.sui-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sui-table__header-cell--sortable:hover{color:var(--sui-text-strong-950)}.sui-table__header-cell--sortable:hover .sui-table__sort-icon{opacity:1}.sui-table__header-cell--sortable:focus-visible{outline:2px solid var(--sui-primary-alpha-10);outline-offset:-2px;border-radius:var(--sui-radius-4)}.sui-table__header-cell--sorted{color:var(--sui-text-strong-950)}.sui-table__header-cell--disabled{cursor:default;pointer-events:none;color:var(--sui-text-disabled-300)}.sui-table__header-cell--disabled .sui-table__sort-icon{color:var(--sui-text-disabled-300);opacity:1}.sui-table__header-cell--empty{flex-shrink:0;padding:0}.sui-table__header-cell--center{justify-content:center}.sui-table__header-cell--right{justify-content:flex-end}.sui-table__header-cell--checkbox{flex:0 0 44px;justify-content:center}.sui-table__header-cell--sticky{position:sticky;left:0;z-index:2;background:var(--sui-bg-weak-50)}.sui-table__header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.sui-table__sort-icon{display:inline-flex;align-items:center;flex-shrink:0;color:var(--sui-text-soft-400);opacity:.6;transition:opacity var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-table__sort-icon--active{color:var(--sui-text-strong-950);opacity:1}.sui-table__body{display:flex;flex-direction:column;width:100%}.sui-table__row{display:flex;align-items:center;width:100%;border-radius:var(--sui-radius-12);overflow:hidden;cursor:pointer;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);box-sizing:border-box}@media(hover:hover)and (pointer:fine){.sui-table__row:hover,.sui-table__row:hover .sui-table__cell{background:var(--sui-bg-weak-50)}}.sui-table__row:active,.sui-table__row:active .sui-table__cell{background:var(--sui-bg-weak-50)}.sui-table__row--selected{background:var(--sui-primary-alpha-10)}.sui-table__row--selected:hover{background:var(--sui-primary-alpha-16)}.sui-table__row--striped{background:var(--sui-bg-weak-25)}.sui-table__row--skeleton{pointer-events:none;cursor:default}.sui-table__row--skeleton:hover{background:transparent}.sui-table__row--skeleton:hover .sui-table__cell{background:var(--sui-bg-white-0)}:host([data-sui-size=medium]) .sui-table__cell{min-height:64px;padding:12px 20px 12px 12px}:host([data-sui-size=small]) .sui-table__cell{min-height:48px;padding:8px 16px 8px 12px}:host([data-sui-size=large]) .sui-table__cell{min-height:80px;padding:16px 20px 16px 12px}:host([data-sui-size=xlarge]) .sui-table__cell{min-height:96px;padding:20px 20px 20px 12px}.sui-table__cell{display:flex;align-items:center;gap:12px;min-width:0;overflow:hidden;box-sizing:border-box;background:var(--sui-bg-white-0);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}.sui-table__cell--center{justify-content:center}.sui-table__cell--right{justify-content:flex-end}.sui-table__cell--checkbox{flex:0 0 44px;justify-content:center;padding:0 12px}.sui-table__cell--leading{font-weight:var(--sui-type-label-sm-weight);color:var(--sui-text-strong-950)}.sui-table__cell--passive{color:var(--sui-text-sub-600);font-weight:var(--sui-type-paragraph-sm-weight)}.sui-table__cell--sticky{position:sticky;left:0;z-index:1;background:var(--sui-bg-white-0)}.sui-table__row--selected .sui-table__cell{background:transparent}.sui-table__row--selected .sui-table__cell.sui-table__cell--sticky{background:var(--sui-primary-alpha-10)}.sui-table__cell-text{min-width:0}.sui-table__cell-text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;display:block}.sui-table__cell-block{display:flex;flex-direction:column;min-width:0}.sui-table__cell-desc{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-xs-size);font-weight:var(--sui-type-paragraph-xs-weight);line-height:var(--sui-type-paragraph-xs-line);letter-spacing:var(--sui-type-paragraph-xs-spacing);color:var(--sui-text-sub-600)}.sui-table__cell--leading .sui-table__cell-text{font-weight:var(--sui-type-label-sm-weight)}.sui-table__cell--passive .sui-table__cell-text{font-weight:inherit;color:inherit}:host ::ng-deep .sui-table__leading-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:40px;height:40px;padding:10px;box-sizing:border-box;border-radius:var(--sui-radius-full);background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);color:var(--sui-text-sub-600)}:host([data-sui-size=small]) ::ng-deep .sui-table__leading-icon{width:32px;height:32px;padding:6px}.sui-table__divider{width:100%;padding:1.5px 0;flex-shrink:0;background:var(--sui-bg-white-0)}.sui-table__divider:after{content:\"\";display:block;height:1px;background:var(--sui-stroke-soft-200)}.sui-table__empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;gap:12px;text-align:center}.sui-table__empty-icon{color:var(--sui-text-disabled-300)}.sui-table__empty-msg{margin:0;font-size:var(--sui-type-paragraph-sm-size);line-height:var(--sui-type-paragraph-sm-line);color:var(--sui-text-sub-600)}.sui-table__skeleton-box{display:block;height:14px;width:100%;max-width:180px;border-radius:var(--sui-radius-4);background:linear-gradient(90deg,var(--sui-bg-soft-200) 25%,var(--sui-bg-weak-50) 50%,var(--sui-bg-soft-200) 75%);background-size:400% 100%;animation:sui-skeleton-pulse 1.4s ease-in-out infinite}.sui-table__skeleton-box--sm{width:20px;max-width:20px;height:20px;border-radius:var(--sui-radius-4)}@keyframes sui-skeleton-pulse{0%{background-position:100% 50%}to{background-position:0% 50%}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: SuiCheckbox, selector: "sui-checkbox", inputs: ["size", "checked", "indeterminate", "disabled"], outputs: ["checkedChange"] }, { kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "directive", type: SuiTooltip, selector: "[suiTooltip], [suiTooltipLarge]", inputs: ["suiTooltip", "suiTooltipLarge", "position", "suiTooltipSize", "theme", "delay", "disabled", "showArrow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
16830
17172
  }
16831
17173
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiTable, decorators: [{
16832
17174
  type: Component,
@@ -16836,7 +17178,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
16836
17178
  '[attr.data-sui-selectable]': 'selectable() ? "" : null',
16837
17179
  '[attr.data-sui-loading]': 'loading() ? "" : null',
16838
17180
  '[attr.data-sui-sticky]': 'hasStickyColumn() ? "" : null',
16839
- }, template: "<!-- \u2550\u2550 SUI Table \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<div class=\"sui-table\" #scrollEl>\n\n <!-- Header -->\n <div class=\"sui-table__header\">\n <!-- Checkbox header (selectable mode) \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__header-cell sui-table__header-cell--checkbox\">\n <sui-checkbox\n [checked]=\"allSelected\"\n [indeterminate]=\"partialSelected\"\n (checkedChange)=\"toggleAll()\"\n (click)=\"$event.stopPropagation()\"\n aria-label=\"Seleccionar todas las filas\"\n />\n </div>\n }\n\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__header-cell\"\n [class.sui-table__header-cell--sortable]=\"col.sortable && !col.disabled\"\n [class.sui-table__header-cell--sorted]=\"isSortActive(col.key)\"\n [class.sui-table__header-cell--disabled]=\"col.disabled\"\n [class.sui-table__header-cell--center]=\"col.align === 'center'\"\n [class.sui-table__header-cell--right]=\"col.align === 'right'\"\n [class.sui-table__header-cell--empty]=\"!col.label\"\n [class.sui-table__header-cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n (click)=\"!col.disabled && onSort(col)\"\n [attr.tabindex]=\"col.sortable && !col.disabled ? '0' : null\"\n [attr.role]=\"col.sortable ? 'columnheader' : null\"\n [attr.aria-disabled]=\"col.disabled ? 'true' : null\"\n [attr.aria-sort]=\"col.sortable ? (isSortActive(col.key) ? (sortDir() === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\n (keydown.enter)=\"!col.disabled && onSort(col)\"\n (keydown.space)=\"$event.preventDefault(); !col.disabled && onSort(col)\"\n >\n @if (col.label) {\n <span class=\"sui-table__header-label\">{{ col.label }}</span>\n }\n @if (col.sortable) {\n <span class=\"sui-table__sort-icon\" [class.sui-table__sort-icon--active]=\"isSortActive(col.key)\">\n @if (!isSortActive(col.key)) {\n <sui-icon name=\"expand-up-down-line\" [size]=\"20\" />\n } @else if (sortDir() === 'asc') {\n <sui-icon name=\"arrow-up-s-fill\" [size]=\"20\" />\n } @else {\n <sui-icon name=\"arrow-down-s-fill\" [size]=\"20\" />\n }\n </span>\n }\n </div>\n }\n </div>\n\n <!-- Body: Loading skeleton -->\n @if (loading()) {\n <div class=\"sui-table__body\">\n @for (sk of skeletonRows; track sk) {\n <div class=\"sui-table__row sui-table__row--skeleton\">\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\">\n <span class=\"sui-table__skeleton-box sui-table__skeleton-box--sm\"></span>\n </div>\n }\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <span class=\"sui-table__skeleton-box\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Body: Empty state -->\n @else if (rows().length === 0) {\n <div class=\"sui-table__empty\">\n <sui-icon name=\"inbox-line\" [size]=\"40\" class=\"sui-table__empty-icon\" />\n <p class=\"sui-table__empty-msg\">{{ emptyMessage() }}</p>\n </div>\n }\n\n <!-- Body: Data rows -->\n @else {\n <div class=\"sui-table__body\">\n @for (row of rows(); track getRowKey(row, $index); let i = $index) {\n <div\n class=\"sui-table__row\"\n [class.sui-table__row--selected]=\"selectedRows().has(getRowKey(row, i))\"\n [class.sui-table__row--striped]=\"striped() && i % 2 === 1\"\n (click)=\"rowClicked.emit(row)\"\n >\n <!-- Checkbox column \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\" (click)=\"$event.stopPropagation()\">\n <sui-checkbox\n [checked]=\"selectedRows().has(getRowKey(row, i))\"\n (checkedChange)=\"toggleRow(row, i)\"\n aria-label=\"Seleccionar fila\"\n />\n </div>\n }\n\n <!-- Data columns -->\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--center]=\"col.align === 'center'\"\n [class.sui-table__cell--right]=\"col.align === 'right'\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [class.sui-table__cell--leading]=\"cellPriority(col) === 'leading'\"\n [class.sui-table__cell--passive]=\"cellPriority(col) === 'passive'\"\n [class.sui-table__cell--none]=\"cellPriority(col) === 'none'\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <!-- Custom template via SuiTableCellDirective -->\n @if (getTemplate(col.key); as tmpl) {\n <ng-container *ngTemplateOutlet=\"tmpl.templateRef; context: { $implicit: row }\"></ng-container>\n } @else if (getCellDescription(row, col); as desc) {\n <!-- Texto + sub-texto (Figma Priority=Leading, 2da l\u00EDnea XSmall) -->\n <span class=\"sui-table__cell-block\">\n <span\n class=\"sui-table__cell-text\"\n [class.sui-table__cell-text--truncate]=\"col.truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n <span class=\"sui-table__cell-desc\">{{ desc }}</span>\n </span>\n } @else if (col.truncate) {\n <!-- Texto truncado + tooltip con el valor completo -->\n <span\n class=\"sui-table__cell-text sui-table__cell-text--truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n } @else {\n <!-- Default text rendering -->\n <span class=\"sui-table__cell-text\">{{ getCellValue(row, col.key) }}</span>\n }\n </div>\n }\n </div>\n\n <!-- Row divider (not after last row) -->\n @if (i < rows().length - 1) {\n <div class=\"sui-table__divider\"></div>\n }\n }\n </div>\n }\n\n</div>\n", styles: ["@charset \"UTF-8\";.mp-badge{display:inline-flex;align-items:center;height:24px;padding:0 10px;border-radius:6px;font-size:12px;font-weight:600;white-space:nowrap;border:1px solid transparent;line-height:1}.mp-badge--green{background:var(--admin-success-bg, #dcfce7);color:var(--admin-success, #16a34a)}.mp-badge--red{background:var(--admin-error-bg, #fee2e2);color:var(--admin-error, #ef4444)}.mp-badge--orange{background:#fff7ed;color:#c2410c;border-color:#fed7aa}.mp-badge--blue{background:var(--admin-info-bg, #dbeafe);color:#2563eb}.mp-badge--gray{background:var(--admin-bg-tertiary, #f3f4f6);color:var(--admin-text-tertiary, #6b7280)}.mp-badge--sm{height:20px;padding:0 8px;font-size:11px}.mp-action-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:30px;padding:0 12px;border-radius:6px;border:1px solid transparent;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;white-space:nowrap;transition:all .15s ease}.mp-action-btn:disabled{opacity:.5;cursor:not-allowed}.mp-action-btn--activate{background:var(--admin-success, #16a34a);color:#fff}.mp-action-btn--activate:hover{background:#15803d}.mp-action-btn--renew{background:var(--admin-info, #3b82f6);color:#fff}.mp-action-btn--renew:hover{background:#2563eb}.mp-action-btn--suspend{background:var(--admin-bg-primary, #fff);color:var(--admin-error, #ef4444);border-color:#fca5a5}.mp-action-btn--suspend:hover{background:var(--admin-error-bg, #fee2e2)}.mp-action-btn--danger{background:#dc2626;color:#fff;border:none}.mp-action-btn--danger:hover{background:#b91c1c}.mp-action-btn--outline{background:var(--admin-bg-primary, #fff);color:var(--admin-text-secondary, #374151);border-color:var(--admin-border-primary, #e5e7eb)}.mp-action-btn--outline:hover{background:var(--admin-bg-hover, #f9fafb)}.mp-action-btn--icon{width:28px;height:28px;padding:0;background:transparent;color:var(--admin-text-muted, #9ca3af);border:none}.mp-action-btn--icon:hover{background:var(--admin-bg-hover, #f9fafb);color:var(--admin-text-primary, #171717)}.mp-action-btn--icon-danger{width:28px;height:28px;padding:0;background:transparent;color:#dc2626;border:none}.mp-action-btn--icon-danger:hover{background:var(--admin-error-bg, #fee2e2);color:#dc2626}:host{display:block;width:100%}.sui-table{display:flex;flex-direction:column;width:100%;overflow:hidden;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0;font-optical-sizing:auto}:host([data-sui-sticky]) .sui-table__header,:host([data-sui-sticky]) .sui-table__row{overflow:visible}@media(max-width:767px){.sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none}}@media(max-width:767px)and (max-width:767px){.sui-table{scrollbar-width:none}.sui-table::-webkit-scrollbar{display:none;width:0;height:0}}@media(max-width:767px){.sui-table .sui-table__header,.sui-table .sui-table__body{min-width:max-content}.sui-table .sui-table__cell,.sui-table .sui-table__header-cell{min-width:120px}.sui-table .sui-table__cell--checkbox,.sui-table .sui-table__header-cell--checkbox{min-width:44px}.sui-table .sui-table__header-cell--empty{min-width:0}}:host([data-sui-sticky]) .sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none}@media(max-width:767px){:host([data-sui-sticky]) .sui-table{scrollbar-width:none}:host([data-sui-sticky]) .sui-table::-webkit-scrollbar{display:none;width:0;height:0}}:host([data-sui-sticky]) .sui-table .sui-table__header,:host([data-sui-sticky]) .sui-table .sui-table__body{min-width:max-content}:host([data-sui-sticky]) .sui-table .sui-table__cell,:host([data-sui-sticky]) .sui-table .sui-table__header-cell{min-width:120px}:host([data-sui-sticky]) .sui-table .sui-table__cell--checkbox,:host([data-sui-sticky]) .sui-table .sui-table__header-cell--checkbox{min-width:44px}:host([data-sui-sticky]) .sui-table .sui-table__header-cell--empty{min-width:0}.sui-table__header{display:flex;align-items:flex-start;background:var(--sui-bg-weak-50);border-radius:var(--sui-radius-8);overflow:hidden;min-height:36px;flex-shrink:0}.sui-table__header-cell{display:flex;align-items:center;gap:2px;padding:8px 12px;min-width:0;box-sizing:border-box;white-space:nowrap;overflow:hidden;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-sub-600)}.sui-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sui-table__header-cell--sortable:hover{color:var(--sui-text-strong-950)}.sui-table__header-cell--sortable:hover .sui-table__sort-icon{opacity:1}.sui-table__header-cell--sortable:focus-visible{outline:2px solid var(--sui-primary-alpha-10);outline-offset:-2px;border-radius:var(--sui-radius-4)}.sui-table__header-cell--sorted{color:var(--sui-text-strong-950)}.sui-table__header-cell--disabled{cursor:default;pointer-events:none;color:var(--sui-text-disabled-300)}.sui-table__header-cell--disabled .sui-table__sort-icon{color:var(--sui-text-disabled-300);opacity:1}.sui-table__header-cell--empty{flex-shrink:0;padding:0}.sui-table__header-cell--center{justify-content:center}.sui-table__header-cell--right{justify-content:flex-end}.sui-table__header-cell--checkbox{flex:0 0 44px;justify-content:center}.sui-table__header-cell--sticky{position:sticky;left:0;z-index:2;background:var(--sui-bg-weak-50)}.sui-table__header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.sui-table__sort-icon{display:inline-flex;align-items:center;flex-shrink:0;color:var(--sui-text-soft-400);opacity:.6;transition:opacity var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-table__sort-icon--active{color:var(--sui-text-strong-950);opacity:1}.sui-table__body{display:flex;flex-direction:column;width:100%}.sui-table__row{display:flex;align-items:center;width:100%;border-radius:var(--sui-radius-12);overflow:hidden;cursor:pointer;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);box-sizing:border-box}.sui-table__row:hover,.sui-table__row:hover .sui-table__cell,.sui-table__row:active,.sui-table__row:active .sui-table__cell{background:var(--sui-bg-weak-50)}.sui-table__row--selected{background:var(--sui-primary-alpha-10)}.sui-table__row--selected:hover{background:var(--sui-primary-alpha-16)}.sui-table__row--striped{background:var(--sui-bg-weak-50)}.sui-table__row--skeleton{pointer-events:none;cursor:default}.sui-table__row--skeleton:hover{background:transparent}.sui-table__row--skeleton:hover .sui-table__cell{background:var(--sui-bg-white-0)}:host([data-sui-size=medium]) .sui-table__cell{min-height:64px;padding:12px 20px 12px 12px}:host([data-sui-size=small]) .sui-table__cell{min-height:48px;padding:8px 16px 8px 12px}:host([data-sui-size=large]) .sui-table__cell{min-height:80px;padding:16px 20px 16px 12px}:host([data-sui-size=xlarge]) .sui-table__cell{min-height:96px;padding:20px 20px 20px 12px}.sui-table__cell{display:flex;align-items:center;gap:12px;min-width:0;overflow:hidden;box-sizing:border-box;background:var(--sui-bg-white-0);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}.sui-table__cell--center{justify-content:center}.sui-table__cell--right{justify-content:flex-end}.sui-table__cell--checkbox{flex:0 0 44px;justify-content:center;padding:0 12px}.sui-table__cell--leading{font-weight:var(--sui-type-label-sm-weight);color:var(--sui-text-strong-950)}.sui-table__cell--passive{color:var(--sui-text-sub-600);font-weight:var(--sui-type-paragraph-sm-weight)}.sui-table__cell--sticky{position:sticky;left:0;z-index:1;background:var(--sui-bg-white-0)}.sui-table__row--selected .sui-table__cell{background:transparent}.sui-table__row--selected .sui-table__cell.sui-table__cell--sticky{background:var(--sui-primary-alpha-10)}.sui-table__cell-text{min-width:0}.sui-table__cell-text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;display:block}.sui-table__cell-block{display:flex;flex-direction:column;min-width:0}.sui-table__cell-desc{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-xs-size);font-weight:var(--sui-type-paragraph-xs-weight);line-height:var(--sui-type-paragraph-xs-line);letter-spacing:var(--sui-type-paragraph-xs-spacing);color:var(--sui-text-sub-600)}.sui-table__cell--leading .sui-table__cell-text{font-weight:var(--sui-type-label-sm-weight)}.sui-table__cell--passive .sui-table__cell-text{font-weight:inherit;color:inherit}:host ::ng-deep .sui-table__leading-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:40px;height:40px;padding:10px;box-sizing:border-box;border-radius:var(--sui-radius-full);background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);color:var(--sui-text-sub-600)}:host([data-sui-size=small]) ::ng-deep .sui-table__leading-icon{width:32px;height:32px;padding:6px}.sui-table__divider{width:100%;padding:1.5px 0;flex-shrink:0;background:var(--sui-bg-white-0)}.sui-table__divider:after{content:\"\";display:block;height:1px;background:var(--sui-stroke-soft-200)}.sui-table__empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;gap:12px;text-align:center}.sui-table__empty-icon{color:var(--sui-text-disabled-300)}.sui-table__empty-msg{margin:0;font-size:var(--sui-type-paragraph-sm-size);line-height:var(--sui-type-paragraph-sm-line);color:var(--sui-text-sub-600)}.sui-table__skeleton-box{display:block;height:14px;width:100%;max-width:180px;border-radius:var(--sui-radius-4);background:linear-gradient(90deg,var(--sui-bg-soft-200) 25%,var(--sui-bg-weak-50) 50%,var(--sui-bg-soft-200) 75%);background-size:400% 100%;animation:sui-skeleton-pulse 1.4s ease-in-out infinite}.sui-table__skeleton-box--sm{width:20px;max-width:20px;height:20px;border-radius:var(--sui-radius-4)}@keyframes sui-skeleton-pulse{0%{background-position:100% 50%}to{background-position:0% 50%}}\n"] }]
17181
+ }, template: "<!-- \u2550\u2550 SUI Table \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<div class=\"sui-table\" #scrollEl>\n\n <!-- Header -->\n <div class=\"sui-table__header\">\n <!-- Checkbox header (selectable mode) \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__header-cell sui-table__header-cell--checkbox\">\n <sui-checkbox\n [checked]=\"allSelected\"\n [indeterminate]=\"partialSelected\"\n (checkedChange)=\"toggleAll()\"\n (click)=\"$event.stopPropagation()\"\n aria-label=\"Seleccionar todas las filas\"\n />\n </div>\n }\n\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__header-cell\"\n [class.sui-table__header-cell--sortable]=\"col.sortable && !col.disabled\"\n [class.sui-table__header-cell--sorted]=\"isSortActive(col.key)\"\n [class.sui-table__header-cell--disabled]=\"col.disabled\"\n [class.sui-table__header-cell--center]=\"col.align === 'center'\"\n [class.sui-table__header-cell--right]=\"col.align === 'right'\"\n [class.sui-table__header-cell--empty]=\"!col.label\"\n [class.sui-table__header-cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n (click)=\"!col.disabled && onSort(col)\"\n [attr.tabindex]=\"col.sortable && !col.disabled ? '0' : null\"\n [attr.role]=\"col.sortable ? 'columnheader' : null\"\n [attr.aria-disabled]=\"col.disabled ? 'true' : null\"\n [attr.aria-sort]=\"col.sortable ? (isSortActive(col.key) ? (sortDir() === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\n (keydown.enter)=\"!col.disabled && onSort(col)\"\n (keydown.space)=\"$event.preventDefault(); !col.disabled && onSort(col)\"\n >\n @if (col.label) {\n <span class=\"sui-table__header-label\">{{ col.label }}</span>\n }\n @if (col.sortable) {\n <span class=\"sui-table__sort-icon\" [class.sui-table__sort-icon--active]=\"isSortActive(col.key)\">\n @if (!isSortActive(col.key)) {\n <sui-icon name=\"expand-up-down-line\" [size]=\"20\" />\n } @else if (sortDir() === 'asc') {\n <sui-icon name=\"arrow-up-s-fill\" [size]=\"20\" />\n } @else {\n <sui-icon name=\"arrow-down-s-fill\" [size]=\"20\" />\n }\n </span>\n }\n </div>\n }\n </div>\n\n <!-- Body: Loading skeleton -->\n @if (loading()) {\n <div class=\"sui-table__body\">\n @for (sk of skeletonRows; track sk) {\n <div class=\"sui-table__row sui-table__row--skeleton\">\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\">\n <span class=\"sui-table__skeleton-box sui-table__skeleton-box--sm\"></span>\n </div>\n }\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <span class=\"sui-table__skeleton-box\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Body: Empty state -->\n @else if (rows().length === 0) {\n <div class=\"sui-table__empty\">\n <sui-icon name=\"inbox-line\" [size]=\"40\" class=\"sui-table__empty-icon\" />\n <p class=\"sui-table__empty-msg\">{{ emptyMessage() }}</p>\n </div>\n }\n\n <!-- Body: Data rows -->\n @else {\n <div class=\"sui-table__body\">\n @for (row of rows(); track getRowKey(row, $index); let i = $index) {\n <div\n class=\"sui-table__row\"\n [class.sui-table__row--selected]=\"selectedRows().has(getRowKey(row, i))\"\n [class.sui-table__row--striped]=\"striped() && i % 2 === 1\"\n (click)=\"rowClicked.emit(row)\"\n >\n <!-- Checkbox column \u2014 compone sui-checkbox (canon) -->\n @if (selectable()) {\n <div class=\"sui-table__cell sui-table__cell--checkbox\" (click)=\"$event.stopPropagation()\">\n <sui-checkbox\n [checked]=\"selectedRows().has(getRowKey(row, i))\"\n (checkedChange)=\"toggleRow(row, i)\"\n aria-label=\"Seleccionar fila\"\n />\n </div>\n }\n\n <!-- Data columns -->\n @for (col of columns(); track col.key) {\n <div\n class=\"sui-table__cell\"\n [class.sui-table__cell--center]=\"col.align === 'center'\"\n [class.sui-table__cell--right]=\"col.align === 'right'\"\n [class.sui-table__cell--sticky]=\"col.sticky\"\n [class.sui-table__cell--leading]=\"cellPriority(col) === 'leading'\"\n [class.sui-table__cell--passive]=\"cellPriority(col) === 'passive'\"\n [class.sui-table__cell--none]=\"cellPriority(col) === 'none'\"\n [style.width]=\"col.width ?? null\"\n [style.min-width]=\"colMinWidth(col)\"\n [style.max-width]=\"col.maxWidth ?? null\"\n [style.flex]=\"col.width ? '0 0 ' + col.width : '1'\"\n >\n <!-- Custom template via SuiTableCellDirective -->\n @if (getTemplate(col.key); as tmpl) {\n <ng-container *ngTemplateOutlet=\"tmpl.templateRef; context: { $implicit: row }\"></ng-container>\n } @else if (getCellDescription(row, col); as desc) {\n <!-- Texto + sub-texto (Figma Priority=Leading, 2da l\u00EDnea XSmall) -->\n <span class=\"sui-table__cell-block\">\n <span\n class=\"sui-table__cell-text\"\n [class.sui-table__cell-text--truncate]=\"col.truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n <span class=\"sui-table__cell-desc\">{{ desc }}</span>\n </span>\n } @else if (col.truncate) {\n <!-- Texto truncado + tooltip con el valor completo -->\n <span\n class=\"sui-table__cell-text sui-table__cell-text--truncate\"\n [suiTooltip]=\"getCellTooltip(row, col)\"\n >{{ getCellValue(row, col.key) }}</span>\n } @else {\n <!-- Default text rendering -->\n <span class=\"sui-table__cell-text\">{{ getCellValue(row, col.key) }}</span>\n }\n </div>\n }\n </div>\n\n <!-- Row divider (not after last row) -->\n @if (i < rows().length - 1) {\n <div class=\"sui-table__divider\"></div>\n }\n }\n </div>\n }\n\n</div>\n", styles: ["@charset \"UTF-8\";.mp-badge{display:inline-flex;align-items:center;height:24px;padding:0 10px;border-radius:6px;font-size:12px;font-weight:600;white-space:nowrap;border:1px solid transparent;line-height:1}.mp-badge--green{background:var(--admin-success-bg, #dcfce7);color:var(--admin-success, #16a34a)}.mp-badge--red{background:var(--admin-error-bg, #fee2e2);color:var(--admin-error, #ef4444)}.mp-badge--orange{background:#fff7ed;color:#c2410c;border-color:#fed7aa}.mp-badge--blue{background:var(--admin-info-bg, #dbeafe);color:#2563eb}.mp-badge--gray{background:var(--admin-bg-tertiary, #f3f4f6);color:var(--admin-text-tertiary, #6b7280)}.mp-badge--sm{height:20px;padding:0 8px;font-size:11px}.mp-action-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:30px;padding:0 12px;border-radius:6px;border:1px solid transparent;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit;white-space:nowrap;transition:all .15s ease}.mp-action-btn:disabled{opacity:.5;cursor:not-allowed}.mp-action-btn--activate{background:var(--admin-success, #16a34a);color:#fff}.mp-action-btn--activate:hover{background:#15803d}.mp-action-btn--renew{background:var(--admin-info, #3b82f6);color:#fff}.mp-action-btn--renew:hover{background:#2563eb}.mp-action-btn--suspend{background:var(--admin-bg-primary, #fff);color:var(--admin-error, #ef4444);border-color:#fca5a5}.mp-action-btn--suspend:hover{background:var(--admin-error-bg, #fee2e2)}.mp-action-btn--danger{background:#dc2626;color:#fff;border:none}.mp-action-btn--danger:hover{background:#b91c1c}.mp-action-btn--outline{background:var(--admin-bg-primary, #fff);color:var(--admin-text-secondary, #374151);border-color:var(--admin-border-primary, #e5e7eb)}.mp-action-btn--outline:hover{background:var(--admin-bg-hover, #f9fafb)}.mp-action-btn--icon{width:28px;height:28px;padding:0;background:transparent;color:var(--admin-text-muted, #9ca3af);border:none}.mp-action-btn--icon:hover{background:var(--admin-bg-hover, #f9fafb);color:var(--admin-text-primary, #171717)}.mp-action-btn--icon-danger{width:28px;height:28px;padding:0;background:transparent;color:#dc2626;border:none}.mp-action-btn--icon-danger:hover{background:var(--admin-error-bg, #fee2e2);color:#dc2626}:host{display:block;width:100%}.sui-table{display:flex;flex-direction:column;width:100%;overflow:hidden;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0;font-optical-sizing:auto}:host([data-sui-sticky]) .sui-table__header,:host([data-sui-sticky]) .sui-table__row{overflow:visible}@media(max-width:767px){.sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none;display:grid;grid-template-columns:max-content}}@media(max-width:767px)and (max-width:767px){.sui-table{scrollbar-width:none}.sui-table::-webkit-scrollbar{display:none;width:0;height:0}}@media(max-width:767px){.sui-table .sui-table__header,.sui-table .sui-table__body{min-width:100%}.sui-table .sui-table__cell,.sui-table .sui-table__header-cell{min-width:120px}.sui-table .sui-table__cell--checkbox,.sui-table .sui-table__header-cell--checkbox{min-width:44px}.sui-table .sui-table__header-cell--empty{min-width:0}}:host([data-sui-sticky]) .sui-table{overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;background:var(--sui-bg-white-0);overscroll-behavior-y:none}@media(max-width:767px){:host([data-sui-sticky]) .sui-table{scrollbar-width:none}:host([data-sui-sticky]) .sui-table::-webkit-scrollbar{display:none;width:0;height:0}}:host([data-sui-sticky]) .sui-table{display:grid;grid-template-columns:max-content}:host([data-sui-sticky]) .sui-table .sui-table__header,:host([data-sui-sticky]) .sui-table .sui-table__body{min-width:100%}:host([data-sui-sticky]) .sui-table .sui-table__cell,:host([data-sui-sticky]) .sui-table .sui-table__header-cell{min-width:120px}:host([data-sui-sticky]) .sui-table .sui-table__cell--checkbox,:host([data-sui-sticky]) .sui-table .sui-table__header-cell--checkbox{min-width:44px}:host([data-sui-sticky]) .sui-table .sui-table__header-cell--empty{min-width:0}.sui-table__header{display:flex;align-items:flex-start;background:var(--sui-bg-weak-50);border-radius:var(--sui-radius-8);overflow:hidden;min-height:36px;flex-shrink:0}.sui-table__header-cell{display:flex;align-items:center;gap:2px;padding:8px 12px;min-width:0;box-sizing:border-box;white-space:nowrap;overflow:hidden;font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-sub-600)}.sui-table__header-cell--sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.sui-table__header-cell--sortable:hover{color:var(--sui-text-strong-950)}.sui-table__header-cell--sortable:hover .sui-table__sort-icon{opacity:1}.sui-table__header-cell--sortable:focus-visible{outline:2px solid var(--sui-primary-alpha-10);outline-offset:-2px;border-radius:var(--sui-radius-4)}.sui-table__header-cell--sorted{color:var(--sui-text-strong-950)}.sui-table__header-cell--disabled{cursor:default;pointer-events:none;color:var(--sui-text-disabled-300)}.sui-table__header-cell--disabled .sui-table__sort-icon{color:var(--sui-text-disabled-300);opacity:1}.sui-table__header-cell--empty{flex-shrink:0;padding:0}.sui-table__header-cell--center{justify-content:center}.sui-table__header-cell--right{justify-content:flex-end}.sui-table__header-cell--checkbox{flex:0 0 44px;justify-content:center}.sui-table__header-cell--sticky{position:sticky;left:0;z-index:2;background:var(--sui-bg-weak-50)}.sui-table__header-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1;min-width:0}.sui-table__sort-icon{display:inline-flex;align-items:center;flex-shrink:0;color:var(--sui-text-soft-400);opacity:.6;transition:opacity var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-table__sort-icon--active{color:var(--sui-text-strong-950);opacity:1}.sui-table__body{display:flex;flex-direction:column;width:100%}.sui-table__row{display:flex;align-items:center;width:100%;border-radius:var(--sui-radius-12);overflow:hidden;cursor:pointer;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);box-sizing:border-box}@media(hover:hover)and (pointer:fine){.sui-table__row:hover,.sui-table__row:hover .sui-table__cell{background:var(--sui-bg-weak-50)}}.sui-table__row:active,.sui-table__row:active .sui-table__cell{background:var(--sui-bg-weak-50)}.sui-table__row--selected{background:var(--sui-primary-alpha-10)}.sui-table__row--selected:hover{background:var(--sui-primary-alpha-16)}.sui-table__row--striped{background:var(--sui-bg-weak-25)}.sui-table__row--skeleton{pointer-events:none;cursor:default}.sui-table__row--skeleton:hover{background:transparent}.sui-table__row--skeleton:hover .sui-table__cell{background:var(--sui-bg-white-0)}:host([data-sui-size=medium]) .sui-table__cell{min-height:64px;padding:12px 20px 12px 12px}:host([data-sui-size=small]) .sui-table__cell{min-height:48px;padding:8px 16px 8px 12px}:host([data-sui-size=large]) .sui-table__cell{min-height:80px;padding:16px 20px 16px 12px}:host([data-sui-size=xlarge]) .sui-table__cell{min-height:96px;padding:20px 20px 20px 12px}.sui-table__cell{display:flex;align-items:center;gap:12px;min-width:0;overflow:hidden;box-sizing:border-box;background:var(--sui-bg-white-0);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out);font-size:var(--sui-type-paragraph-sm-size);font-weight:var(--sui-type-paragraph-sm-weight);line-height:var(--sui-type-paragraph-sm-line);letter-spacing:var(--sui-type-paragraph-sm-spacing);color:var(--sui-text-strong-950)}.sui-table__cell--center{justify-content:center}.sui-table__cell--right{justify-content:flex-end}.sui-table__cell--checkbox{flex:0 0 44px;justify-content:center;padding:0 12px}.sui-table__cell--leading{font-weight:var(--sui-type-label-sm-weight);color:var(--sui-text-strong-950)}.sui-table__cell--passive{color:var(--sui-text-sub-600);font-weight:var(--sui-type-paragraph-sm-weight)}.sui-table__cell--sticky{position:sticky;left:0;z-index:1;background:var(--sui-bg-white-0)}.sui-table__row--selected .sui-table__cell{background:transparent}.sui-table__row--selected .sui-table__cell.sui-table__cell--sticky{background:var(--sui-primary-alpha-10)}.sui-table__cell-text{min-width:0}.sui-table__cell-text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;display:block}.sui-table__cell-block{display:flex;flex-direction:column;min-width:0}.sui-table__cell-desc{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--sui-type-paragraph-xs-size);font-weight:var(--sui-type-paragraph-xs-weight);line-height:var(--sui-type-paragraph-xs-line);letter-spacing:var(--sui-type-paragraph-xs-spacing);color:var(--sui-text-sub-600)}.sui-table__cell--leading .sui-table__cell-text{font-weight:var(--sui-type-label-sm-weight)}.sui-table__cell--passive .sui-table__cell-text{font-weight:inherit;color:inherit}:host ::ng-deep .sui-table__leading-icon{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:40px;height:40px;padding:10px;box-sizing:border-box;border-radius:var(--sui-radius-full);background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);box-shadow:var(--sui-regular-shadow-x-small);color:var(--sui-text-sub-600)}:host([data-sui-size=small]) ::ng-deep .sui-table__leading-icon{width:32px;height:32px;padding:6px}.sui-table__divider{width:100%;padding:1.5px 0;flex-shrink:0;background:var(--sui-bg-white-0)}.sui-table__divider:after{content:\"\";display:block;height:1px;background:var(--sui-stroke-soft-200)}.sui-table__empty{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:48px 24px;gap:12px;text-align:center}.sui-table__empty-icon{color:var(--sui-text-disabled-300)}.sui-table__empty-msg{margin:0;font-size:var(--sui-type-paragraph-sm-size);line-height:var(--sui-type-paragraph-sm-line);color:var(--sui-text-sub-600)}.sui-table__skeleton-box{display:block;height:14px;width:100%;max-width:180px;border-radius:var(--sui-radius-4);background:linear-gradient(90deg,var(--sui-bg-soft-200) 25%,var(--sui-bg-weak-50) 50%,var(--sui-bg-soft-200) 75%);background-size:400% 100%;animation:sui-skeleton-pulse 1.4s ease-in-out infinite}.sui-table__skeleton-box--sm{width:20px;max-width:20px;height:20px;border-radius:var(--sui-radius-4)}@keyframes sui-skeleton-pulse{0%{background-position:100% 50%}to{background-position:0% 50%}}\n"] }]
16840
17182
  }], ctorParameters: () => [], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], emptyMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], rowKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowKey", required: false }] }], selectedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedRows", required: false }] }, { type: i0.Output, args: ["selectedRowsChange"] }], sortKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortKey", required: false }] }, { type: i0.Output, args: ["sortKeyChange"] }], sortDir: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDir", required: false }] }, { type: i0.Output, args: ["sortDirChange"] }], rowClicked: [{ type: i0.Output, args: ["rowClicked"] }], sortChanged: [{ type: i0.Output, args: ["sortChanged"] }], scrollEl: [{ type: i0.ViewChild, args: ['scrollEl', { isSignal: true }] }], cellTemplates: [{
16841
17183
  type: ContentChildren,
16842
17184
  args: [SuiTableCellDirective]