@ajuarezso/sui-design-system 0.18.4 → 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
|
|
10870
|
-
|
|
10871
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
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
|
|
10877
|
-
|
|
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.
|
|
10880
|
-
/**
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
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
|
|
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
|
-
|
|
10897
|
-
return this.currentBreakpoint() >= maxBp;
|
|
10951
|
+
return this.currentBreakpoint() >= this.maxBreakpoint();
|
|
10898
10952
|
}, ...(ngDevMode ? [{ debugName: "atMaxBreakpoint" }] : /* istanbul ignore next */ []));
|
|
10899
|
-
// ──
|
|
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).
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
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
|
-
/*
|
|
10962
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
// ──
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
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
|
-
|
|
11040
|
-
if (
|
|
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.
|
|
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
|
-
|
|
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
|
-
/*
|
|
11061
|
-
reduce el progress (sheet baja). */
|
|
11062
|
-
const
|
|
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.
|
|
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
|
-
/*
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
const
|
|
11110
|
-
const
|
|
11111
|
-
const snapBp = this.
|
|
11112
|
-
this.
|
|
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
|
|
11138
|
-
//
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
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
|
-
/*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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']
|
|
@@ -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]
|