@ajuarezso/sui-design-system 0.18.4 → 0.18.9

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';
@@ -1707,7 +1707,7 @@ const BRAND_DISPLAY_NAMES = {
1707
1707
  youtube: 'YouTube',
1708
1708
  };
1709
1709
  /** Sizes canon — alineados con sui-flag / sui-emoji. */
1710
- const SIZE_PX$1 = {
1710
+ const SIZE_PX$2 = {
1711
1711
  xs: 16,
1712
1712
  sm: 20,
1713
1713
  md: 24,
@@ -1771,7 +1771,7 @@ class SuiBrandLogo {
1771
1771
  rel = input('noopener noreferrer', ...(ngDevMode ? [{ debugName: "rel" }] : /* istanbul ignore next */ []));
1772
1772
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
1773
1773
  ariaLabel = input(null, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
1774
- sizePx = computed(() => `${SIZE_PX$1[this.size()]}px`, ...(ngDevMode ? [{ debugName: "sizePx" }] : /* istanbul ignore next */ []));
1774
+ sizePx = computed(() => `${SIZE_PX$2[this.size()]}px`, ...(ngDevMode ? [{ debugName: "sizePx" }] : /* istanbul ignore next */ []));
1775
1775
  src = computed(() => `/assets/brand/brand-logos/${this.company()}-${this.variant()}.svg`, ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
1776
1776
  /** Alt label auto-derived from company name. Override via ariaLabel. */
1777
1777
  alt = computed(() => this.ariaLabel() ?? `${BRAND_DISPLAY_NAMES[this.company()]} logo`, ...(ngDevMode ? [{ debugName: "alt" }] : /* istanbul ignore next */ []));
@@ -9139,7 +9139,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
9139
9139
  }], propDecorators: { imageUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageUrl", required: false }] }], companyLogoSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "companyLogoSrc", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], subtitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitle", required: false }] }], alignment: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignment", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], upload: [{ type: i0.Output, args: ["upload"] }], remove: [{ type: i0.Output, args: ["remove"] }], change: [{ type: i0.Output, args: ["change"] }] } });
9140
9140
 
9141
9141
  /** px values per size token */
9142
- const SIZE_PX = {
9142
+ const SIZE_PX$1 = {
9143
9143
  sm: 80,
9144
9144
  md: 120,
9145
9145
  lg: 160,
@@ -9258,7 +9258,7 @@ class SuiImageUpload {
9258
9258
  inputRef = viewChild('imgInput', ...(ngDevMode ? [{ debugName: "inputRef" }] : /* istanbul ignore next */ []));
9259
9259
  dragging = signal(false, ...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
9260
9260
  internalError = signal(null, ...(ngDevMode ? [{ debugName: "internalError" }] : /* istanbul ignore next */ []));
9261
- sizePx = computed(() => SIZE_PX[this.size()], ...(ngDevMode ? [{ debugName: "sizePx" }] : /* istanbul ignore next */ []));
9261
+ sizePx = computed(() => SIZE_PX$1[this.size()], ...(ngDevMode ? [{ debugName: "sizePx" }] : /* istanbul ignore next */ []));
9262
9262
  /** Camera icon px en el empty state. xl escala a 20, resto 16
9263
9263
  * (matchea el escalado del contenedor 32→40 en SCSS). */
9264
9264
  iconSize = computed(() => (this.size() === 'xl' ? 20 : 16), ...(ngDevMode ? [{ debugName: "iconSize" }] : /* istanbul ignore next */ []));
@@ -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();
@@ -10799,6 +10816,123 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
10799
10816
  }, template: "<!-- Brand logo (circle 40 / 48 seg\u00FAn appearance) -->\n<div class=\"sui-integration-switch__brand\" aria-hidden=\"true\">\n <ng-content select=\"[sui-integration-brand]\">\n @if (brandIconSrc(); as src) {\n <img [src]=\"src\" alt=\"\" class=\"sui-integration-switch__brand-img\" />\n } @else if (brandIcon(); as icon) {\n <sui-icon [name]=\"icon\" [size]=\"appearance() === 'list' ? 32 : 24\" />\n }\n </ng-content>\n</div>\n\n<!-- Title + description block -->\n<div class=\"sui-integration-switch__text\">\n <div class=\"sui-integration-switch__title-row\">\n <span class=\"sui-integration-switch__title\">{{ title() }}</span>\n @if (badgeCfg(); as bcfg) {\n <sui-badge\n class=\"sui-integration-switch__badge\"\n [color]=\"bcfg.color ?? 'orange'\"\n [variant]=\"bcfg.variant ?? 'light'\"\n [size]=\"bcfg.size ?? 'small'\"\n >{{ bcfg.label }}</sui-badge>\n }\n </div>\n @if (description(); as desc) {\n <p class=\"sui-integration-switch__description\">{{ desc }}</p>\n }\n</div>\n\n<!-- Manage button (trailing en horizontal, full-width en vertical) -->\n@if (manageCfg(); as mcfg) {\n <button\n type=\"button\"\n class=\"sui-integration-switch__manage\"\n [attr.aria-label]=\"mcfg.label\"\n [disabled]=\"isDisabled()\"\n (click)=\"onManageClick($event)\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n >\n <sui-icon [name]=\"mcfg.icon\" [size]=\"20\" />\n <span class=\"sui-integration-switch__manage-label\">{{ mcfg.label }}</span>\n </button>\n}\n\n<!-- Switch (inline en horizontal \u00B7 absolute top-right en vertical) -->\n@if (showToggle()) {\n <sui-switch\n class=\"sui-integration-switch__toggle\"\n [checked]=\"effectiveActive()\"\n [disabled]=\"isDisabled()\"\n (checkedChange)=\"onSwitchChange($event)\"\n />\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;display:flex;box-sizing:border-box;width:100%;font-family:var(--sui-font-sans, \"Inter\", system-ui, sans-serif);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0}:host([data-sui-type=horizontal]){flex-direction:row;align-items:center;gap:14px}:host([data-sui-type=vertical]){flex-direction:column;align-items:flex-start;gap:14px}:host([data-sui-appearance=card]){padding:16px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:12px;box-shadow:var(--sui-shadow-x-small)}:host([data-sui-appearance=list]){padding:0;background:transparent;border:0}.sui-integration-switch__brand{box-sizing:border-box;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;padding:8px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:999px;box-shadow:var(--sui-shadow-x-small);overflow:hidden}:host([data-sui-appearance=card]) .sui-integration-switch__brand{width:40px;height:40px}:host([data-sui-appearance=list]) .sui-integration-switch__brand{width:48px;height:48px}.sui-integration-switch__brand-img{width:100%;height:100%;object-fit:contain;display:block}.sui-integration-switch__text{flex:1 0 0;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:4px}.sui-integration-switch__title-row{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.sui-integration-switch__title{color:var(--sui-text-strong-950);font-weight:500;word-break:break-word}:host([data-sui-appearance=card]) .sui-integration-switch__title{font-size:14px;line-height:20px;letter-spacing:-.006em}:host([data-sui-appearance=list]) .sui-integration-switch__title{font-size:16px;line-height:24px;letter-spacing:-.011em}.sui-integration-switch__description{margin:0;color:var(--sui-text-sub-600);font-weight:400;word-break:break-word}:host([data-sui-appearance=card]) .sui-integration-switch__description{font-size:12px;line-height:16px}:host([data-sui-appearance=list]) .sui-integration-switch__description{font-size:14px;line-height:20px;letter-spacing:-.006em}.sui-integration-switch__badge{flex-shrink:0}.sui-integration-switch__manage{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;gap:4px;padding:8px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:8px;box-shadow:var(--sui-shadow-x-small);color:var(--sui-text-sub-600);font-family:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent;transition:background-color .15s ease,transform .12s ease}.sui-integration-switch__manage:hover:not(:disabled){background:var(--sui-bg-weak-50)}.sui-integration-switch__manage:active:not(:disabled){transform:scale(.97)}.sui-integration-switch__manage:focus-visible{outline:2px solid var(--sui-primary-base);outline-offset:2px}.sui-integration-switch__manage:disabled{opacity:.4;cursor:not-allowed}.sui-integration-switch__manage-label{padding:0 4px;font-size:14px;font-weight:500;line-height:20px;letter-spacing:-.006em}:host([data-sui-type=vertical]) .sui-integration-switch__manage{width:100%}.sui-integration-switch__toggle{flex-shrink:0}:host([data-sui-type=vertical]) .sui-integration-switch__toggle{position:absolute;top:19px;right:19px}:host([data-sui-type=vertical][data-sui-appearance=list]) .sui-integration-switch__toggle{top:12px;right:12px}:host([data-sui-disabled]){opacity:.5;pointer-events:none}\n"] }]
10800
10817
  }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], brandIconSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandIconSrc", required: false }] }], brandIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandIcon", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], manage: [{ type: i0.Input, args: [{ isSignal: true, alias: "manage", required: false }] }], showToggle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showToggle", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], activeChange: [{ type: i0.Output, args: ["activeChange"] }], manageClick: [{ type: i0.Output, args: ["manageClick"] }] } });
10801
10818
 
10819
+ /** Alto en px por size. En este componente el size manda el ALTO; el ancho sale
10820
+ * del aspect ratio del lockup, que no es cuadrado. */
10821
+ const SIZE_PX = {
10822
+ xs: 16,
10823
+ sm: 20,
10824
+ md: 24,
10825
+ lg: 32,
10826
+ xl: 40,
10827
+ '2xl': 48,
10828
+ };
10829
+ /**
10830
+ * SUI Logo — el logo de Master Pedidos, dibujado inline y coloreable.
10831
+ *
10832
+ * NO confundir con `sui-brand-logo`, que sirve logos de TERCEROS (Apple, Google,
10833
+ * Stripe…) como assets `<img>` intocables por compliance de marca. Este es el
10834
+ * logo PROPIO del producto: se inlinea justamente para poder teñirlo.
10835
+ *
10836
+ * ── El dibujo ────────────────────────────────────────────────────────────────
10837
+ * Son tres piezas: la M (isotipo) y las palabras «Master» y «Pedidos». Las dos
10838
+ * orientaciones son esas mismas tres piezas re-acomodadas, así que el path data
10839
+ * vive UNA sola vez en el template y lo único que cambia es el `viewBox` y el
10840
+ * `transform` de cada grupo:
10841
+ *
10842
+ * horizontal → M a la izquierda + bloque de palabra a la derecha, escala 1.
10843
+ * viewBox `0.218 3.987 773.623 266.421` (ratio 2.904:1)
10844
+ * stacked → M arriba + bloque de palabra debajo, centrado, escala 0.55765.
10845
+ * viewBox `-0.266 0.109 257.897 420.55` (ratio 0.613:1)
10846
+ * markOnly → solo la M.
10847
+ * viewBox `0.218 3.987 257.897 266.421` (ratio 0.968:1)
10848
+ *
10849
+ * Los viewBox son el bbox EXACTO medido con `getBBox()` sobre el dibujo, no un
10850
+ * lienzo con aire: el componente no aporta padding propio.
10851
+ *
10852
+ * En las dos orientaciones la palabra va en dos líneas («Master» sobre
10853
+ * «Pedidos»). El lockup de una sola línea es otro dibujo y no está acá.
10854
+ *
10855
+ * ── Color ────────────────────────────────────────────────────────────────────
10856
+ * `markColor` y `textColor` aceptan cualquier color CSS, y lo natural es pasar
10857
+ * un token: `markColor="var(--sui-primary-base)"`. Se aplican por custom
10858
+ * property (`--sui-logo-mark-color` / `--sui-logo-text-color`) y no por atributo
10859
+ * `fill`, porque un `var()` dentro de un atributo de presentación SVG no
10860
+ * resuelve.
10861
+ *
10862
+ * ── Tamaño ───────────────────────────────────────────────────────────────────
10863
+ * `size` fija el ALTO (xs=16 … 2xl=48) y el ancho sale solo. `height` es el
10864
+ * escape hatch para los altos que no están en la escala: un número son px
10865
+ * (28, 80…) y un string es cualquier valor CSS (`'60%'` para seguir al
10866
+ * contenedor). Si viene, gana sobre `size`.
10867
+ *
10868
+ * ── Accesibilidad ────────────────────────────────────────────────────────────
10869
+ * Por defecto el SVG va con `role="img"` y `aria-label="Master Pedidos"`: el
10870
+ * logo ES el nombre del producto. Cuando se pone al lado de un texto que ya dice
10871
+ * «Master Pedidos» (el `<h1>` de las pantallas «Acerca de»), pasar
10872
+ * `[decorative]="true"` para que el lector de pantalla no lo diga dos veces.
10873
+ *
10874
+ * Usage:
10875
+ * <sui-logo />
10876
+ * <sui-logo orientation="stacked" size="xl" />
10877
+ * <sui-logo [markOnly]="true" [decorative]="true" [height]="80" />
10878
+ * <sui-logo markColor="var(--sui-static-white)" textColor="var(--sui-static-white)" />
10879
+ */
10880
+ class SuiLogo {
10881
+ orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
10882
+ /** Solo la M, sin la palabra. Cuando es `true`, `orientation` no aplica. */
10883
+ markOnly = input(false, ...(ngDevMode ? [{ debugName: "markOnly" }] : /* istanbul ignore next */ []));
10884
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
10885
+ /**
10886
+ * Alto fuera de la escala. Número = px; string = cualquier valor CSS
10887
+ * (`'60%'` para seguir al contenedor, como hace `sui-icon` con `size`).
10888
+ * Si viene, gana sobre `size`.
10889
+ */
10890
+ height = input(null, ...(ngDevMode ? [{ debugName: "height" }] : /* istanbul ignore next */ []));
10891
+ /** Color de la M. Token o cualquier color CSS. */
10892
+ markColor = input('var(--sui-primary-base)', ...(ngDevMode ? [{ debugName: "markColor" }] : /* istanbul ignore next */ []));
10893
+ /** Color de la palabra. Token o cualquier color CSS. */
10894
+ textColor = input('var(--sui-text-strong-950)', ...(ngDevMode ? [{ debugName: "textColor" }] : /* istanbul ignore next */ []));
10895
+ /** `true` cuando al lado ya está escrito «Master Pedidos». */
10896
+ decorative = input(false, ...(ngDevMode ? [{ debugName: "decorative" }] : /* istanbul ignore next */ []));
10897
+ ariaLabel = input('Master Pedidos', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
10898
+ heightPx = computed(() => {
10899
+ const h = this.height();
10900
+ if (h === null)
10901
+ return `${SIZE_PX[this.size()]}px`;
10902
+ return typeof h === 'number' ? `${h}px` : h;
10903
+ }, ...(ngDevMode ? [{ debugName: "heightPx" }] : /* istanbul ignore next */ []));
10904
+ viewBox = computed(() => {
10905
+ if (this.markOnly())
10906
+ return '0.218 3.987 257.897 266.421';
10907
+ return this.orientation() === 'stacked'
10908
+ ? '-0.266 0.109 257.897 420.55'
10909
+ : '0.218 3.987 773.623 266.421';
10910
+ }, ...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
10911
+ /** En apilado la M se corre para que el bloque entero quede centrado. */
10912
+ markTransform = computed(() => !this.markOnly() && this.orientation() === 'stacked' ? 'translate(-0.484,-3.878)' : null, ...(ngDevMode ? [{ debugName: "markTransform" }] : /* istanbul ignore next */ []));
10913
+ masterTransform = computed(() => this.orientation() === 'stacked'
10914
+ ? 'translate(0,309.299) scale(0.55765) translate(39.626,0.082)'
10915
+ : 'matrix(1,0,0,1,311.359985,40.32)', ...(ngDevMode ? [{ debugName: "masterTransform" }] : /* istanbul ignore next */ []));
10916
+ pedidosTransform = computed(() => this.orientation() === 'stacked'
10917
+ ? 'translate(0,309.299) scale(0.55765) translate(0.3,110.402)'
10918
+ : 'matrix(1,0,0,1,312.480011,150.639999)', ...(ngDevMode ? [{ debugName: "pedidosTransform" }] : /* istanbul ignore next */ []));
10919
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiLogo, deps: [], target: i0.ɵɵFactoryTarget.Component });
10920
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiLogo, isStandalone: true, selector: "sui-logo", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, markOnly: { classPropertyName: "markOnly", publicName: "markOnly", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, markColor: { classPropertyName: "markColor", publicName: "markColor", isSignal: true, isRequired: false, transformFunction: null }, textColor: { classPropertyName: "textColor", publicName: "textColor", isSignal: true, isRequired: false, transformFunction: null }, decorative: { classPropertyName: "decorative", publicName: "decorative", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.title": "null", "attr.data-sui-orientation": "markOnly() ? \"mark\" : orientation()", "attr.data-sui-size": "size()", "style.--sui-logo-height": "heightPx()", "style.--sui-logo-mark-color": "markColor()", "style.--sui-logo-text-color": "textColor()" } }, ngImport: i0, template: "<!-- El dibujo vive una sola vez: la M, la palabra \u00ABMaster\u00BB y la palabra\n \u00ABPedidos\u00BB son los mismos tres grupos en las dos orientaciones. Lo \u00FAnico que\n cambia entre horizontal y apilado es el viewBox y el transform de cada grupo. -->\n<svg\n class=\"sui-logo__svg\"\n [attr.viewBox]=\"viewBox()\"\n [attr.role]=\"decorative() ? null : 'img'\"\n [attr.aria-label]=\"decorative() ? null : ariaLabel()\"\n [attr.aria-hidden]=\"decorative() ? 'true' : null\"\n focusable=\"false\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <g class=\"sui-logo__mark\" [attr.transform]=\"markTransform()\" fill-rule=\"nonzero\">\n <polygon points=\"21.2352 84.0784 57.3384 84.0784 60.3288 66.472 24.1752 66.472\" />\n <polygon points=\"30.072 31.0744 27.132 48.6976 63.3528 48.6976 66.3432 31.0744\" />\n <path d=\"M219.8112,31.0744 L145.8072,137.2336 C145.6392,137.5528 145.32,137.872 145.152,138.04 C144.6648,138.5272 144.0264,138.8464 143.3712,138.8464 C142.2456,138.8464 141.4392,138.208 140.952,137.2336 L104.5968,31.0744 L66.2088,31.0744 L63.0672,49.6888 L60.3288,66.4552 L60.2448,66.4552 L56.7672,87.0688 L54.348,101.8528 L54.2808,101.8528 L44.6544,158.8888 C42.7224,166.8016 35.9352,172.6312 27.5184,172.6312 L6.5184,172.6312 L0.2184,210.448 L45.6288,210.448 C61.7904,210.448 75.0456,199.2928 78.5904,184.2736 L79.0776,181.3672 L80.6904,172.648 L81.4968,167.9608 L92.3328,103.4824 L124.8072,193.3288 C124.9752,193.984 125.1264,194.6224 125.4624,195.2608 C126.924,198.3352 129.9816,200.4352 133.5432,200.4352 C135.9624,200.4352 138.2304,199.4608 139.8432,197.848 C139.8432,197.68 140.0112,197.5288 140.1624,197.5288 L141.288,195.748 L207.6984,102.1888 L179.256,270.4072 L217.56,270.4072 L258.1152,31.0912 L219.8112,31.0912 L219.8112,31.0744 Z\" />\n <circle cx=\"161.175613\" cy=\"31.0350292\" r=\"27.0484118\" />\n <polygon points=\"12.3816 137.2504 9.4416 154.8568 45.3264 154.8568 48.3168 137.2504\" />\n <polygon points=\"15.3384 119.476 51.3408 119.476 54.3312 101.8528 18.2784 101.8528\" />\n </g>\n\n @if (!markOnly()) {\n <g class=\"sui-logo__word\" [attr.transform]=\"masterTransform()\" fill-rule=\"nonzero\">\n <path d=\"M18.4912,86.296 L0.1456,86.296 L0.1456,0.1288 L27.5464,0.1288 L43.6912,68.6728 L59.3488,0.1288 L87.0016,0.1288 L87.0016,86.296 L68.656,86.296 L68.656,19.1632 L54.9808,77.3584 C53.7544,82.6 49.0672,86.3128 43.6912,86.3128 L43.6912,86.3128 C38.3152,86.3128 33.6616,82.6336 32.4016,77.4088 L18.508,19.18 L18.508,86.296 L18.4912,86.296 Z\" />\n <path d=\"M157.9816,86.296 L139.384,86.296 C137.8048,84.3976 137.4352,83.2216 137.4352,79.912 C131.32,86.0608 124.7176,89.0176 117.376,89.0176 C105.2632,89.0176 97.3168,81.34 97.3168,69.8656 C97.3168,58.3912 103.6672,51.8896 116.7712,49.7728 L123.6256,48.5968 C132.0592,47.3032 132.0592,47.3032 134.3944,46.1272 C136.2424,45.0688 137.3344,43.288 137.3344,41.1544 C137.3344,36.904 134.0248,34.7704 127.4224,34.7704 C118.9888,34.7704 116.1664,36.904 115.3096,43.5232 L98.7952,43.5232 C99.904,28.7392 109.1944,21.4144 127.036,21.4144 C144.8776,21.4144 154.0672,28.0336 154.0672,41.0368 L154.0672,76.5016 C154.0672,79.6936 155.0416,81.5752 157.9816,84.2968 L157.9816,86.296 Z M137.3176,56.1568 C135.352,57.0976 134.6296,57.3328 130.0936,58.1728 L124.2136,59.2312 C117.124,60.6592 114.436,63.0112 114.436,67.984 C114.436,72.7216 117.9808,75.6616 123.7264,75.6616 C132.412,75.6616 137.3008,70.2184 137.3008,60.6592 L137.3008,56.1568 L137.3176,56.1568 Z\" />\n <path d=\"M206.8696,43.036 C206.752,37.24 202.72,34.4008 194.5216,34.4008 C188.524,34.4008 184.6096,36.7696 184.6096,40.3144 C184.6096,42.9184 185.836,43.8592 190.6072,45.2704 L212.2624,51.3016 C220.948,53.788 225.232,59.1136 225.232,67.3792 C225.232,73.6456 222.292,79.5592 217.4032,83.3392 C212.5144,87.1192 205.5424,89.0008 196.3696,89.0008 C176.3104,89.0008 165.676,81.7936 165.1888,67.732 L181.9384,67.732 C182.6776,71.1592 183.4168,72.4528 185.248,73.7632 C187.4488,75.3088 190.876,76.0144 195.3952,76.0144 C203.3584,76.0144 208.1128,73.6456 208.1128,69.748 C208.1128,67.1608 206.6344,65.8504 202.3672,64.5568 L181.9384,58.408 C175.588,56.4088 173.5048,55.3336 171.1696,53.0992 C168.8512,50.6128 167.4904,46.9504 167.4904,42.7 C167.4904,29.5792 177.8896,21.4312 194.6392,21.4312 C212.38,21.4312 223.132,29.5792 223.384,43.0696 L206.8696,43.0696 L206.8696,43.036 Z\" />\n <path d=\"M266.2744,34.7704 L256.732,34.7704 L256.732,69.5128 C256.732,75.1744 257.8408,76.4848 262.36,76.4848 C263.704,76.4848 264.5608,76.3672 266.2744,76.132 L266.2744,87.724 C263.0992,88.6648 260.2768,89.0176 256.3624,89.0176 C245.1064,89.0176 239.6128,84.0616 239.6128,73.9984 L239.6128,34.7536 L231.1792,34.7536 L231.1792,23.7496 L239.6128,23.7496 L239.6128,6.6136 L256.732,6.6136 L256.732,23.7496 L266.2744,23.7496 L266.2744,34.7704 L266.2744,34.7704 Z\" />\n <path d=\"M289.492,59.6008 C289.744,65.632 290.3488,68.4544 291.9448,70.8232 C294.3808,74.368 298.2952,76.384 303.2008,76.384 C309.4336,76.384 314.2048,73.4272 316.288,68.3536 L333.172,68.3536 C329.3752,81.004 317.3968,89.0344 302.596,89.0344 C283.8808,89.0344 272.3896,76.5016 272.3896,56.056 C272.3896,34.6528 284.0152,21.4312 302.9656,21.4312 C316.3048,21.4312 326.9392,28.4032 331.3408,39.9784 C332.9368,44.4808 333.9112,50.3776 333.9112,56.7616 C333.9112,57.5848 333.9112,58.1896 333.7936,59.6008 L289.492,59.6008 L289.492,59.6008 Z M316.036,48.5968 C315.1792,39.1384 310.5256,34.0648 302.6968,34.0648 C295.1032,34.0648 290.836,38.8024 289.7272,48.5968 L316.036,48.5968 Z\" />\n <path d=\"M362.4712,22.4728 L362.4712,35.0056 C366.268,26.3704 372.988,21.4144 380.8168,21.4144 C381.556,21.4144 381.9256,21.4144 382.9,21.532 L382.9,38.3152 C380.5816,37.9624 379.3552,37.8448 377.5072,37.8448 C367.4776,37.8448 362.4712,42.6832 362.4712,52.3768 L362.4712,86.296 L345.352,86.296 L345.352,22.4728 L362.4712,22.4728 L362.4712,22.4728 Z\" />\n </g>\n <g class=\"sui-logo__word\" [attr.transform]=\"pedidosTransform()\" fill-rule=\"nonzero\">\n <path d=\"M18.8328,86.5704 L0.4872,86.5704 L0.4872,0.4032 L39.8664,0.4032 C58.4472,0.4032 68.6112,9.8616 68.6112,27.1152 C68.6112,44.604 58.0944,55.8432 41.6976,55.8432 L18.8328,55.8432 L18.8328,86.5704 Z M35.952,41.0592 C45.7464,41.0592 50.2656,36.9264 50.2656,28.056 C50.2656,19.3032 45.7464,15.1704 35.952,15.1704 L18.8328,15.1704 L18.8328,41.0592 L35.952,41.0592 Z\" />\n <path d=\"M89.7624,59.8584 C90.0144,65.8896 90.6192,68.712 92.2152,71.0808 C94.6512,74.6256 98.5656,76.6416 103.4712,76.6416 C109.704,76.6416 114.4752,73.6848 116.5584,68.6112 L133.4424,68.6112 C129.6456,81.2616 117.6672,89.292 102.8664,89.292 C84.1512,89.292 72.66,76.7592 72.66,56.3136 C72.66,34.9104 84.2856,21.6888 103.236,21.6888 C116.5752,21.6888 127.2096,28.6608 131.6112,40.236 C133.2072,44.7384 134.1816,50.6352 134.1816,57.0192 C134.1816,57.8424 134.1816,58.4472 134.064,59.8584 L89.7624,59.8584 L89.7624,59.8584 Z M116.3064,48.8544 C115.4496,39.396 110.796,34.3224 102.9672,34.3224 C95.3736,34.3224 91.1064,39.06 89.9976,48.8544 L116.3064,48.8544 Z\" />\n <path d=\"M189.252,80.0688 C184.968,86.4528 179.34,89.292 171.024,89.292 C162.96,89.292 154.8792,85.3944 150.36,79.128 C145.9584,72.9792 143.2704,64.2432 143.2704,55.608 C143.2704,36.3384 155.2656,21.6888 171.0408,21.6888 C179.3568,21.6888 184.9848,24.6456 189.2688,31.0296 L189.2688,0.42 L206.388,0.42 L206.388,86.5872 L189.2688,86.5872 L189.2688,80.0688 L189.252,80.0688 Z M160.3896,55.608 C160.3896,67.3008 166.2528,75.4656 174.8208,75.4656 C183.372,75.4656 189.252,67.4352 189.252,55.8432 C189.252,43.5456 183.4896,35.5151741 174.8208,35.5151741 C166.2528,35.4984 160.3896,43.6632 160.3896,55.608 Z\" />\n <rect x=\"222.6\" y=\"22.7472\" width=\"17.1192\" height=\"63.8232\" />\n <path d=\"M297.9144,80.0688 C293.6304,86.4528 288.0024,89.292 279.6864,89.292 C271.6224,89.292 263.5416,85.3944 259.0224,79.128 C254.6208,72.9792 251.9328,64.2432 251.9328,55.608 C251.9328,36.3384 263.928,21.6888 279.7032,21.6888 C288.0192,21.6888 293.6472,24.6456 297.9312,31.0296 L297.9312,0.42 L315.0504,0.42 L315.0504,86.5872 L297.9312,86.5872 L297.9312,80.0688 L297.9144,80.0688 Z M269.052,55.608 C269.052,67.3008 274.9152,75.4656 283.4832,75.4656 C292.0344,75.4656 297.9144,67.4352 297.9144,55.8432 C297.9144,43.5456 292.152,35.5151741 283.4832,35.5151741 C274.9152,35.4984 269.052,43.6632 269.052,55.608 Z\" />\n <path d=\"M392.6664,55.944 C392.6664,76.5072 380.2008,89.2752 360.0072,89.2752 C339.7128,89.2752 327.348,76.5072 327.348,55.4736 C327.348,34.5576 339.696,21.672 359.8728,21.672 C380.5536,21.672 392.6664,34.3224 392.6664,55.944 Z M344.4672,55.4736 C344.4672,67.7712 350.7,75.9192 360.0072,75.9192 C369.18,75.9192 375.5472,67.6536 375.5472,55.7088 C375.5472,43.176 369.432,35.028 360.0072,35.028 C350.7168,35.028 344.4672,43.1928 344.4672,55.4736 Z\" />\n <path d=\"M442.9992,43.3104 C442.8816,37.5144 438.8328,34.6752 430.6512,34.6752 C424.6536,34.6752 420.7392,37.044 420.7392,40.5888 C420.7392,43.1928 421.9656,44.1336 426.7368,45.5448 L448.392,51.576 C457.0776,54.0624 461.3616,59.388 461.3616,67.6536 C461.3616,73.92 458.4216,79.8336 453.5328,83.6136 C448.644,87.3936 441.672,89.2752 432.4992,89.2752 C412.44,89.2752 401.8056,82.068 401.3184,68.0064 L418.068,68.0064 C418.8072,71.4336 419.5464,72.7272 421.3776,74.0376 C423.5784,75.5832 427.0056,76.2888 431.5248,76.2888 C439.488,76.2888 444.2424,73.92 444.2424,70.0224 C444.2424,67.4352 442.7808,66.1248 438.4968,64.8312 L418.068,58.6824 C411.7176,56.6832 409.6344,55.608 407.2992,53.3736 C404.9808,50.8872 403.6368,47.2248 403.6368,42.9744 C403.6368,29.8536 414.036,21.7056 430.7856,21.7056 C448.5264,21.7056 459.2784,29.8536 459.5304,43.344 L442.9992,43.344 L442.9992,43.3104 Z\" />\n <ellipse cx=\"231.168\" cy=\"8.6688\" rx=\"8.5512\" ry=\"8.2656\" />\n </g>\n }\n</svg>\n", styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;height:var(--sui-logo-height, 24px);width:auto;flex-shrink:0}.sui-logo__svg{display:block;height:100%;width:auto;overflow:visible}.sui-logo__mark{fill:var(--sui-logo-mark-color)}.sui-logo__word{fill:var(--sui-logo-text-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
10921
+ }
10922
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiLogo, decorators: [{
10923
+ type: Component,
10924
+ args: [{ selector: 'sui-logo', changeDetection: ChangeDetectionStrategy.OnPush, host: {
10925
+ /* El input `title` no existe acá, pero el host igual podría recibir un
10926
+ `title=""` desde el template consumidor — se stripea por convención. */
10927
+ '[attr.title]': 'null',
10928
+ '[attr.data-sui-orientation]': 'markOnly() ? "mark" : orientation()',
10929
+ '[attr.data-sui-size]': 'size()',
10930
+ '[style.--sui-logo-height]': 'heightPx()',
10931
+ '[style.--sui-logo-mark-color]': 'markColor()',
10932
+ '[style.--sui-logo-text-color]': 'textColor()',
10933
+ }, template: "<!-- El dibujo vive una sola vez: la M, la palabra \u00ABMaster\u00BB y la palabra\n \u00ABPedidos\u00BB son los mismos tres grupos en las dos orientaciones. Lo \u00FAnico que\n cambia entre horizontal y apilado es el viewBox y el transform de cada grupo. -->\n<svg\n class=\"sui-logo__svg\"\n [attr.viewBox]=\"viewBox()\"\n [attr.role]=\"decorative() ? null : 'img'\"\n [attr.aria-label]=\"decorative() ? null : ariaLabel()\"\n [attr.aria-hidden]=\"decorative() ? 'true' : null\"\n focusable=\"false\"\n xmlns=\"http://www.w3.org/2000/svg\"\n>\n <g class=\"sui-logo__mark\" [attr.transform]=\"markTransform()\" fill-rule=\"nonzero\">\n <polygon points=\"21.2352 84.0784 57.3384 84.0784 60.3288 66.472 24.1752 66.472\" />\n <polygon points=\"30.072 31.0744 27.132 48.6976 63.3528 48.6976 66.3432 31.0744\" />\n <path d=\"M219.8112,31.0744 L145.8072,137.2336 C145.6392,137.5528 145.32,137.872 145.152,138.04 C144.6648,138.5272 144.0264,138.8464 143.3712,138.8464 C142.2456,138.8464 141.4392,138.208 140.952,137.2336 L104.5968,31.0744 L66.2088,31.0744 L63.0672,49.6888 L60.3288,66.4552 L60.2448,66.4552 L56.7672,87.0688 L54.348,101.8528 L54.2808,101.8528 L44.6544,158.8888 C42.7224,166.8016 35.9352,172.6312 27.5184,172.6312 L6.5184,172.6312 L0.2184,210.448 L45.6288,210.448 C61.7904,210.448 75.0456,199.2928 78.5904,184.2736 L79.0776,181.3672 L80.6904,172.648 L81.4968,167.9608 L92.3328,103.4824 L124.8072,193.3288 C124.9752,193.984 125.1264,194.6224 125.4624,195.2608 C126.924,198.3352 129.9816,200.4352 133.5432,200.4352 C135.9624,200.4352 138.2304,199.4608 139.8432,197.848 C139.8432,197.68 140.0112,197.5288 140.1624,197.5288 L141.288,195.748 L207.6984,102.1888 L179.256,270.4072 L217.56,270.4072 L258.1152,31.0912 L219.8112,31.0912 L219.8112,31.0744 Z\" />\n <circle cx=\"161.175613\" cy=\"31.0350292\" r=\"27.0484118\" />\n <polygon points=\"12.3816 137.2504 9.4416 154.8568 45.3264 154.8568 48.3168 137.2504\" />\n <polygon points=\"15.3384 119.476 51.3408 119.476 54.3312 101.8528 18.2784 101.8528\" />\n </g>\n\n @if (!markOnly()) {\n <g class=\"sui-logo__word\" [attr.transform]=\"masterTransform()\" fill-rule=\"nonzero\">\n <path d=\"M18.4912,86.296 L0.1456,86.296 L0.1456,0.1288 L27.5464,0.1288 L43.6912,68.6728 L59.3488,0.1288 L87.0016,0.1288 L87.0016,86.296 L68.656,86.296 L68.656,19.1632 L54.9808,77.3584 C53.7544,82.6 49.0672,86.3128 43.6912,86.3128 L43.6912,86.3128 C38.3152,86.3128 33.6616,82.6336 32.4016,77.4088 L18.508,19.18 L18.508,86.296 L18.4912,86.296 Z\" />\n <path d=\"M157.9816,86.296 L139.384,86.296 C137.8048,84.3976 137.4352,83.2216 137.4352,79.912 C131.32,86.0608 124.7176,89.0176 117.376,89.0176 C105.2632,89.0176 97.3168,81.34 97.3168,69.8656 C97.3168,58.3912 103.6672,51.8896 116.7712,49.7728 L123.6256,48.5968 C132.0592,47.3032 132.0592,47.3032 134.3944,46.1272 C136.2424,45.0688 137.3344,43.288 137.3344,41.1544 C137.3344,36.904 134.0248,34.7704 127.4224,34.7704 C118.9888,34.7704 116.1664,36.904 115.3096,43.5232 L98.7952,43.5232 C99.904,28.7392 109.1944,21.4144 127.036,21.4144 C144.8776,21.4144 154.0672,28.0336 154.0672,41.0368 L154.0672,76.5016 C154.0672,79.6936 155.0416,81.5752 157.9816,84.2968 L157.9816,86.296 Z M137.3176,56.1568 C135.352,57.0976 134.6296,57.3328 130.0936,58.1728 L124.2136,59.2312 C117.124,60.6592 114.436,63.0112 114.436,67.984 C114.436,72.7216 117.9808,75.6616 123.7264,75.6616 C132.412,75.6616 137.3008,70.2184 137.3008,60.6592 L137.3008,56.1568 L137.3176,56.1568 Z\" />\n <path d=\"M206.8696,43.036 C206.752,37.24 202.72,34.4008 194.5216,34.4008 C188.524,34.4008 184.6096,36.7696 184.6096,40.3144 C184.6096,42.9184 185.836,43.8592 190.6072,45.2704 L212.2624,51.3016 C220.948,53.788 225.232,59.1136 225.232,67.3792 C225.232,73.6456 222.292,79.5592 217.4032,83.3392 C212.5144,87.1192 205.5424,89.0008 196.3696,89.0008 C176.3104,89.0008 165.676,81.7936 165.1888,67.732 L181.9384,67.732 C182.6776,71.1592 183.4168,72.4528 185.248,73.7632 C187.4488,75.3088 190.876,76.0144 195.3952,76.0144 C203.3584,76.0144 208.1128,73.6456 208.1128,69.748 C208.1128,67.1608 206.6344,65.8504 202.3672,64.5568 L181.9384,58.408 C175.588,56.4088 173.5048,55.3336 171.1696,53.0992 C168.8512,50.6128 167.4904,46.9504 167.4904,42.7 C167.4904,29.5792 177.8896,21.4312 194.6392,21.4312 C212.38,21.4312 223.132,29.5792 223.384,43.0696 L206.8696,43.0696 L206.8696,43.036 Z\" />\n <path d=\"M266.2744,34.7704 L256.732,34.7704 L256.732,69.5128 C256.732,75.1744 257.8408,76.4848 262.36,76.4848 C263.704,76.4848 264.5608,76.3672 266.2744,76.132 L266.2744,87.724 C263.0992,88.6648 260.2768,89.0176 256.3624,89.0176 C245.1064,89.0176 239.6128,84.0616 239.6128,73.9984 L239.6128,34.7536 L231.1792,34.7536 L231.1792,23.7496 L239.6128,23.7496 L239.6128,6.6136 L256.732,6.6136 L256.732,23.7496 L266.2744,23.7496 L266.2744,34.7704 L266.2744,34.7704 Z\" />\n <path d=\"M289.492,59.6008 C289.744,65.632 290.3488,68.4544 291.9448,70.8232 C294.3808,74.368 298.2952,76.384 303.2008,76.384 C309.4336,76.384 314.2048,73.4272 316.288,68.3536 L333.172,68.3536 C329.3752,81.004 317.3968,89.0344 302.596,89.0344 C283.8808,89.0344 272.3896,76.5016 272.3896,56.056 C272.3896,34.6528 284.0152,21.4312 302.9656,21.4312 C316.3048,21.4312 326.9392,28.4032 331.3408,39.9784 C332.9368,44.4808 333.9112,50.3776 333.9112,56.7616 C333.9112,57.5848 333.9112,58.1896 333.7936,59.6008 L289.492,59.6008 L289.492,59.6008 Z M316.036,48.5968 C315.1792,39.1384 310.5256,34.0648 302.6968,34.0648 C295.1032,34.0648 290.836,38.8024 289.7272,48.5968 L316.036,48.5968 Z\" />\n <path d=\"M362.4712,22.4728 L362.4712,35.0056 C366.268,26.3704 372.988,21.4144 380.8168,21.4144 C381.556,21.4144 381.9256,21.4144 382.9,21.532 L382.9,38.3152 C380.5816,37.9624 379.3552,37.8448 377.5072,37.8448 C367.4776,37.8448 362.4712,42.6832 362.4712,52.3768 L362.4712,86.296 L345.352,86.296 L345.352,22.4728 L362.4712,22.4728 L362.4712,22.4728 Z\" />\n </g>\n <g class=\"sui-logo__word\" [attr.transform]=\"pedidosTransform()\" fill-rule=\"nonzero\">\n <path d=\"M18.8328,86.5704 L0.4872,86.5704 L0.4872,0.4032 L39.8664,0.4032 C58.4472,0.4032 68.6112,9.8616 68.6112,27.1152 C68.6112,44.604 58.0944,55.8432 41.6976,55.8432 L18.8328,55.8432 L18.8328,86.5704 Z M35.952,41.0592 C45.7464,41.0592 50.2656,36.9264 50.2656,28.056 C50.2656,19.3032 45.7464,15.1704 35.952,15.1704 L18.8328,15.1704 L18.8328,41.0592 L35.952,41.0592 Z\" />\n <path d=\"M89.7624,59.8584 C90.0144,65.8896 90.6192,68.712 92.2152,71.0808 C94.6512,74.6256 98.5656,76.6416 103.4712,76.6416 C109.704,76.6416 114.4752,73.6848 116.5584,68.6112 L133.4424,68.6112 C129.6456,81.2616 117.6672,89.292 102.8664,89.292 C84.1512,89.292 72.66,76.7592 72.66,56.3136 C72.66,34.9104 84.2856,21.6888 103.236,21.6888 C116.5752,21.6888 127.2096,28.6608 131.6112,40.236 C133.2072,44.7384 134.1816,50.6352 134.1816,57.0192 C134.1816,57.8424 134.1816,58.4472 134.064,59.8584 L89.7624,59.8584 L89.7624,59.8584 Z M116.3064,48.8544 C115.4496,39.396 110.796,34.3224 102.9672,34.3224 C95.3736,34.3224 91.1064,39.06 89.9976,48.8544 L116.3064,48.8544 Z\" />\n <path d=\"M189.252,80.0688 C184.968,86.4528 179.34,89.292 171.024,89.292 C162.96,89.292 154.8792,85.3944 150.36,79.128 C145.9584,72.9792 143.2704,64.2432 143.2704,55.608 C143.2704,36.3384 155.2656,21.6888 171.0408,21.6888 C179.3568,21.6888 184.9848,24.6456 189.2688,31.0296 L189.2688,0.42 L206.388,0.42 L206.388,86.5872 L189.2688,86.5872 L189.2688,80.0688 L189.252,80.0688 Z M160.3896,55.608 C160.3896,67.3008 166.2528,75.4656 174.8208,75.4656 C183.372,75.4656 189.252,67.4352 189.252,55.8432 C189.252,43.5456 183.4896,35.5151741 174.8208,35.5151741 C166.2528,35.4984 160.3896,43.6632 160.3896,55.608 Z\" />\n <rect x=\"222.6\" y=\"22.7472\" width=\"17.1192\" height=\"63.8232\" />\n <path d=\"M297.9144,80.0688 C293.6304,86.4528 288.0024,89.292 279.6864,89.292 C271.6224,89.292 263.5416,85.3944 259.0224,79.128 C254.6208,72.9792 251.9328,64.2432 251.9328,55.608 C251.9328,36.3384 263.928,21.6888 279.7032,21.6888 C288.0192,21.6888 293.6472,24.6456 297.9312,31.0296 L297.9312,0.42 L315.0504,0.42 L315.0504,86.5872 L297.9312,86.5872 L297.9312,80.0688 L297.9144,80.0688 Z M269.052,55.608 C269.052,67.3008 274.9152,75.4656 283.4832,75.4656 C292.0344,75.4656 297.9144,67.4352 297.9144,55.8432 C297.9144,43.5456 292.152,35.5151741 283.4832,35.5151741 C274.9152,35.4984 269.052,43.6632 269.052,55.608 Z\" />\n <path d=\"M392.6664,55.944 C392.6664,76.5072 380.2008,89.2752 360.0072,89.2752 C339.7128,89.2752 327.348,76.5072 327.348,55.4736 C327.348,34.5576 339.696,21.672 359.8728,21.672 C380.5536,21.672 392.6664,34.3224 392.6664,55.944 Z M344.4672,55.4736 C344.4672,67.7712 350.7,75.9192 360.0072,75.9192 C369.18,75.9192 375.5472,67.6536 375.5472,55.7088 C375.5472,43.176 369.432,35.028 360.0072,35.028 C350.7168,35.028 344.4672,43.1928 344.4672,55.4736 Z\" />\n <path d=\"M442.9992,43.3104 C442.8816,37.5144 438.8328,34.6752 430.6512,34.6752 C424.6536,34.6752 420.7392,37.044 420.7392,40.5888 C420.7392,43.1928 421.9656,44.1336 426.7368,45.5448 L448.392,51.576 C457.0776,54.0624 461.3616,59.388 461.3616,67.6536 C461.3616,73.92 458.4216,79.8336 453.5328,83.6136 C448.644,87.3936 441.672,89.2752 432.4992,89.2752 C412.44,89.2752 401.8056,82.068 401.3184,68.0064 L418.068,68.0064 C418.8072,71.4336 419.5464,72.7272 421.3776,74.0376 C423.5784,75.5832 427.0056,76.2888 431.5248,76.2888 C439.488,76.2888 444.2424,73.92 444.2424,70.0224 C444.2424,67.4352 442.7808,66.1248 438.4968,64.8312 L418.068,58.6824 C411.7176,56.6832 409.6344,55.608 407.2992,53.3736 C404.9808,50.8872 403.6368,47.2248 403.6368,42.9744 C403.6368,29.8536 414.036,21.7056 430.7856,21.7056 C448.5264,21.7056 459.2784,29.8536 459.5304,43.344 L442.9992,43.344 L442.9992,43.3104 Z\" />\n <ellipse cx=\"231.168\" cy=\"8.6688\" rx=\"8.5512\" ry=\"8.2656\" />\n </g>\n }\n</svg>\n", styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;height:var(--sui-logo-height, 24px);width:auto;flex-shrink:0}.sui-logo__svg{display:block;height:100%;width:auto;overflow:visible}.sui-logo__mark{fill:var(--sui-logo-mark-color)}.sui-logo__word{fill:var(--sui-logo-text-color)}\n"] }]
10934
+ }], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], markOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "markOnly", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], markColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "markColor", required: false }] }], textColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "textColor", required: false }] }], decorative: [{ type: i0.Input, args: [{ isSignal: true, alias: "decorative", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
10935
+
10802
10936
  /**
10803
10937
  * SUI Modal Sheet — bottom sheet con breakpoints (estilo Apple Maps / Ionic ion-modal sheet).
10804
10938
  *
@@ -10816,6 +10950,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
10816
10950
  * contenido desde scrollTop 0 (solo por handle). Aquí SÍ soportamos ese
10817
10951
  * handoff (patrón Apple Maps nativo) vía touchmove no-pasivo + takeover.
10818
10952
  *
10953
+ * ── Modelo de movimiento (2026-09) ──────────────────────────────────────────
10954
+ *
10955
+ * Dos capas: `.sui-sheet` es un marco FIJO de alto constante
10956
+ * H = min(contenido, maxBreakpoint·100dvh, viewport − safe-top − 16px), anclado
10957
+ * abajo, que recorta (radius + squircle) y no captura toques; adentro,
10958
+ * `.sui-sheet__panel` (fondo, asa y body) es lo único que se mueve, con la
10959
+ * propiedad `translate` (compositor):
10960
+ *
10961
+ * y(p) = max(0, H − p·vh) visible(p) = min(H, p·vh)
10962
+ *
10963
+ * donde vh es el alto del viewport en px. Así al 25% se ven 25dvh del sheet, la
10964
+ * parte que baja queda recortada por el marco (las esquinas inferiores
10965
+ * redondeadas siguen a la vista, como antes) y el área libre del viewport sigue
10966
+ * siendo del contenido de fondo. Misma semántica que la versión anterior, que
10967
+ * animaba `max-height`, pero sin layout por frame: durante el drag no se toca
10968
+ * ningún signal ni binding — el `translate` del panel y la opacidad del
10969
+ * backdrop se escriben directo en el DOM dentro de un requestAnimationFrame
10970
+ * coalescido (una escritura por frame, gana el último pointermove). Los signals
10971
+ * `progress`, `currentBreakpoint` y `dragging` cambian al empezar/terminar el
10972
+ * drag y al snap, no por movimiento.
10973
+ *
10974
+ * Se usa `translate` (propiedad individual) y NO `transform`, y sobre el panel
10975
+ * y no sobre `.sui-sheet`: un consumer puede seguir escribiendo su propio
10976
+ * `transform`/`left`/`width` sobre `.sui-sheet` (ej. centrarlo en desktop) sin
10977
+ * pisar el movimiento.
10978
+ *
10819
10979
  * Uso típico para tracking de pedido con mapa abajo:
10820
10980
  * ```html
10821
10981
  * <sui-modal-sheet
@@ -10831,6 +10991,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
10831
10991
  */
10832
10992
  class SuiModalSheet {
10833
10993
  doc = inject(DOCUMENT$1);
10994
+ renderer = inject(Renderer2);
10834
10995
  navbarVisibility = inject(SUI_NAVBAR_VISIBILITY, { optional: true });
10835
10996
  /** ID único por instancia para el counter centralizado del navbar. */
10836
10997
  _sheetId = `sui-modal-sheet-${Math.random().toString(36).slice(2, 11)}`;
@@ -10860,66 +11021,101 @@ class SuiModalSheet {
10860
11021
  closed = output();
10861
11022
  breakpointChange = output();
10862
11023
  // ── Refs ──────────────────────────────────────────────────────────────────
11024
+ /** Marco fijo que recorta; se mide acá (alto H). */
10863
11025
  containerRef;
11026
+ /** Capa que se mueve (`translate`). */
11027
+ panelRef;
11028
+ backdropRef;
10864
11029
  handleRef;
10865
11030
  bodyRef;
10866
11031
  // ── State ─────────────────────────────────────────────────────────────────
10867
11032
  /** Breakpoint actual (0-1). Cambia al snap, no durante el drag. */
10868
11033
  currentBreakpoint = signal(0, ...(ngDevMode ? [{ debugName: "currentBreakpoint" }] : /* istanbul ignore next */ []));
10869
- /** Progress en vivo durante el drag (0-1). Expuesto como readonly al
10870
- template (binding `--sheet-progress`) y al public para que el consumer
10871
- pueda leerlo si quiere reaccionar. */
10872
- liveProgress = signal(0, ...(ngDevMode ? [{ debugName: "liveProgress" }] : /* istanbul ignore next */ []));
10873
- progress = this.liveProgress.asReadonly();
10874
- /** True mientras el usuario está arrastrando. Desactiva CSS transition. */
11034
+ /** Progress EN REPOSO (0-1): el breakpoint al que el sheet está o hacia el
11035
+ que va. Durante el drag NO se actualiza (el movimiento vive en el DOM,
11036
+ ver header): cambia al soltar y al snap. Expuesto al template como
11037
+ `--sheet-progress` y al consumer como `progress`. */
11038
+ restProgress = signal(0, ...(ngDevMode ? [{ debugName: "restProgress" }] : /* istanbul ignore next */ []));
11039
+ progress = this.restProgress.asReadonly();
11040
+ /** True mientras el usuario está arrastrando. Se setea al arrancar y al
11041
+ soltar; la clase CSS que apaga la transición se maneja imperativa en el
11042
+ mismo tick que la escritura del `translate` (ver `beginDrag`/`snapTo`). */
10875
11043
  dragging = signal(false, ...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
10876
- /** Opacity del backdrop calculada según el progress vivo. */
10877
- backdropOpacity = computed(() => this.computeBackdropOpacity(this.liveProgress()), ...(ngDevMode ? [{ debugName: "backdropOpacity" }] : /* istanbul ignore next */ []));
11044
+ /** Opacity del backdrop para el progress en reposo. La opacidad viva del
11045
+ drag se escribe directo en el DOM; este computed queda como API. */
11046
+ backdropOpacity = computed(() => this.computeBackdropOpacity(this.restProgress()), ...(ngDevMode ? [{ debugName: "backdropOpacity" }] : /* istanbul ignore next */ []));
10878
11047
  /** True si el backdrop debe capturar pointer events (current > backdropBreakpoint). */
10879
- backdropInteractive = computed(() => this.liveProgress() > this.backdropBreakpoint(), ...(ngDevMode ? [{ debugName: "backdropInteractive" }] : /* istanbul ignore next */ []));
10880
- /** CAP de altura del sheet — `min(progress·100dvh, viewport - safe-top - 16)`.
10881
- Se bindea como max-height con `height: max-content` en el scss: el sheet
10882
- NUNCA mide más que su contenido (sin espacio vacío al final cuando el
10883
- contenido termina antes del breakpoint), y el breakpoint actúa como techo.
10884
- Cuando progress=0.25 el sheet ocupa a lo sumo 25dvh y el resto del
10885
- viewport queda VACÍO → contenido detrás (mapa) interactivo. */
10886
- heightCss = computed(() => `min(${this.liveProgress() * 100}dvh, calc(100dvh - env(safe-area-inset-top, 0px) - 16px))`, ...(ngDevMode ? [{ debugName: "heightCss" }] : /* istanbul ignore next */ []));
11048
+ backdropInteractive = computed(() => this.restProgress() > this.backdropBreakpoint(), ...(ngDevMode ? [{ debugName: "backdropInteractive" }] : /* istanbul ignore next */ []));
11049
+ /** Breakpoint máximo del array (1 si está vacío). */
11050
+ maxBreakpoint = computed(() => {
11051
+ const bps = this.breakpoints();
11052
+ return bps.length ? Math.max(...bps) : 1;
11053
+ }, ...(ngDevMode ? [{ debugName: "maxBreakpoint" }] : /* istanbul ignore next */ []));
11054
+ /** CAP ESTÁTICO de altura — `min(maxBp·100dvh, viewport − safe-top − 16)`.
11055
+ Con `height: max-content` en el scss el sheet mide su contenido y este
11056
+ techo lo acota. Depende solo de `breakpoints`: no cambia por drag ni por
11057
+ snap, así que no fuerza layout durante el gesto. */
11058
+ maxHeightCss = computed(() => `min(${this.maxBreakpoint() * 100}dvh, calc(100dvh - env(safe-area-inset-top, 0px) - 16px))`, ...(ngDevMode ? [{ debugName: "maxHeightCss" }] : /* istanbul ignore next */ []));
10887
11059
  /** True cuando el sheet está al breakpoint máximo del array. En ese punto
10888
11060
  habilitamos scroll del body (touch-action: pan-y) — el user ya no puede
10889
11061
  expandir más, así que se prioriza ver el contenido sobre el drag. En el
10890
11062
  resto de breakpoints el body actúa como handle gigante (touch-action:
10891
- none) y solo el drag controla la altura del sheet. */
11063
+ none) y solo el drag controla la posición del sheet. */
10892
11064
  atMaxBreakpoint = computed(() => {
10893
11065
  const bps = this.breakpoints();
10894
11066
  if (bps.length === 0)
10895
11067
  return false;
10896
- const maxBp = Math.max(...bps);
10897
- return this.currentBreakpoint() >= maxBp;
11068
+ return this.currentBreakpoint() >= this.maxBreakpoint();
10898
11069
  }, ...(ngDevMode ? [{ debugName: "atMaxBreakpoint" }] : /* istanbul ignore next */ []));
10899
- // ── Drag state (no signals, se manejan imperativamente) ───────────────────
11070
+ // ── Geometría / drag (imperativo, sin signals) ───────────────────────────
11071
+ /** Alto medido del sheet (px). Se mide al abrir, al empezar un drag y
11072
+ cuando el contenido cambia de tamaño (ResizeObserver). */
11073
+ sheetHeight = 0;
11074
+ /** Alto del viewport (px) = 1 unidad de progress. */
11075
+ viewportHeight = 0;
10900
11076
  dragStartY = 0;
10901
11077
  dragStartProgress = 0;
10902
- wrapperHeight = 0;
10903
11078
  pointerId = null;
10904
11079
  /** Para calcular velocity al final */
10905
11080
  lastMoveTime = 0;
10906
11081
  lastMoveY = 0;
10907
11082
  velocityY = 0;
11083
+ /** Último progress pedido por el dedo; lo consume el rAF. */
11084
+ pendingProgress = null;
11085
+ frameId = null;
10908
11086
  /** Flag para distinguir drag iniciado en body (scroll-then-drag) vs en handle.
10909
11087
  En body, el drag NO arranca con pointerdown — sólo si pointermove
10910
11088
  excede un threshold y la condición de scroll lo permite. Sirve para no
10911
11089
  robar tap/click a buttons internos. */
10912
11090
  bodyDragArmed = false;
10913
11091
  /** Threshold de movimiento (px) para decidir que un pointermove en body es
10914
- drag (no tap). Patrón iOS estándar ~6-10px. */
10915
- /* 5px = más sensible que el iOS canon de 8px. El user pidió "como nativo"
10916
- pero el threshold default del 8px sentía que tardaba en activar.
10917
- Trade-off: 5px puede activar drag con micro-movements al hacer tap, pero
10918
- la heurística shouldIgnoreBodyDrag protege inputs/select/option. */
11092
+ drag (no tap). 5px = más sensible que el iOS canon de 8px: el dueño pidió
11093
+ "como nativo" y el 8 sentía que tardaba en activar. Trade-off: 5px puede
11094
+ activar drag con micro-movements al hacer tap, pero la heurística
11095
+ shouldIgnoreBodyDrag protege inputs/select/option. */
10919
11096
  static BODY_DRAG_THRESHOLD_PX = 5;
11097
+ /** Lookahead de velocidad al soltar (ms): predice dónde estaría el dedo y
11098
+ snapea ahí. Permite que un swipe rápido brinque breakpoints sin saltarse
11099
+ los intermedios. 80ms validado en device: a 150 se saltaba el 0.7 entre
11100
+ 0.5 y 1; a 0 el sheet se sentía pesado. */
11101
+ static VELOCITY_LOOKAHEAD_MS = 80;
11102
+ /** Duración del snap: se acota entre estos dos valores según distancia
11103
+ restante / velocidad del dedo (ver `snapDuration`). */
11104
+ static SNAP_MIN_MS = 180;
11105
+ static SNAP_MAX_MS = 350;
11106
+ static CLASS_PANEL_DRAGGING = 'sui-sheet__panel--dragging';
11107
+ static CLASS_BACKDROP_DRAGGING = 'sui-sheet__backdrop--dragging';
11108
+ /** Cerrado = el panel baja todo su alto y el marco lo recorta entero. Se usa
11109
+ `100%` (y no el H medido) para que el cierre quede bien aunque el
11110
+ contenido cambie de tamaño a mitad de camino. */
11111
+ static TRANSLATE_CLOSED = '0 100%';
10920
11112
  // ── Lifecycle ─────────────────────────────────────────────────────────────
10921
11113
  wasOpen = false;
10922
11114
  escapeHandler;
11115
+ closeTimer = null;
11116
+ closeTransitionHandler;
11117
+ resizeObserver;
11118
+ windowResizeHandler;
10923
11119
  constructor() {
10924
11120
  effect(() => {
10925
11121
  const isOpen = this.open();
@@ -10935,6 +11131,9 @@ class SuiModalSheet {
10935
11131
  ngOnDestroy() {
10936
11132
  this.removeEscapeHandler();
10937
11133
  this.detachTouchSuppressor();
11134
+ this.stopObservingSize();
11135
+ this.cancelPendingClose();
11136
+ this.cancelFrame();
10938
11137
  this.unlockBodyScroll();
10939
11138
  if (this.wasOpen) {
10940
11139
  this.navbarVisibility?.release(this._sheetId);
@@ -10958,20 +11157,29 @@ class SuiModalSheet {
10958
11157
  this.lockBodyScroll();
10959
11158
  this.navbarVisibility?.requestHide(this._sheetId);
10960
11159
  this.attachEscapeHandler();
10961
- /* Setear initial breakpoint en el siguiente tick (después del render para
10962
- que el container ya tenga clientHeight). */
11160
+ /* Snap al initial breakpoint en el siguiente tick (después del render,
11161
+ cuando el container ya existe y mide). El panel nace en `translate:
11162
+ 0 100%` (scss) y la lectura de offsetHeight dentro de `snapTo` fuerza
11163
+ el recálculo de estilo que hace que la escritura del destino
11164
+ transicione: la entrada se ve deslizando desde abajo. */
10963
11165
  setTimeout(() => {
10964
- const initial = this.initialBreakpoint();
10965
- this.snapTo(initial, false);
11166
+ this.snapTo(this.initialBreakpoint(), true);
10966
11167
  this.attachTouchSuppressor();
11168
+ this.observeSize();
10967
11169
  }, 0);
10968
11170
  }
10969
11171
  onClose() {
10970
11172
  this.removeEscapeHandler();
10971
11173
  this.detachTouchSuppressor();
11174
+ this.stopObservingSize();
11175
+ this.cancelPendingClose();
11176
+ this.cancelFrame();
10972
11177
  this.unlockBodyScroll();
10973
11178
  this.navbarVisibility?.release(this._sheetId);
10974
- this.liveProgress.set(0);
11179
+ this.pointerId = null;
11180
+ this.bodyDragArmed = false;
11181
+ this.dragging.set(false);
11182
+ this.restProgress.set(0);
10975
11183
  this.currentBreakpoint.set(0);
10976
11184
  this.closed.emit();
10977
11185
  }
@@ -10988,6 +11196,8 @@ class SuiModalSheet {
10988
11196
  // Con el default prevenido, el scroll nativo nunca arranca y los pointer
10989
11197
  // events siguen fluyendo hacia la lógica de drag existente. Los touch
10990
11198
  // handlers de Angular son pasivos por default — por eso se atachan a mano.
11199
+ // El touchstart sí es pasivo (no previene nada). Los pointer events no son
11200
+ // scroll-blocking, así que `passive` no les aplica.
10991
11201
  touchStartY = 0;
10992
11202
  touchStartHandler;
10993
11203
  touchMoveHandler;
@@ -11030,43 +11240,220 @@ class SuiModalSheet {
11030
11240
  this.touchStartHandler = undefined;
11031
11241
  this.touchMoveHandler = undefined;
11032
11242
  }
11033
- // ── Drag gesture ──────────────────────────────────────────────────────────
11034
- onPointerDown(event) {
11035
- /* Solo eventos primarios (un dedo, click izquierdo). Multi-touch zoom etc.
11036
- no inicia drag. */
11037
- if (!event.isPrimary)
11243
+ // ── Medición ──────────────────────────────────────────────────────────────
11244
+ /** Mide alto del sheet y del viewport. Devuelve false si todavía no hay
11245
+ layout (container sin render o entorno sin medidas, ej. jsdom). Es la
11246
+ ÚNICA lectura de layout del gesto: se hace al abrir, al pointerdown y
11247
+ cuando cambia el tamaño — nunca por pointermove. */
11248
+ measure() {
11249
+ const container = this.containerRef?.nativeElement;
11250
+ const win = this.doc.defaultView;
11251
+ if (!container || !win)
11252
+ return false;
11253
+ this.sheetHeight = container.offsetHeight;
11254
+ this.viewportHeight = win.innerHeight || this.doc.documentElement.clientHeight;
11255
+ return this.sheetHeight > 0 && this.viewportHeight > 0;
11256
+ }
11257
+ /** Desplazamiento vertical (px) para un progress: `max(0, H − p·vh)`. */
11258
+ yFor(progress) {
11259
+ if (progress <= 0)
11260
+ return this.sheetHeight;
11261
+ return Math.max(0, this.sheetHeight - progress * this.viewportHeight);
11262
+ }
11263
+ /** Valor de `translate` para un progress. */
11264
+ translateFor(progress) {
11265
+ if (progress <= 0)
11266
+ return SuiModalSheet.TRANSLATE_CLOSED;
11267
+ return `0 ${this.yFor(progress)}px`;
11268
+ }
11269
+ /** Progress EFECTIVO de un breakpoint: el que corresponde al y que el sheet
11270
+ muestra de verdad. Con contenido corto varios breakpoints valen y = 0 y
11271
+ su progress efectivo es H/vh, no el nominal — es el punto de partida
11272
+ correcto para que el dedo mueva 1:1 desde ahí. */
11273
+ effectiveProgress(breakpoint) {
11274
+ if (this.viewportHeight === 0)
11275
+ return breakpoint;
11276
+ const p = (this.sheetHeight - this.yFor(breakpoint)) / this.viewportHeight;
11277
+ return Math.max(0, Math.min(1, p));
11278
+ }
11279
+ /** Progress real del sheet leyendo el `translate` computado del panel —
11280
+ sirve para agarrarlo a mitad de una transición sin que salte al
11281
+ breakpoint de destino. Si no se puede leer (jsdom, valor no numérico,
11282
+ un calc() a mitad de la entrada) cae al progress efectivo del
11283
+ `currentBreakpoint`. */
11284
+ progressFromDom() {
11285
+ const fallback = this.effectiveProgress(this.currentBreakpoint());
11286
+ const panel = this.panelRef?.nativeElement;
11287
+ const win = this.doc.defaultView;
11288
+ if (!panel || !win || this.viewportHeight === 0)
11289
+ return fallback;
11290
+ const raw = win.getComputedStyle(panel).translate;
11291
+ const parts = raw ? raw.trim().split(/\s+/) : [];
11292
+ const yPart = parts[1] ?? parts[0];
11293
+ if (!yPart || !yPart.endsWith('px'))
11294
+ return fallback;
11295
+ const y = parseFloat(yPart);
11296
+ if (!Number.isFinite(y))
11297
+ return fallback;
11298
+ const p = (this.sheetHeight - y) / this.viewportHeight;
11299
+ return Math.max(0, Math.min(1, p));
11300
+ }
11301
+ // ── Escrituras al DOM (sin signals) ───────────────────────────────────────
11302
+ writeTranslate(progress) {
11303
+ const panel = this.panelRef?.nativeElement;
11304
+ if (!panel)
11305
+ return;
11306
+ this.renderer.setStyle(panel, 'translate', this.translateFor(progress), RendererStyleFlags2.DashCase);
11307
+ }
11308
+ writeBackdropOpacity(progress) {
11309
+ const backdrop = this.backdropRef?.nativeElement;
11310
+ if (!backdrop)
11311
+ return;
11312
+ this.renderer.setStyle(backdrop, 'opacity', String(this.computeBackdropOpacity(progress)));
11313
+ }
11314
+ setTransitionDuration(ms) {
11315
+ const value = `${ms}ms`;
11316
+ const panel = this.panelRef?.nativeElement;
11317
+ const backdrop = this.backdropRef?.nativeElement;
11318
+ if (panel)
11319
+ this.renderer.setStyle(panel, 'transition-duration', value, RendererStyleFlags2.DashCase);
11320
+ if (backdrop)
11321
+ this.renderer.setStyle(backdrop, 'transition-duration', value, RendererStyleFlags2.DashCase);
11322
+ }
11323
+ setDraggingClasses(on) {
11324
+ const panel = this.panelRef?.nativeElement;
11325
+ const backdrop = this.backdropRef?.nativeElement;
11326
+ const op = on ? 'addClass' : 'removeClass';
11327
+ if (panel)
11328
+ this.renderer[op](panel, SuiModalSheet.CLASS_PANEL_DRAGGING);
11329
+ if (backdrop)
11330
+ this.renderer[op](backdrop, SuiModalSheet.CLASS_BACKDROP_DRAGGING);
11331
+ }
11332
+ /** Coalesce: guarda el último progress y escribe UNA vez por frame. */
11333
+ scheduleFrame(progress) {
11334
+ this.pendingProgress = progress;
11335
+ if (this.frameId !== null)
11038
11336
  return;
11039
- this.wrapperHeight = this.containerRef?.nativeElement?.clientHeight ?? 0;
11040
- if (this.wrapperHeight === 0)
11337
+ const win = this.doc.defaultView;
11338
+ if (!win || typeof win.requestAnimationFrame !== 'function') {
11339
+ this.flushFrame();
11041
11340
  return;
11341
+ }
11342
+ this.frameId = win.requestAnimationFrame(() => {
11343
+ this.frameId = null;
11344
+ this.flushFrame();
11345
+ });
11346
+ }
11347
+ flushFrame() {
11348
+ if (this.pendingProgress === null)
11349
+ return;
11350
+ const p = this.pendingProgress;
11351
+ this.pendingProgress = null;
11352
+ this.writeTranslate(p);
11353
+ this.writeBackdropOpacity(p);
11354
+ }
11355
+ cancelFrame() {
11356
+ if (this.frameId !== null) {
11357
+ this.doc.defaultView?.cancelAnimationFrame(this.frameId);
11358
+ this.frameId = null;
11359
+ }
11360
+ this.pendingProgress = null;
11361
+ }
11362
+ // ── Tamaño del contenido / viewport ───────────────────────────────────────
11363
+ //
11364
+ // El alto H entra en la fórmula del translate. Si el contenido crece después
11365
+ // de abrir (datos async, un acordeón que se expande) o el viewport cambia
11366
+ // (rotación, teclado en Android), el y viejo dejaría al sheet mostrando más
11367
+ // o menos de lo que dice su breakpoint. Se re-deriva la posición en reposo
11368
+ // sin transición.
11369
+ observeSize() {
11370
+ const container = this.containerRef?.nativeElement;
11371
+ const win = this.doc.defaultView;
11372
+ if (!container || !win)
11373
+ return;
11374
+ if (typeof ResizeObserver !== 'undefined' && !this.resizeObserver) {
11375
+ this.resizeObserver = new ResizeObserver(() => this.onSizeChange());
11376
+ this.resizeObserver.observe(container);
11377
+ }
11378
+ if (!this.windowResizeHandler) {
11379
+ this.windowResizeHandler = () => this.onSizeChange();
11380
+ win.addEventListener('resize', this.windowResizeHandler, { passive: true });
11381
+ }
11382
+ }
11383
+ stopObservingSize() {
11384
+ this.resizeObserver?.disconnect();
11385
+ this.resizeObserver = undefined;
11386
+ if (this.windowResizeHandler) {
11387
+ this.doc.defaultView?.removeEventListener('resize', this.windowResizeHandler);
11388
+ this.windowResizeHandler = undefined;
11389
+ }
11390
+ }
11391
+ onSizeChange() {
11392
+ if (this.dragging() || !this.open())
11393
+ return;
11394
+ const prevH = this.sheetHeight;
11395
+ const prevVh = this.viewportHeight;
11396
+ if (!this.measure())
11397
+ return;
11398
+ if (prevH === this.sheetHeight && prevVh === this.viewportHeight)
11399
+ return;
11400
+ const p = this.restProgress();
11401
+ if (p <= 0)
11402
+ return;
11403
+ this.setTransitionDuration(0);
11404
+ this.writeTranslate(p);
11405
+ this.writeBackdropOpacity(p);
11406
+ }
11407
+ // ── Drag gesture ──────────────────────────────────────────────────────────
11408
+ /** Arranque común del drag (handle o body ya armado): congela la transición
11409
+ en curso, lee la posición real y marca `dragging`. */
11410
+ beginDrag(event) {
11411
+ this.cancelPendingClose();
11412
+ this.cancelFrame();
11042
11413
  this.pointerId = event.pointerId;
11043
11414
  this.dragStartY = event.clientY;
11044
- this.dragStartProgress = this.currentBreakpoint();
11415
+ this.dragStartProgress = this.progressFromDom();
11045
11416
  this.lastMoveY = event.clientY;
11046
11417
  this.lastMoveTime = performance.now();
11047
11418
  this.velocityY = 0;
11419
+ /* Congelar donde está: la clase apaga la transición y el translate se
11420
+ fija en el valor actual (si se agarró a mitad de un snap). */
11421
+ this.setDraggingClasses(true);
11422
+ this.writeTranslate(this.dragStartProgress);
11423
+ this.writeBackdropOpacity(this.dragStartProgress);
11048
11424
  this.dragging.set(true);
11425
+ }
11426
+ onPointerDown(event) {
11427
+ /* Solo eventos primarios (un dedo, click izquierdo). Multi-touch zoom etc.
11428
+ no inicia drag. */
11429
+ if (!event.isPrimary)
11430
+ return;
11431
+ if (!this.measure())
11432
+ return;
11433
+ this.beginDrag(event);
11049
11434
  /* setPointerCapture en el handle hace que pointermove/pointerup sigan
11050
11435
  llegando aunque el dedo salga del elemento original. Sin esto, swipes
11051
11436
  largos pierden eventos. */
11052
11437
  const handle = this.handleRef?.nativeElement;
11053
- handle?.setPointerCapture(event.pointerId);
11438
+ try {
11439
+ handle?.setPointerCapture(event.pointerId);
11440
+ }
11441
+ catch { /* noop */ }
11054
11442
  event.preventDefault();
11055
11443
  }
11056
11444
  onPointerMove(event) {
11057
11445
  if (this.pointerId !== event.pointerId || !this.dragging())
11058
11446
  return;
11059
11447
  const deltaY = event.clientY - this.dragStartY;
11060
- /* Convertir deltaY a delta de progress: arrastrar hacia abajo (deltaY+)
11061
- reduce el progress (sheet baja). */
11062
- const deltaProgress = -deltaY / this.wrapperHeight;
11063
- const next = this.dragStartProgress + deltaProgress;
11448
+ /* 1:1 con el dedo: 1 unidad de progress = el alto del viewport. Arrastrar
11449
+ hacia abajo (deltaY+) reduce el progress (sheet baja). */
11450
+ const next = this.dragStartProgress - deltaY / this.viewportHeight;
11064
11451
  /* Clamp al rango del array de breakpoints. Min = primer breakpoint del
11065
11452
  array — si el array no incluye 0, el sheet NUNCA puede cerrarse por
11066
11453
  gesture (Apple Maps style). Max acotado a 1. */
11067
11454
  const minBp = this.breakpoints()[0] ?? 0;
11068
11455
  const clamped = Math.max(minBp, Math.min(1, next));
11069
- this.liveProgress.set(clamped);
11456
+ this.scheduleFrame(clamped);
11070
11457
  /* Velocity tracking para boost del snap */
11071
11458
  const now = performance.now();
11072
11459
  const dt = now - this.lastMoveTime;
@@ -11085,7 +11472,6 @@ class SuiModalSheet {
11085
11472
  const wasDragging = this.dragging();
11086
11473
  this.pointerId = null;
11087
11474
  this.bodyDragArmed = false;
11088
- this.dragging.set(false);
11089
11475
  const handle = this.handleRef?.nativeElement;
11090
11476
  const body = this.bodyRef?.nativeElement;
11091
11477
  try {
@@ -11098,28 +11484,32 @@ class SuiModalSheet {
11098
11484
  catch { /* noop */ }
11099
11485
  if (!wasDragging)
11100
11486
  return;
11101
- /* Aplicar boost de velocity al progress final antes de snappear. Velocity
11102
- en px/ms × (1/wrapperHeight) = progress/ms. Multiplicamos por una
11103
- constante "lookahead" que predice ~80ms en el futuro — esto permite
11104
- swipes rápidos brincar breakpoints SIN saltarse breakpoints intermedios
11105
- (ej. 0.7 entre 0.5 y 1.0). 80ms es el sweet spot validado: a 150ms se
11106
- saltaba el 0.7 con cualquier swipe medio-rápido; a 0ms el sheet se
11107
- sentía pesado y nunca brincaba breakpoints. */
11108
- const lookaheadMs = 80;
11109
- const velocityProgress = -(this.velocityY * lookaheadMs) / this.wrapperHeight;
11110
- const projected = Math.max(0, Math.min(1, this.liveProgress() + velocityProgress));
11111
- const snapBp = this.findClosestBreakpoint(projected);
11112
- this.snapTo(snapBp, true);
11487
+ /* El último move pendiente define dónde quedó el dedo. */
11488
+ const released = this.pendingProgress ?? this.progressFromDom();
11489
+ this.cancelFrame();
11490
+ /* Boost de velocity: predice ~80ms en el futuro (px/ms × ms) y snapea al
11491
+ breakpoint más cercano de ESE punto. Se decide en PÍXELES y no en
11492
+ progress: con contenido corto varios breakpoints comparten y = 0 (el
11493
+ sheet no puede mostrar más que su alto) y medir en progress cerraba el
11494
+ sheet con un arrastre mínimo desde el máximo. */
11495
+ const yReleased = this.yFor(released);
11496
+ const yProjected = Math.max(0, Math.min(this.sheetHeight, yReleased + this.velocityY * SuiModalSheet.VELOCITY_LOOKAHEAD_MS));
11497
+ const snapBp = this.closestBreakpointByY(yProjected);
11498
+ this.dragging.set(false);
11499
+ this.snapTo(snapBp, true, released, Math.abs(this.velocityY));
11113
11500
  }
11114
11501
  onPointerCancel(event) {
11115
11502
  /* Si el browser cancela el pointer (ej. scroll fight, otra app), volvemos
11116
11503
  al currentBreakpoint sin animar agresivo. */
11117
11504
  if (this.pointerId !== event.pointerId)
11118
11505
  return;
11506
+ const wasDragging = this.dragging();
11119
11507
  this.pointerId = null;
11120
11508
  this.bodyDragArmed = false;
11509
+ const released = wasDragging ? (this.pendingProgress ?? this.progressFromDom()) : this.currentBreakpoint();
11510
+ this.cancelFrame();
11121
11511
  this.dragging.set(false);
11122
- this.snapTo(this.currentBreakpoint(), true);
11512
+ this.snapTo(this.currentBreakpoint(), true, released);
11123
11513
  }
11124
11514
  // ── Body drag (scroll-then-drag canon iOS) ───────────────────────────────
11125
11515
  //
@@ -11134,8 +11524,8 @@ class SuiModalSheet {
11134
11524
  // hacia arriba: scroll body.
11135
11525
  //
11136
11526
  // Importante: el drag NO arranca en pointerdown — lo armamos pero esperamos
11137
- // a que pointermove supere un threshold (8px) antes de marcar `dragging`.
11138
- // Esto evita robarle el click/tap a buttons del body.
11527
+ // a que pointermove supere el threshold antes de marcar `dragging`. Esto
11528
+ // evita robarle el click/tap a buttons del body.
11139
11529
  onBodyPointerDown(event) {
11140
11530
  if (!event.isPrimary)
11141
11531
  return;
@@ -11144,14 +11534,12 @@ class SuiModalSheet {
11144
11534
  const target = event.target;
11145
11535
  if (this.shouldIgnoreBodyDrag(target))
11146
11536
  return;
11147
- this.wrapperHeight = this.containerRef?.nativeElement?.clientHeight ?? 0;
11148
- if (this.wrapperHeight === 0)
11537
+ if (!this.measure())
11149
11538
  return;
11150
11539
  /* Solo armamos — el drag real arranca cuando pointermove supere threshold. */
11151
11540
  this.bodyDragArmed = true;
11152
11541
  this.pointerId = event.pointerId;
11153
11542
  this.dragStartY = event.clientY;
11154
- this.dragStartProgress = this.currentBreakpoint();
11155
11543
  this.lastMoveY = event.clientY;
11156
11544
  this.lastMoveTime = performance.now();
11157
11545
  this.velocityY = 0;
@@ -11171,9 +11559,7 @@ class SuiModalSheet {
11171
11559
  const deltaY = event.clientY - this.dragStartY;
11172
11560
  if (Math.abs(deltaY) < SuiModalSheet.BODY_DRAG_THRESHOLD_PX)
11173
11561
  return;
11174
- /* Track velocity instantánea para detectar "fling down" — patrón canon
11175
- iOS / Apple Maps / Twitter X: un swipe rápido hacia abajo colapsa el
11176
- sheet incluso si el body está scrolleado en medio del contenido. */
11562
+ /* Track velocity instantánea. */
11177
11563
  const now = performance.now();
11178
11564
  const dt = now - this.lastMoveTime;
11179
11565
  if (dt > 0) {
@@ -11207,14 +11593,14 @@ class SuiModalSheet {
11207
11593
  }
11208
11594
  }
11209
11595
  this.bodyDragArmed = false;
11210
- this.dragging.set(true);
11596
+ /* El drag arranca DESDE la posición actual del dedo (touch slop, como
11597
+ UIKit): los primeros 5px no mueven el sheet en vez de hacerlo saltar. */
11598
+ this.beginDrag(event);
11211
11599
  try {
11212
11600
  body?.setPointerCapture(event.pointerId);
11213
11601
  }
11214
11602
  catch { /* noop */ }
11215
11603
  event.preventDefault();
11216
- /* Forwardear este move ya en modo drag para no perder el delta. */
11217
- this.onPointerMove(event);
11218
11604
  }
11219
11605
  /** Heurística: ignorar drag si el target es un input/textarea/select/button
11220
11606
  interactivo. El user está intentando interactuar, no arrastrar. */
@@ -11232,18 +11618,41 @@ class SuiModalSheet {
11232
11618
  return false;
11233
11619
  }
11234
11620
  // ── Snap ──────────────────────────────────────────────────────────────────
11235
- snapTo(breakpoint, animated) {
11236
- /* Si el snap es a 0, animamos pero después emitimos close. La animación de
11237
- cierre la maneja el CSS transition (350ms). */
11238
- this.liveProgress.set(breakpoint);
11621
+ /** Duración del snap en función de la distancia restante y la velocidad del
11622
+ dedo (px/ms): un fling rápido cierra la distancia en poco tiempo; un
11623
+ release lento o un snap programático usa la duración larga. Acotado a
11624
+ [180, 350] ms. */
11625
+ snapDuration(distancePx, velocityPxMs) {
11626
+ const speed = Math.max(velocityPxMs, 0.5);
11627
+ const raw = distancePx / speed;
11628
+ return Math.round(Math.max(SuiModalSheet.SNAP_MIN_MS, Math.min(SuiModalSheet.SNAP_MAX_MS, raw)));
11629
+ }
11630
+ /**
11631
+ * Lleva el sheet a `breakpoint`.
11632
+ * @param fromProgress progress desde el que sale (default: el de reposo);
11633
+ * solo influye en la duración.
11634
+ * @param velocityPxMs velocidad del dedo al soltar, para acortar el snap.
11635
+ */
11636
+ snapTo(breakpoint, animated, fromProgress, velocityPxMs = 0) {
11637
+ this.cancelPendingClose();
11638
+ this.cancelFrame();
11639
+ const measured = this.measure();
11640
+ const from = fromProgress ?? this.restProgress();
11641
+ const distance = measured ? Math.abs(this.yFor(breakpoint) - this.yFor(from)) : 0;
11642
+ const duration = animated ? this.snapDuration(distance, velocityPxMs) : 0;
11643
+ /* Todo en el mismo tick: sacar la clase que apaga la transición, fijar la
11644
+ duración y escribir el destino. El recálculo de estilo ve las tres
11645
+ cosas juntas y la transición arranca con la duración nueva. */
11646
+ this.setDraggingClasses(false);
11647
+ this.setTransitionDuration(duration);
11648
+ this.writeTranslate(breakpoint);
11649
+ this.writeBackdropOpacity(breakpoint);
11650
+ this.restProgress.set(breakpoint);
11239
11651
  if (breakpoint === 0) {
11240
- /* Esperar la transición antes de emit close para que el sheet se vea
11652
+ /* Emitir close cuando termina la transición (transitionend del
11653
+ translate) con fallback por timeout, para que el sheet se vea
11241
11654
  deslizando hacia abajo. Si !animated saltamos directo. */
11242
- const wait = animated ? 350 : 0;
11243
- setTimeout(() => {
11244
- this.currentBreakpoint.set(0);
11245
- this.open.set(false);
11246
- }, wait);
11655
+ this.scheduleClose(duration);
11247
11656
  return;
11248
11657
  }
11249
11658
  if (this.currentBreakpoint() !== breakpoint) {
@@ -11251,9 +11660,53 @@ class SuiModalSheet {
11251
11660
  this.breakpointChange.emit(breakpoint);
11252
11661
  }
11253
11662
  }
11254
- findClosestBreakpoint(progress) {
11663
+ scheduleClose(durationMs) {
11664
+ const finish = () => {
11665
+ this.cancelPendingClose();
11666
+ this.currentBreakpoint.set(0);
11667
+ this.open.set(false);
11668
+ };
11669
+ const panel = this.panelRef?.nativeElement;
11670
+ if (durationMs > 0 && panel) {
11671
+ this.closeTransitionHandler = (e) => {
11672
+ if (e.target === panel && e.propertyName === 'translate')
11673
+ finish();
11674
+ };
11675
+ panel.addEventListener('transitionend', this.closeTransitionHandler);
11676
+ }
11677
+ this.closeTimer = setTimeout(finish, durationMs > 0 ? durationMs + 80 : 0);
11678
+ }
11679
+ cancelPendingClose() {
11680
+ if (this.closeTimer !== null) {
11681
+ clearTimeout(this.closeTimer);
11682
+ this.closeTimer = null;
11683
+ }
11684
+ if (this.closeTransitionHandler) {
11685
+ this.panelRef?.nativeElement.removeEventListener('transitionend', this.closeTransitionHandler);
11686
+ this.closeTransitionHandler = undefined;
11687
+ }
11688
+ }
11689
+ /** Breakpoint cuyo desplazamiento (`yFor`) queda más cerca de `y`. Varios
11690
+ breakpoints pueden compartir el mismo y (todos los que superan el alto
11691
+ del contenido valen 0): en ese empate gana el actual si está entre
11692
+ ellos, si no el mayor — así un toque-arrastre al máximo no cambia de
11693
+ breakpoint ni apaga el scroll del body. */
11694
+ closestBreakpointByY(y) {
11255
11695
  const bps = this.breakpoints();
11256
- return bps.reduce((closest, bp) => Math.abs(bp - progress) < Math.abs(closest - progress) ? bp : closest);
11696
+ const current = this.currentBreakpoint();
11697
+ let best = bps[0] ?? 0;
11698
+ let bestDist = Infinity;
11699
+ for (const bp of bps) {
11700
+ const d = Math.abs(this.yFor(bp) - y);
11701
+ if (d < bestDist - 0.5) {
11702
+ best = bp;
11703
+ bestDist = d;
11704
+ }
11705
+ else if (Math.abs(d - bestDist) <= 0.5 && (bp === current || (best !== current && bp > best))) {
11706
+ best = bp;
11707
+ }
11708
+ }
11709
+ return best;
11257
11710
  }
11258
11711
  // ── Backdrop ──────────────────────────────────────────────────────────────
11259
11712
  /** Fórmula linear entre (backdropBreakpoint, 0) y (1, 1). Igual que Ionic. */
@@ -11297,16 +11750,22 @@ class SuiModalSheet {
11297
11750
  }
11298
11751
  }
11299
11752
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiModalSheet, deps: [], target: i0.ɵɵFactoryTarget.Component });
11300
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiModalSheet, isStandalone: true, selector: "sui-modal-sheet", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, breakpoints: { classPropertyName: "breakpoints", publicName: "breakpoints", isSignal: true, isRequired: false, transformFunction: null }, initialBreakpoint: { classPropertyName: "initialBreakpoint", publicName: "initialBreakpoint", isSignal: true, isRequired: false, transformFunction: null }, backdropBreakpoint: { classPropertyName: "backdropBreakpoint", publicName: "backdropBreakpoint", isSignal: true, isRequired: false, transformFunction: null }, showHandle: { classPropertyName: "showHandle", publicName: "showHandle", isSignal: true, isRequired: false, transformFunction: null }, closeOnBackdrop: { classPropertyName: "closeOnBackdrop", publicName: "closeOnBackdrop", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, fullBody: { classPropertyName: "fullBody", publicName: "fullBody", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", closed: "closed", breakpointChange: "breakpointChange" }, host: { properties: { "attr.data-sui-sheet-open": "open() ? \"\" : null" } }, viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["container"], descendants: true }, { propertyName: "handleRef", first: true, predicate: ["handle"], descendants: true }, { propertyName: "bodyRef", first: true, predicate: ["body"], descendants: true }], ngImport: i0, template: "@if (open()) {\n <!-- Backdrop con opacity din\u00E1mica.\n pointer-events: none cuando current \u2264 backdropBreakpoint para dejar\n interactivo el contenido debajo (ej. mapa). -->\n <div\n class=\"sui-sheet__backdrop\"\n [style.opacity]=\"backdropOpacity()\"\n [style.pointer-events]=\"backdropInteractive() ? 'auto' : 'none'\"\n (click)=\"onBackdropClick()\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Sheet container \u2014 anclado al bottom, altura din\u00E1mica.\n Usar `height` en vez de transform para que el \u00E1rea \"no cubierta\" del\n viewport (donde se ve el mapa) NO sea parte del DOM del sheet \u2014\n contenido de fondo autom\u00E1ticamente interactivo, scroll del body\n respeta la altura visible (no fantasma). -->\n <div\n #container\n class=\"sui-sheet\"\n role=\"dialog\"\n aria-modal=\"true\"\n [class.sui-sheet--dragging]=\"dragging()\"\n [style.max-height]=\"heightCss()\"\n [style.--sheet-progress]=\"liveProgress()\"\n >\n @if (showHandle()) {\n <!-- Drag handle (pill). Solo este elemento captura los pointer events\n del drag \u2014 el resto del sheet permite scroll/clicks normales. -->\n <div\n #handle\n class=\"sui-sheet__handle\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <div class=\"sui-sheet__handle-pill\"></div>\n </div>\n }\n\n <!-- Body con scroll interno. Consumer proyecta su contenido aqu\u00ED.\n Acepta drag con patr\u00F3n scroll-then-drag (iOS canon):\n - Si el body est\u00E1 scrolleado (scrollTop > 0), el drag se ignora y\n el touch hace scroll normal.\n - Si est\u00E1 en top (scrollTop === 0) y el user arrastra hacia abajo,\n se inicia drag del sheet.\n - Si est\u00E1 en max breakpoint y user arrastra hacia abajo, se inicia\n drag (incluso con scrollTop === 0 ya cubre eso).\n - Drag hacia arriba siempre permite scroll del body (no roba el gesto). -->\n <div\n #body\n class=\"sui-sheet__body\"\n [class.sui-sheet__body--full]=\"fullBody()\"\n [class.sui-sheet__body--scrollable]=\"atMaxBreakpoint()\"\n (pointerdown)=\"onBodyPointerDown($event)\"\n (pointermove)=\"onBodyPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <ng-content />\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-sheet__backdrop{position:fixed;inset:0;z-index:1000;background-color:#3333333d;transition:opacity .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging~.sui-sheet__backdrop,:host([data-sui-sheet-open]) .sui-sheet--dragging+.sui-sheet__backdrop{transition:none}.sui-sheet{position:fixed;bottom:8px;left:8px;right:8px;z-index:1001;display:flex;flex-direction:column;box-sizing:border-box;height:max-content;background:var(--sui-bg-white-0, #ffffff);border-radius:36px 36px 54px 54px;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet{--sq-t: 45px;--sq-b: 68px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to calc(100% - var(--sq-b)),curve to calc(100% - var(--sq-b)) 100% with 100% 100%/100% 100%,hline to var(--sq-b),curve to 0 calc(100% - var(--sq-b)) with 0 100%/0 100%,close);box-shadow:none!important;filter:none}}.sui-sheet{box-shadow:none;overflow:hidden;overscroll-behavior:contain;will-change:max-height;transition:max-height .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging{transition:none}:host-context(html.platform-android) .sui-sheet{border-radius:var(--sui-radius-20, 20px);--sq-t: 25px;--sq-b: 25px}.sui-sheet__handle{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:12px 0 8px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}.sui-sheet__handle:active{cursor:grabbing}.sui-sheet__handle-pill{width:36px;height:5px;border-radius:999px;background:var(--sui-bg-soft-200, #d4d4d8)}.sui-sheet__body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:none;padding:0 20px 20px}.sui-sheet__body--scrollable{touch-action:pan-y;overscroll-behavior-y:contain}.sui-sheet__body--full{padding:0}@media(max-width:767px){.sui-sheet__body{scrollbar-width:none}.sui-sheet__body::-webkit-scrollbar{display:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
11753
+ 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
11754
  }
11302
11755
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiModalSheet, decorators: [{
11303
11756
  type: Component,
11304
11757
  args: [{ selector: 'sui-modal-sheet', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, host: {
11305
11758
  '[attr.data-sui-sheet-open]': 'open() ? "" : null',
11306
- }, template: "@if (open()) {\n <!-- Backdrop con opacity din\u00E1mica.\n pointer-events: none cuando current \u2264 backdropBreakpoint para dejar\n interactivo el contenido debajo (ej. mapa). -->\n <div\n class=\"sui-sheet__backdrop\"\n [style.opacity]=\"backdropOpacity()\"\n [style.pointer-events]=\"backdropInteractive() ? 'auto' : 'none'\"\n (click)=\"onBackdropClick()\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Sheet container \u2014 anclado al bottom, altura din\u00E1mica.\n Usar `height` en vez de transform para que el \u00E1rea \"no cubierta\" del\n viewport (donde se ve el mapa) NO sea parte del DOM del sheet \u2014\n contenido de fondo autom\u00E1ticamente interactivo, scroll del body\n respeta la altura visible (no fantasma). -->\n <div\n #container\n class=\"sui-sheet\"\n role=\"dialog\"\n aria-modal=\"true\"\n [class.sui-sheet--dragging]=\"dragging()\"\n [style.max-height]=\"heightCss()\"\n [style.--sheet-progress]=\"liveProgress()\"\n >\n @if (showHandle()) {\n <!-- Drag handle (pill). Solo este elemento captura los pointer events\n del drag \u2014 el resto del sheet permite scroll/clicks normales. -->\n <div\n #handle\n class=\"sui-sheet__handle\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <div class=\"sui-sheet__handle-pill\"></div>\n </div>\n }\n\n <!-- Body con scroll interno. Consumer proyecta su contenido aqu\u00ED.\n Acepta drag con patr\u00F3n scroll-then-drag (iOS canon):\n - Si el body est\u00E1 scrolleado (scrollTop > 0), el drag se ignora y\n el touch hace scroll normal.\n - Si est\u00E1 en top (scrollTop === 0) y el user arrastra hacia abajo,\n se inicia drag del sheet.\n - Si est\u00E1 en max breakpoint y user arrastra hacia abajo, se inicia\n drag (incluso con scrollTop === 0 ya cubre eso).\n - Drag hacia arriba siempre permite scroll del body (no roba el gesto). -->\n <div\n #body\n class=\"sui-sheet__body\"\n [class.sui-sheet__body--full]=\"fullBody()\"\n [class.sui-sheet__body--scrollable]=\"atMaxBreakpoint()\"\n (pointerdown)=\"onBodyPointerDown($event)\"\n (pointermove)=\"onBodyPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerCancel($event)\"\n >\n <ng-content />\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-sheet__backdrop{position:fixed;inset:0;z-index:1000;background-color:#3333333d;transition:opacity .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging~.sui-sheet__backdrop,:host([data-sui-sheet-open]) .sui-sheet--dragging+.sui-sheet__backdrop{transition:none}.sui-sheet{position:fixed;bottom:8px;left:8px;right:8px;z-index:1001;display:flex;flex-direction:column;box-sizing:border-box;height:max-content;background:var(--sui-bg-white-0, #ffffff);border-radius:36px 36px 54px 54px;corner-shape:squircle}@supports (clip-path: shape(from 0 0,close)){.sui-sheet{--sq-t: 45px;--sq-b: 68px;clip-path:shape(from 0 var(--sq-t),curve to var(--sq-t) 0 with 0 0/0 0,hline to calc(100% - var(--sq-t)),curve to 100% var(--sq-t) with 100% 0/100% 0,vline to calc(100% - var(--sq-b)),curve to calc(100% - var(--sq-b)) 100% with 100% 100%/100% 100%,hline to var(--sq-b),curve to 0 calc(100% - var(--sq-b)) with 0 100%/0 100%,close);box-shadow:none!important;filter:none}}.sui-sheet{box-shadow:none;overflow:hidden;overscroll-behavior:contain;will-change:max-height;transition:max-height .35s cubic-bezier(.32,.72,0,1)}.sui-sheet--dragging{transition:none}:host-context(html.platform-android) .sui-sheet{border-radius:var(--sui-radius-20, 20px);--sq-t: 25px;--sq-b: 25px}.sui-sheet__handle{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:12px 0 8px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}.sui-sheet__handle:active{cursor:grabbing}.sui-sheet__handle-pill{width:36px;height:5px;border-radius:999px;background:var(--sui-bg-soft-200, #d4d4d8)}.sui-sheet__body{flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;touch-action:none;padding:0 20px 20px}.sui-sheet__body--scrollable{touch-action:pan-y;overscroll-behavior-y:contain}.sui-sheet__body--full{padding:0}@media(max-width:767px){.sui-sheet__body{scrollbar-width:none}.sui-sheet__body::-webkit-scrollbar{display:none}}\n"] }]
11759
+ }, 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
11760
  }], 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
11761
  type: ViewChild,
11309
11762
  args: ['container']
11763
+ }], panelRef: [{
11764
+ type: ViewChild,
11765
+ args: ['panel']
11766
+ }], backdropRef: [{
11767
+ type: ViewChild,
11768
+ args: ['backdrop']
11310
11769
  }], handleRef: [{
11311
11770
  type: ViewChild,
11312
11771
  args: ['handle']
@@ -15681,6 +16140,35 @@ class SuiStoreCard {
15681
16140
  isFavorite = input(false, ...(ngDevMode ? [{ debugName: "isFavorite" }] : /* istanbul ignore next */ []));
15682
16141
  /** Si true, no se navega al detalle (caso suspendido). El padre puede sobreescribir. */
15683
16142
  disableLink = input(false, ...(ngDevMode ? [{ debugName: "disableLink" }] : /* istanbul ignore next */ []));
16143
+ /**
16144
+ * El texto de Envío y el de Distancia, ya escritos por quien llama.
16145
+ *
16146
+ * ## Por qué existen: la tarjeta DIBUJA, no decide
16147
+ *
16148
+ * El costo de envío se calcula en un solo lugar de la app
16149
+ * (`StateService.computeDeliveryFee`) desde un bug real: la tarjeta decía
16150
+ * S/ 1,90 y el checkout cobraba S/ 1,50, porque cada vista lo deducía por su
16151
+ * cuenta. Un componente del design system que deduce precios es esa misma
16152
+ * trampa, un piso más abajo — y encima repartida entre todas las apps que lo
16153
+ * consuman. Lo mismo vale para la distancia, que según de dónde salga el
16154
+ * número se escribe como rango («menos de 500 m», mientras es un estimado) o
16155
+ * como número exacto («475 m», cuando la ruta ya se midió): esa distinción
16156
+ * la conoce la app, no la tarjeta.
16157
+ *
16158
+ * ## Los tres estados, y por qué son tres
16159
+ *
16160
+ * | valor | qué hace |
16161
+ * |---|---|
16162
+ * | sin pasar (`undefined`) | la tarjeta lo deduce como siempre — nada cambia para quien ya la usa |
16163
+ * | un string | se muestra tal cual |
16164
+ * | `null` | esa columna NO se renderiza (ni guion ni hueco) |
16165
+ *
16166
+ * `null` tiene que ser distinto de «no lo pasé» justamente para poder pedir
16167
+ * que el dato desaparezca. Al quedar tres columnas en vez de cuatro, la fila
16168
+ * se reparte mejor y el distrito deja de cortarse en «San Jeróni…».
16169
+ */
16170
+ deliveryText = input(...(ngDevMode ? [undefined, { debugName: "deliveryText" }] : /* istanbul ignore next */ []));
16171
+ distanceText = input(...(ngDevMode ? [undefined, { debugName: "distanceText" }] : /* istanbul ignore next */ []));
15684
16172
  toggleFavorite = output();
15685
16173
  /** Emite cuando el usuario tapea la sección de calificación. El padre debe
15686
16174
  * abrir `StoreRatingsModalService.open(id, name, logoUrl)` para mostrar
@@ -15720,7 +16208,13 @@ class SuiStoreCard {
15720
16208
  const nota = (s.rating != null && s.rating > 0 ? s.rating : 5).toFixed(2).replace(/0$/, '');
15721
16209
  return `${nota} (${n})`;
15722
16210
  }, ...(ngDevMode ? [{ debugName: "ratingLabel" }] : /* istanbul ignore next */ []));
16211
+ /** El texto de Distancia: el que le pasaron, o el que deduce del `distanceKm`
16212
+ * cuando nadie le pasó nada. `null` = no se pinta la columna (ver
16213
+ * `distanceText`). */
15723
16214
  distanceLabel = computed(() => {
16215
+ const dado = this.distanceText();
16216
+ if (dado !== undefined)
16217
+ return dado;
15724
16218
  const km = this.store().distanceKm;
15725
16219
  if (km == null)
15726
16220
  return '—';
@@ -15739,8 +16233,13 @@ class SuiStoreCard {
15739
16233
  default: return { label: 'En revisión', variant: 'pending' };
15740
16234
  }
15741
16235
  }, ...(ngDevMode ? [{ debugName: "previewBadge" }] : /* istanbul ignore next */ []));
15742
- /** Etiqueta corta de envío (Gratis/Recojo/Courier/S/X). */
16236
+ /** El texto de Envío: el que le pasaron, o la etiqueta corta que deduce del
16237
+ * `deliveryType` (Gratis/Recojo/Courier/S/X) cuando nadie le pasó nada.
16238
+ * `null` = no se pinta la columna (ver `deliveryText`). */
15743
16239
  deliveryLabel = computed(() => {
16240
+ const dado = this.deliveryText();
16241
+ if (dado !== undefined)
16242
+ return dado;
15744
16243
  const s = this.store();
15745
16244
  switch (s.deliveryType) {
15746
16245
  case 'free': return 'Gratis';
@@ -15767,12 +16266,12 @@ class SuiStoreCard {
15767
16266
  this.ratingClicked.emit({ id: s.id, name: s.name, logoUrl: s.logoUrl ?? null });
15768
16267
  }
15769
16268
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiStoreCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
15770
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiStoreCard, isStandalone: true, selector: "sui-store-card", inputs: { store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: true, transformFunction: null }, isFavorite: { classPropertyName: "isFavorite", publicName: "isFavorite", isSignal: true, isRequired: false, transformFunction: null }, disableLink: { classPropertyName: "disableLink", publicName: "disableLink", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleFavorite: "toggleFavorite", ratingClicked: "ratingClicked" }, ngImport: i0, template: "<a class=\"store\"\n [class.store--suspended]=\"store().isSuspended\"\n [class.store--closed]=\"!store().isOpen && !store().isSuspended && !store().isOwnerPreview\"\n [class.store--preview]=\"store().isOwnerPreview\"\n [routerLink]=\"link()\"\n (click)=\"onCardClick($event)\">\n\n <div class=\"store__cover\"\n [class.store__cover--fallback]=\"!store().coverUrl\">\n <!-- <img> real (no background CSS): permite retry nativo via suiImgRetry\n cuando un load falla (red flaky) + fade-in al cargar. El fallback\n oscuro queda debajo como placeholder hasta que la imagen aparece. -->\n @if (store().coverUrl) {\n <img class=\"store__cover-img\"\n suiImgRetry\n [src]=\"store().coverUrl\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\" />\n }\n <div class=\"store__cover-grad\"></div>\n\n @if (!store().isOwnerPreview) {\n <button type=\"button\"\n class=\"store__fav\"\n [class.store__fav--active]=\"isFavorite()\"\n (click)=\"onFavClick($event)\"\n aria-label=\"Favorito\">\n <sui-icon\n [name]=\"isFavorite() ? 'heart-fill' : 'heart-line'\"\n [size]=\"18\"\n color=\"var(--sui-primary-base, #fa7319)\"\n ></sui-icon>\n </button>\n }\n\n @if (store().isSuspended) {\n <span class=\"store__status store__status--suspended\">No disponible</span>\n } @else if (previewBadge(); as pb) {\n <span class=\"store__status\"\n [class.store__status--draft]=\"pb.variant === 'draft'\"\n [class.store__status--pending]=\"pb.variant === 'pending'\"\n [class.store__status--rejected]=\"pb.variant === 'rejected'\">\n {{ pb.label }}\n </span>\n } @else {\n <span class=\"store__status\"\n [class.store__status--open]=\"store().isOpen\"\n [class.store__status--closed]=\"!store().isOpen\">\n {{ store().isOpen ? 'Abierto' : 'Cerrado' }}\n </span>\n }\n </div>\n\n <div class=\"store__body\">\n <div class=\"store__logo\">\n @if (store().logoUrl) {\n <!-- suiImgRetry reintenta loads fallidos; si muere definitivo, el\n atributo data-sui-img-dead lo oculta via CSS (queda el fondo). -->\n <img suiImgRetry [src]=\"store().logoUrl\" [alt]=\"store().name\" />\n } @else {\n {{ initial() }}\n }\n </div>\n <div class=\"store__info\">\n <h3 class=\"store__name\">{{ store().name }}</h3>\n <p class=\"store__type\">{{ store().businessType }}</p>\n </div>\n\n <!-- Meta a ANCHO COMPLETO de la card (hijo directo del body con wrap):\n antes viv\u00EDa dentro de store__info y heredaba el sangrado del logo\n (60px muertos a la izquierda). -->\n @if (store().isOwnerPreview) {\n <!-- Modo preview (owner viendo borrador/revisi\u00F3n, super-admin revisando):\n solo Ubicaci\u00F3n + Env\u00EDo. Rating + Distancia no aplican antes de aprobar. -->\n <div class=\"store__meta store__meta--preview\">\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n </div>\n } @else {\n <div class=\"store__meta\">\n <button\n type=\"button\"\n class=\"store__stat store__stat--clickable\"\n (click)=\"onRatingClick($event)\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n [attr.aria-label]=\"'Ver las opiniones y la informaci\u00F3n del local'\"\n >\n <span class=\"store__stat-label\">Calificaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"star-fill\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n {{ ratingLabel() }}\n <!-- El chevron es lo que dice que la nota ABRE algo. Sin \u00E9l el\n stat se lee como dato muerto y nadie lo toca \u2014 el mismo\n remate que la ficha del local usa junto al puntaje. Va\n siempre, incluso sin opiniones: el modal tambi\u00E9n trae la\n pesta\u00F1a de informaci\u00F3n \u2014mapa, horario, direcci\u00F3n\u2014, que sirve\n igual el primer d\u00EDa del local. -->\n <sui-icon class=\"store__stat-chevron\" name=\"arrow-right-s-line\" [size]=\"14\"></sui-icon>\n </span>\n </button>\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Distancia</span>\n <span class=\"store__stat-value\">{{ distanceLabel() }}</span>\n </div>\n </div>\n }\n </div>\n</a>\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}.store{-webkit-touch-callout:none;-webkit-user-drag:none;user-select:none;-webkit-user-select:none}.store img{-webkit-user-drag:none;pointer-events:none}.store{display:block;background:var(--sui-bg-white-0, #fff);border:1px solid var(--sui-stroke-soft-200, #ebebeb);border-radius:16px;overflow:hidden;text-decoration:none;color:inherit;transition:box-shadow .2s ease,transform .2s ease;cursor:pointer}.store:active{transform:scale(.995);box-shadow:0 4px 14px #00000014}.store--suspended{cursor:not-allowed;opacity:.6}.store--closed .store__cover{filter:grayscale(1) brightness(.92);transition:filter .2s ease}.store--preview{cursor:default}.store--preview:active{transform:none;box-shadow:none}.store__cover{height:120px;position:relative;overflow:hidden;background:linear-gradient(135deg,#3a3a3a,#171717)}.store__cover-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .25s ease-out}.store__cover-img.sui-img-loaded{opacity:1}.store__cover-img[data-sui-img-dead]{display:none}.store__cover-grad{position:absolute;inset:0;background:linear-gradient(180deg,#0000 40%,#00000059);pointer-events:none}.store__fav{position:absolute;top:10px;left:10px;width:36px;height:36px;border-radius:999px;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:1;transition:background .15s ease}.store__fav:active{background:#fff}.store__status{position:absolute;top:10px;right:10px;padding:4px 10px;border-radius:999px;font-size:11px;font-weight:700;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:inline-flex;align-items:center;gap:4px;z-index:1;letter-spacing:.01em}.store__status:before{content:\"\";width:6px;height:6px;border-radius:50%;background:var(--sui-state-success-base, #22c55e)}.store__status--open{color:var(--sui-state-success-base, #16a34a)}.store__status--open:before{background:var(--sui-state-success-base, #22c55e)}.store__status--closed{color:var(--sui-state-faded-base, #94a3b8)}.store__status--closed:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--suspended{color:var(--sui-state-error-base, #dc2626)}.store__status--suspended:before{background:var(--sui-state-error-base, #dc2626)}.store__status--draft{color:var(--sui-state-faded-base, #475569);background:#fffffff5}.store__status--draft:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--pending{color:var(--sui-primary-darkest, #b85513);background:#fffffff5}.store__status--pending:before{background:var(--sui-primary-base, #fa7319);animation:store-pulse 1.6s ease-in-out infinite}.store__status--rejected{color:var(--sui-state-error-base, #b91c1c);background:#fffffff5}.store__status--rejected:before{background:var(--sui-state-error-base, #dc2626)}@keyframes store-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(1.4)}}.store__body{padding:12px 14px 14px;display:flex;flex-wrap:wrap;gap:12px;align-items:flex-start}.store__logo img[data-sui-img-dead]{display:none}.store__logo{width:48px;height:48px;border-radius:10px;background:var(--sui-static-white, #fff);border:2px solid var(--sui-static-white, #fff);box-shadow:0 1px 4px #0000001f;flex-shrink:0;margin-top:-32px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:800;color:var(--sui-primary-base, #fa7319);overflow:hidden;position:relative;z-index:2}.store__logo img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.store__info{flex:1;min-width:0}.store__name{font-size:20px;line-height:26px;font-weight:700;color:var(--sui-text-strong-950, #171717);margin:0 0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__type{font-size:14px;line-height:20px;font-weight:500;color:var(--sui-text-sub-600, #5c5c5c);margin:0 0 8px}.store__meta{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:2px;padding-top:14px;border-top:1px solid var(--sui-stroke-soft-200, #ebebeb)}.store__meta--preview{justify-content:flex-start;gap:32px}.store__stat{display:flex;flex-direction:column;gap:2px;min-width:0}.store__stat--clickable{background:transparent;border:none;padding:4px 6px;margin:-4px -6px;border-radius:8px;cursor:pointer;text-align:left;font:inherit;color:inherit;-webkit-tap-highlight-color:transparent;transition:background-color .15s}.store__stat--clickable:hover{background:var(--sui-bg-weak-50, #f5f7fa)}.store__stat--clickable:active{background:var(--sui-bg-soft-200, #ebeef2)}.store__stat-label{font-size:10px;color:var(--sui-text-soft-400, #a3a3a3);font-weight:600;text-transform:uppercase;letter-spacing:.05em}.store__stat-value{font-size:13px;font-weight:700;color:var(--sui-text-strong-950, #171717);display:inline-flex;align-items:center;gap:3px;white-space:nowrap}.store__stat-value svg{color:var(--sui-primary-base, #fa7319);flex-shrink:0}.store__stat--elastico{overflow:hidden}.store__stat--elastico .store__stat-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__stat--elastico .store__stat-texto{overflow:hidden;text-overflow:ellipsis;min-width:0}.store__stat-chevron{color:var(--sui-text-soft-400, #a3a3a3);margin-left:-1px}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "directive", type: SuiImgRetry, selector: "img[suiImgRetry]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
16269
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiStoreCard, isStandalone: true, selector: "sui-store-card", inputs: { store: { classPropertyName: "store", publicName: "store", isSignal: true, isRequired: true, transformFunction: null }, isFavorite: { classPropertyName: "isFavorite", publicName: "isFavorite", isSignal: true, isRequired: false, transformFunction: null }, disableLink: { classPropertyName: "disableLink", publicName: "disableLink", isSignal: true, isRequired: false, transformFunction: null }, deliveryText: { classPropertyName: "deliveryText", publicName: "deliveryText", isSignal: true, isRequired: false, transformFunction: null }, distanceText: { classPropertyName: "distanceText", publicName: "distanceText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleFavorite: "toggleFavorite", ratingClicked: "ratingClicked" }, ngImport: i0, template: "<a class=\"store\"\n [class.store--suspended]=\"store().isSuspended\"\n [class.store--closed]=\"!store().isOpen && !store().isSuspended && !store().isOwnerPreview\"\n [class.store--preview]=\"store().isOwnerPreview\"\n [routerLink]=\"link()\"\n (click)=\"onCardClick($event)\">\n\n <div class=\"store__cover\"\n [class.store__cover--fallback]=\"!store().coverUrl\">\n <!-- <img> real (no background CSS): permite retry nativo via suiImgRetry\n cuando un load falla (red flaky) + fade-in al cargar. El fallback\n oscuro queda debajo como placeholder hasta que la imagen aparece. -->\n @if (store().coverUrl) {\n <img class=\"store__cover-img\"\n suiImgRetry\n [src]=\"store().coverUrl\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\" />\n }\n <div class=\"store__cover-grad\"></div>\n\n @if (!store().isOwnerPreview) {\n <button type=\"button\"\n class=\"store__fav\"\n [class.store__fav--active]=\"isFavorite()\"\n (click)=\"onFavClick($event)\"\n aria-label=\"Favorito\">\n <sui-icon\n [name]=\"isFavorite() ? 'heart-fill' : 'heart-line'\"\n [size]=\"18\"\n color=\"var(--sui-primary-base, #fa7319)\"\n ></sui-icon>\n </button>\n }\n\n @if (store().isSuspended) {\n <span class=\"store__status store__status--suspended\">No disponible</span>\n } @else if (previewBadge(); as pb) {\n <span class=\"store__status\"\n [class.store__status--draft]=\"pb.variant === 'draft'\"\n [class.store__status--pending]=\"pb.variant === 'pending'\"\n [class.store__status--rejected]=\"pb.variant === 'rejected'\">\n {{ pb.label }}\n </span>\n } @else {\n <span class=\"store__status\"\n [class.store__status--open]=\"store().isOpen\"\n [class.store__status--closed]=\"!store().isOpen\">\n {{ store().isOpen ? 'Abierto' : 'Cerrado' }}\n </span>\n }\n </div>\n\n <div class=\"store__body\">\n <div class=\"store__logo\">\n @if (store().logoUrl) {\n <!-- suiImgRetry reintenta loads fallidos; si muere definitivo, el\n atributo data-sui-img-dead lo oculta via CSS (queda el fondo). -->\n <img suiImgRetry [src]=\"store().logoUrl\" [alt]=\"store().name\" />\n } @else {\n {{ initial() }}\n }\n </div>\n <div class=\"store__info\">\n <h3 class=\"store__name\">{{ store().name }}</h3>\n <p class=\"store__type\">{{ store().businessType }}</p>\n </div>\n\n <!-- Meta a ANCHO COMPLETO de la card (hijo directo del body con wrap):\n antes viv\u00EDa dentro de store__info y heredaba el sangrado del logo\n (60px muertos a la izquierda). -->\n @if (store().isOwnerPreview) {\n <!-- Modo preview (owner viendo borrador/revisi\u00F3n, super-admin revisando):\n solo Ubicaci\u00F3n + Env\u00EDo. Rating + Distancia no aplican antes de aprobar. -->\n <div class=\"store__meta store__meta--preview\">\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <!-- `null` en `deliveryText` = esta columna no existe, y no un guion:\n un hueco rotulado \u00ABEnv\u00EDo\u00BB sobre nada se lee como dato faltante.\n Quien no pasa nada sigue viendo la etiqueta deducida. -->\n @if (deliveryLabel() !== null) {\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n }\n </div>\n } @else {\n <div class=\"store__meta\">\n <button\n type=\"button\"\n class=\"store__stat store__stat--clickable\"\n (click)=\"onRatingClick($event)\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n [attr.aria-label]=\"'Ver las opiniones y la informaci\u00F3n del local'\"\n >\n <span class=\"store__stat-label\">Calificaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"star-fill\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n {{ ratingLabel() }}\n <!-- El chevron es lo que dice que la nota ABRE algo. Sin \u00E9l el\n stat se lee como dato muerto y nadie lo toca \u2014 el mismo\n remate que la ficha del local usa junto al puntaje. Va\n siempre, incluso sin opiniones: el modal tambi\u00E9n trae la\n pesta\u00F1a de informaci\u00F3n \u2014mapa, horario, direcci\u00F3n\u2014, que sirve\n igual el primer d\u00EDa del local. -->\n <sui-icon class=\"store__stat-chevron\" name=\"arrow-right-s-line\" [size]=\"14\"></sui-icon>\n </span>\n </button>\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <!-- Las dos columnas de la derecha desaparecen con `null` (ver\n `deliveryText`/`distanceText` en el .ts): con tres columnas el\n reparto sobra y el distrito deja de recortarse. -->\n @if (deliveryLabel() !== null) {\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n }\n @if (distanceLabel() !== null) {\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Distancia</span>\n <span class=\"store__stat-value\">{{ distanceLabel() }}</span>\n </div>\n }\n </div>\n }\n </div>\n</a>\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}.store{-webkit-touch-callout:none;-webkit-user-drag:none;user-select:none;-webkit-user-select:none}.store img{-webkit-user-drag:none;pointer-events:none}.store{display:block;background:var(--sui-bg-white-0, #fff);border:1px solid var(--sui-stroke-soft-200, #ebebeb);border-radius:16px;overflow:hidden;text-decoration:none;color:inherit;transition:box-shadow .2s ease,transform .2s ease;cursor:pointer}.store:active{transform:scale(.995);box-shadow:0 4px 14px #00000014}.store--suspended{cursor:not-allowed;opacity:.6}.store--closed .store__cover{filter:grayscale(1) brightness(.92);transition:filter .2s ease}.store--preview{cursor:default}.store--preview:active{transform:none;box-shadow:none}.store__cover{height:120px;position:relative;overflow:hidden;background:linear-gradient(135deg,#3a3a3a,#171717)}.store__cover-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .25s ease-out}.store__cover-img.sui-img-loaded{opacity:1}.store__cover-img[data-sui-img-dead]{display:none}.store__cover-grad{position:absolute;inset:0;background:linear-gradient(180deg,#0000 40%,#00000059);pointer-events:none}.store__fav{position:absolute;top:10px;left:10px;width:36px;height:36px;border-radius:999px;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:1;transition:background .15s ease}.store__fav:active{background:#fff}.store__status{position:absolute;top:10px;right:10px;padding:4px 10px;border-radius:999px;font-size:11px;font-weight:700;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:inline-flex;align-items:center;gap:4px;z-index:1;letter-spacing:.01em}.store__status:before{content:\"\";width:6px;height:6px;border-radius:50%;background:var(--sui-state-success-base, #22c55e)}.store__status--open{color:var(--sui-state-success-base, #16a34a)}.store__status--open:before{background:var(--sui-state-success-base, #22c55e)}.store__status--closed{color:var(--sui-state-faded-base, #94a3b8)}.store__status--closed:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--suspended{color:var(--sui-state-error-base, #dc2626)}.store__status--suspended:before{background:var(--sui-state-error-base, #dc2626)}.store__status--draft{color:var(--sui-state-faded-base, #475569);background:#fffffff5}.store__status--draft:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--pending{color:var(--sui-primary-darkest, #b85513);background:#fffffff5}.store__status--pending:before{background:var(--sui-primary-base, #fa7319);animation:store-pulse 1.6s ease-in-out infinite}.store__status--rejected{color:var(--sui-state-error-base, #b91c1c);background:#fffffff5}.store__status--rejected:before{background:var(--sui-state-error-base, #dc2626)}@keyframes store-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(1.4)}}.store__body{padding:12px 14px 14px;display:flex;flex-wrap:wrap;gap:12px;align-items:flex-start}.store__logo img[data-sui-img-dead]{display:none}.store__logo{width:48px;height:48px;border-radius:10px;background:var(--sui-static-white, #fff);border:2px solid var(--sui-static-white, #fff);box-shadow:0 1px 4px #0000001f;flex-shrink:0;margin-top:-32px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:800;color:var(--sui-primary-base, #fa7319);overflow:hidden;position:relative;z-index:2}.store__logo img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.store__info{flex:1;min-width:0}.store__name{font-size:20px;line-height:26px;font-weight:700;color:var(--sui-text-strong-950, #171717);margin:0 0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__type{font-size:14px;line-height:20px;font-weight:500;color:var(--sui-text-sub-600, #5c5c5c);margin:0 0 8px}.store__meta{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:2px;padding-top:14px;border-top:1px solid var(--sui-stroke-soft-200, #ebebeb)}.store__meta--preview{justify-content:flex-start;gap:32px}.store__stat{display:flex;flex-direction:column;gap:2px;min-width:0}.store__stat--clickable{background:transparent;border:none;padding:4px 6px;margin:-4px -6px;border-radius:8px;cursor:pointer;text-align:left;font:inherit;color:inherit;-webkit-tap-highlight-color:transparent;transition:background-color .15s}.store__stat--clickable:hover{background:var(--sui-bg-weak-50, #f5f7fa)}.store__stat--clickable:active{background:var(--sui-bg-soft-200, #ebeef2)}.store__stat-label{font-size:10px;color:var(--sui-text-soft-400, #a3a3a3);font-weight:600;text-transform:uppercase;letter-spacing:.05em}.store__stat-value{font-size:13px;font-weight:700;color:var(--sui-text-strong-950, #171717);display:inline-flex;align-items:center;gap:3px;white-space:nowrap}.store__stat-value svg{color:var(--sui-primary-base, #fa7319);flex-shrink:0}.store__stat--elastico{overflow:hidden}.store__stat--elastico .store__stat-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__stat--elastico .store__stat-texto{overflow:hidden;text-overflow:ellipsis;min-width:0}.store__stat-chevron{color:var(--sui-text-soft-400, #a3a3a3);margin-left:-1px}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "directive", type: SuiImgRetry, selector: "img[suiImgRetry]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
15771
16270
  }
15772
16271
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiStoreCard, decorators: [{
15773
16272
  type: Component,
15774
- args: [{ selector: 'sui-store-card', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink, SuiIcon, SuiImgRetry], template: "<a class=\"store\"\n [class.store--suspended]=\"store().isSuspended\"\n [class.store--closed]=\"!store().isOpen && !store().isSuspended && !store().isOwnerPreview\"\n [class.store--preview]=\"store().isOwnerPreview\"\n [routerLink]=\"link()\"\n (click)=\"onCardClick($event)\">\n\n <div class=\"store__cover\"\n [class.store__cover--fallback]=\"!store().coverUrl\">\n <!-- <img> real (no background CSS): permite retry nativo via suiImgRetry\n cuando un load falla (red flaky) + fade-in al cargar. El fallback\n oscuro queda debajo como placeholder hasta que la imagen aparece. -->\n @if (store().coverUrl) {\n <img class=\"store__cover-img\"\n suiImgRetry\n [src]=\"store().coverUrl\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\" />\n }\n <div class=\"store__cover-grad\"></div>\n\n @if (!store().isOwnerPreview) {\n <button type=\"button\"\n class=\"store__fav\"\n [class.store__fav--active]=\"isFavorite()\"\n (click)=\"onFavClick($event)\"\n aria-label=\"Favorito\">\n <sui-icon\n [name]=\"isFavorite() ? 'heart-fill' : 'heart-line'\"\n [size]=\"18\"\n color=\"var(--sui-primary-base, #fa7319)\"\n ></sui-icon>\n </button>\n }\n\n @if (store().isSuspended) {\n <span class=\"store__status store__status--suspended\">No disponible</span>\n } @else if (previewBadge(); as pb) {\n <span class=\"store__status\"\n [class.store__status--draft]=\"pb.variant === 'draft'\"\n [class.store__status--pending]=\"pb.variant === 'pending'\"\n [class.store__status--rejected]=\"pb.variant === 'rejected'\">\n {{ pb.label }}\n </span>\n } @else {\n <span class=\"store__status\"\n [class.store__status--open]=\"store().isOpen\"\n [class.store__status--closed]=\"!store().isOpen\">\n {{ store().isOpen ? 'Abierto' : 'Cerrado' }}\n </span>\n }\n </div>\n\n <div class=\"store__body\">\n <div class=\"store__logo\">\n @if (store().logoUrl) {\n <!-- suiImgRetry reintenta loads fallidos; si muere definitivo, el\n atributo data-sui-img-dead lo oculta via CSS (queda el fondo). -->\n <img suiImgRetry [src]=\"store().logoUrl\" [alt]=\"store().name\" />\n } @else {\n {{ initial() }}\n }\n </div>\n <div class=\"store__info\">\n <h3 class=\"store__name\">{{ store().name }}</h3>\n <p class=\"store__type\">{{ store().businessType }}</p>\n </div>\n\n <!-- Meta a ANCHO COMPLETO de la card (hijo directo del body con wrap):\n antes viv\u00EDa dentro de store__info y heredaba el sangrado del logo\n (60px muertos a la izquierda). -->\n @if (store().isOwnerPreview) {\n <!-- Modo preview (owner viendo borrador/revisi\u00F3n, super-admin revisando):\n solo Ubicaci\u00F3n + Env\u00EDo. Rating + Distancia no aplican antes de aprobar. -->\n <div class=\"store__meta store__meta--preview\">\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n </div>\n } @else {\n <div class=\"store__meta\">\n <button\n type=\"button\"\n class=\"store__stat store__stat--clickable\"\n (click)=\"onRatingClick($event)\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n [attr.aria-label]=\"'Ver las opiniones y la informaci\u00F3n del local'\"\n >\n <span class=\"store__stat-label\">Calificaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"star-fill\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n {{ ratingLabel() }}\n <!-- El chevron es lo que dice que la nota ABRE algo. Sin \u00E9l el\n stat se lee como dato muerto y nadie lo toca \u2014 el mismo\n remate que la ficha del local usa junto al puntaje. Va\n siempre, incluso sin opiniones: el modal tambi\u00E9n trae la\n pesta\u00F1a de informaci\u00F3n \u2014mapa, horario, direcci\u00F3n\u2014, que sirve\n igual el primer d\u00EDa del local. -->\n <sui-icon class=\"store__stat-chevron\" name=\"arrow-right-s-line\" [size]=\"14\"></sui-icon>\n </span>\n </button>\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Distancia</span>\n <span class=\"store__stat-value\">{{ distanceLabel() }}</span>\n </div>\n </div>\n }\n </div>\n</a>\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}.store{-webkit-touch-callout:none;-webkit-user-drag:none;user-select:none;-webkit-user-select:none}.store img{-webkit-user-drag:none;pointer-events:none}.store{display:block;background:var(--sui-bg-white-0, #fff);border:1px solid var(--sui-stroke-soft-200, #ebebeb);border-radius:16px;overflow:hidden;text-decoration:none;color:inherit;transition:box-shadow .2s ease,transform .2s ease;cursor:pointer}.store:active{transform:scale(.995);box-shadow:0 4px 14px #00000014}.store--suspended{cursor:not-allowed;opacity:.6}.store--closed .store__cover{filter:grayscale(1) brightness(.92);transition:filter .2s ease}.store--preview{cursor:default}.store--preview:active{transform:none;box-shadow:none}.store__cover{height:120px;position:relative;overflow:hidden;background:linear-gradient(135deg,#3a3a3a,#171717)}.store__cover-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .25s ease-out}.store__cover-img.sui-img-loaded{opacity:1}.store__cover-img[data-sui-img-dead]{display:none}.store__cover-grad{position:absolute;inset:0;background:linear-gradient(180deg,#0000 40%,#00000059);pointer-events:none}.store__fav{position:absolute;top:10px;left:10px;width:36px;height:36px;border-radius:999px;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:1;transition:background .15s ease}.store__fav:active{background:#fff}.store__status{position:absolute;top:10px;right:10px;padding:4px 10px;border-radius:999px;font-size:11px;font-weight:700;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:inline-flex;align-items:center;gap:4px;z-index:1;letter-spacing:.01em}.store__status:before{content:\"\";width:6px;height:6px;border-radius:50%;background:var(--sui-state-success-base, #22c55e)}.store__status--open{color:var(--sui-state-success-base, #16a34a)}.store__status--open:before{background:var(--sui-state-success-base, #22c55e)}.store__status--closed{color:var(--sui-state-faded-base, #94a3b8)}.store__status--closed:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--suspended{color:var(--sui-state-error-base, #dc2626)}.store__status--suspended:before{background:var(--sui-state-error-base, #dc2626)}.store__status--draft{color:var(--sui-state-faded-base, #475569);background:#fffffff5}.store__status--draft:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--pending{color:var(--sui-primary-darkest, #b85513);background:#fffffff5}.store__status--pending:before{background:var(--sui-primary-base, #fa7319);animation:store-pulse 1.6s ease-in-out infinite}.store__status--rejected{color:var(--sui-state-error-base, #b91c1c);background:#fffffff5}.store__status--rejected:before{background:var(--sui-state-error-base, #dc2626)}@keyframes store-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(1.4)}}.store__body{padding:12px 14px 14px;display:flex;flex-wrap:wrap;gap:12px;align-items:flex-start}.store__logo img[data-sui-img-dead]{display:none}.store__logo{width:48px;height:48px;border-radius:10px;background:var(--sui-static-white, #fff);border:2px solid var(--sui-static-white, #fff);box-shadow:0 1px 4px #0000001f;flex-shrink:0;margin-top:-32px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:800;color:var(--sui-primary-base, #fa7319);overflow:hidden;position:relative;z-index:2}.store__logo img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.store__info{flex:1;min-width:0}.store__name{font-size:20px;line-height:26px;font-weight:700;color:var(--sui-text-strong-950, #171717);margin:0 0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__type{font-size:14px;line-height:20px;font-weight:500;color:var(--sui-text-sub-600, #5c5c5c);margin:0 0 8px}.store__meta{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:2px;padding-top:14px;border-top:1px solid var(--sui-stroke-soft-200, #ebebeb)}.store__meta--preview{justify-content:flex-start;gap:32px}.store__stat{display:flex;flex-direction:column;gap:2px;min-width:0}.store__stat--clickable{background:transparent;border:none;padding:4px 6px;margin:-4px -6px;border-radius:8px;cursor:pointer;text-align:left;font:inherit;color:inherit;-webkit-tap-highlight-color:transparent;transition:background-color .15s}.store__stat--clickable:hover{background:var(--sui-bg-weak-50, #f5f7fa)}.store__stat--clickable:active{background:var(--sui-bg-soft-200, #ebeef2)}.store__stat-label{font-size:10px;color:var(--sui-text-soft-400, #a3a3a3);font-weight:600;text-transform:uppercase;letter-spacing:.05em}.store__stat-value{font-size:13px;font-weight:700;color:var(--sui-text-strong-950, #171717);display:inline-flex;align-items:center;gap:3px;white-space:nowrap}.store__stat-value svg{color:var(--sui-primary-base, #fa7319);flex-shrink:0}.store__stat--elastico{overflow:hidden}.store__stat--elastico .store__stat-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__stat--elastico .store__stat-texto{overflow:hidden;text-overflow:ellipsis;min-width:0}.store__stat-chevron{color:var(--sui-text-soft-400, #a3a3a3);margin-left:-1px}\n"] }]
15775
- }], propDecorators: { store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: true }] }], isFavorite: [{ type: i0.Input, args: [{ isSignal: true, alias: "isFavorite", required: false }] }], disableLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableLink", required: false }] }], toggleFavorite: [{ type: i0.Output, args: ["toggleFavorite"] }], ratingClicked: [{ type: i0.Output, args: ["ratingClicked"] }] } });
16273
+ args: [{ selector: 'sui-store-card', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink, SuiIcon, SuiImgRetry], template: "<a class=\"store\"\n [class.store--suspended]=\"store().isSuspended\"\n [class.store--closed]=\"!store().isOpen && !store().isSuspended && !store().isOwnerPreview\"\n [class.store--preview]=\"store().isOwnerPreview\"\n [routerLink]=\"link()\"\n (click)=\"onCardClick($event)\">\n\n <div class=\"store__cover\"\n [class.store__cover--fallback]=\"!store().coverUrl\">\n <!-- <img> real (no background CSS): permite retry nativo via suiImgRetry\n cuando un load falla (red flaky) + fade-in al cargar. El fallback\n oscuro queda debajo como placeholder hasta que la imagen aparece. -->\n @if (store().coverUrl) {\n <img class=\"store__cover-img\"\n suiImgRetry\n [src]=\"store().coverUrl\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\" />\n }\n <div class=\"store__cover-grad\"></div>\n\n @if (!store().isOwnerPreview) {\n <button type=\"button\"\n class=\"store__fav\"\n [class.store__fav--active]=\"isFavorite()\"\n (click)=\"onFavClick($event)\"\n aria-label=\"Favorito\">\n <sui-icon\n [name]=\"isFavorite() ? 'heart-fill' : 'heart-line'\"\n [size]=\"18\"\n color=\"var(--sui-primary-base, #fa7319)\"\n ></sui-icon>\n </button>\n }\n\n @if (store().isSuspended) {\n <span class=\"store__status store__status--suspended\">No disponible</span>\n } @else if (previewBadge(); as pb) {\n <span class=\"store__status\"\n [class.store__status--draft]=\"pb.variant === 'draft'\"\n [class.store__status--pending]=\"pb.variant === 'pending'\"\n [class.store__status--rejected]=\"pb.variant === 'rejected'\">\n {{ pb.label }}\n </span>\n } @else {\n <span class=\"store__status\"\n [class.store__status--open]=\"store().isOpen\"\n [class.store__status--closed]=\"!store().isOpen\">\n {{ store().isOpen ? 'Abierto' : 'Cerrado' }}\n </span>\n }\n </div>\n\n <div class=\"store__body\">\n <div class=\"store__logo\">\n @if (store().logoUrl) {\n <!-- suiImgRetry reintenta loads fallidos; si muere definitivo, el\n atributo data-sui-img-dead lo oculta via CSS (queda el fondo). -->\n <img suiImgRetry [src]=\"store().logoUrl\" [alt]=\"store().name\" />\n } @else {\n {{ initial() }}\n }\n </div>\n <div class=\"store__info\">\n <h3 class=\"store__name\">{{ store().name }}</h3>\n <p class=\"store__type\">{{ store().businessType }}</p>\n </div>\n\n <!-- Meta a ANCHO COMPLETO de la card (hijo directo del body con wrap):\n antes viv\u00EDa dentro de store__info y heredaba el sangrado del logo\n (60px muertos a la izquierda). -->\n @if (store().isOwnerPreview) {\n <!-- Modo preview (owner viendo borrador/revisi\u00F3n, super-admin revisando):\n solo Ubicaci\u00F3n + Env\u00EDo. Rating + Distancia no aplican antes de aprobar. -->\n <div class=\"store__meta store__meta--preview\">\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <!-- `null` en `deliveryText` = esta columna no existe, y no un guion:\n un hueco rotulado \u00ABEnv\u00EDo\u00BB sobre nada se lee como dato faltante.\n Quien no pasa nada sigue viendo la etiqueta deducida. -->\n @if (deliveryLabel() !== null) {\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n }\n </div>\n } @else {\n <div class=\"store__meta\">\n <button\n type=\"button\"\n class=\"store__stat store__stat--clickable\"\n (click)=\"onRatingClick($event)\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n [attr.aria-label]=\"'Ver las opiniones y la informaci\u00F3n del local'\"\n >\n <span class=\"store__stat-label\">Calificaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"star-fill\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n {{ ratingLabel() }}\n <!-- El chevron es lo que dice que la nota ABRE algo. Sin \u00E9l el\n stat se lee como dato muerto y nadie lo toca \u2014 el mismo\n remate que la ficha del local usa junto al puntaje. Va\n siempre, incluso sin opiniones: el modal tambi\u00E9n trae la\n pesta\u00F1a de informaci\u00F3n \u2014mapa, horario, direcci\u00F3n\u2014, que sirve\n igual el primer d\u00EDa del local. -->\n <sui-icon class=\"store__stat-chevron\" name=\"arrow-right-s-line\" [size]=\"14\"></sui-icon>\n </span>\n </button>\n <!-- El distrito es el \u00FAnico dato de largo variable de la fila, as\u00ED que\n es el que cede: ver \u00ABSan Jer\u00F3ni\u2026\u00BB cuesta menos que ver los cuatro\n stats pis\u00E1ndose. Por eso lleva `--elastico`. -->\n <div class=\"store__stat store__stat--elastico\">\n <span class=\"store__stat-label\">Ubicaci\u00F3n</span>\n <span class=\"store__stat-value\">\n <sui-icon name=\"map-pin-line\" [size]=\"13\" color=\"var(--sui-primary-base, #fa7319)\"></sui-icon>\n <span class=\"store__stat-texto\">{{ store().district || '\u2014' }}</span>\n </span>\n </div>\n <!-- Las dos columnas de la derecha desaparecen con `null` (ver\n `deliveryText`/`distanceText` en el .ts): con tres columnas el\n reparto sobra y el distrito deja de recortarse. -->\n @if (deliveryLabel() !== null) {\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Env\u00EDo</span>\n <span class=\"store__stat-value\">{{ deliveryLabel() }}</span>\n </div>\n }\n @if (distanceLabel() !== null) {\n <div class=\"store__stat\">\n <span class=\"store__stat-label\">Distancia</span>\n <span class=\"store__stat-value\">{{ distanceLabel() }}</span>\n </div>\n }\n </div>\n }\n </div>\n</a>\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}.store{-webkit-touch-callout:none;-webkit-user-drag:none;user-select:none;-webkit-user-select:none}.store img{-webkit-user-drag:none;pointer-events:none}.store{display:block;background:var(--sui-bg-white-0, #fff);border:1px solid var(--sui-stroke-soft-200, #ebebeb);border-radius:16px;overflow:hidden;text-decoration:none;color:inherit;transition:box-shadow .2s ease,transform .2s ease;cursor:pointer}.store:active{transform:scale(.995);box-shadow:0 4px 14px #00000014}.store--suspended{cursor:not-allowed;opacity:.6}.store--closed .store__cover{filter:grayscale(1) brightness(.92);transition:filter .2s ease}.store--preview{cursor:default}.store--preview:active{transform:none;box-shadow:none}.store__cover{height:120px;position:relative;overflow:hidden;background:linear-gradient(135deg,#3a3a3a,#171717)}.store__cover-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .25s ease-out}.store__cover-img.sui-img-loaded{opacity:1}.store__cover-img[data-sui-img-dead]{display:none}.store__cover-grad{position:absolute;inset:0;background:linear-gradient(180deg,#0000 40%,#00000059);pointer-events:none}.store__fav{position:absolute;top:10px;left:10px;width:36px;height:36px;border-radius:999px;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:1;transition:background .15s ease}.store__fav:active{background:#fff}.store__status{position:absolute;top:10px;right:10px;padding:4px 10px;border-radius:999px;font-size:11px;font-weight:700;background:#ffffffeb;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);display:inline-flex;align-items:center;gap:4px;z-index:1;letter-spacing:.01em}.store__status:before{content:\"\";width:6px;height:6px;border-radius:50%;background:var(--sui-state-success-base, #22c55e)}.store__status--open{color:var(--sui-state-success-base, #16a34a)}.store__status--open:before{background:var(--sui-state-success-base, #22c55e)}.store__status--closed{color:var(--sui-state-faded-base, #94a3b8)}.store__status--closed:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--suspended{color:var(--sui-state-error-base, #dc2626)}.store__status--suspended:before{background:var(--sui-state-error-base, #dc2626)}.store__status--draft{color:var(--sui-state-faded-base, #475569);background:#fffffff5}.store__status--draft:before{background:var(--sui-state-faded-base, #94a3b8)}.store__status--pending{color:var(--sui-primary-darkest, #b85513);background:#fffffff5}.store__status--pending:before{background:var(--sui-primary-base, #fa7319);animation:store-pulse 1.6s ease-in-out infinite}.store__status--rejected{color:var(--sui-state-error-base, #b91c1c);background:#fffffff5}.store__status--rejected:before{background:var(--sui-state-error-base, #dc2626)}@keyframes store-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(1.4)}}.store__body{padding:12px 14px 14px;display:flex;flex-wrap:wrap;gap:12px;align-items:flex-start}.store__logo img[data-sui-img-dead]{display:none}.store__logo{width:48px;height:48px;border-radius:10px;background:var(--sui-static-white, #fff);border:2px solid var(--sui-static-white, #fff);box-shadow:0 1px 4px #0000001f;flex-shrink:0;margin-top:-32px;display:flex;align-items:center;justify-content:center;font-size:18px;font-weight:800;color:var(--sui-primary-base, #fa7319);overflow:hidden;position:relative;z-index:2}.store__logo img{width:100%;height:100%;object-fit:cover;border-radius:inherit}.store__info{flex:1;min-width:0}.store__name{font-size:20px;line-height:26px;font-weight:700;color:var(--sui-text-strong-950, #171717);margin:0 0 4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__type{font-size:14px;line-height:20px;font-weight:500;color:var(--sui-text-sub-600, #5c5c5c);margin:0 0 8px}.store__meta{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:2px;padding-top:14px;border-top:1px solid var(--sui-stroke-soft-200, #ebebeb)}.store__meta--preview{justify-content:flex-start;gap:32px}.store__stat{display:flex;flex-direction:column;gap:2px;min-width:0}.store__stat--clickable{background:transparent;border:none;padding:4px 6px;margin:-4px -6px;border-radius:8px;cursor:pointer;text-align:left;font:inherit;color:inherit;-webkit-tap-highlight-color:transparent;transition:background-color .15s}.store__stat--clickable:hover{background:var(--sui-bg-weak-50, #f5f7fa)}.store__stat--clickable:active{background:var(--sui-bg-soft-200, #ebeef2)}.store__stat-label{font-size:10px;color:var(--sui-text-soft-400, #a3a3a3);font-weight:600;text-transform:uppercase;letter-spacing:.05em}.store__stat-value{font-size:13px;font-weight:700;color:var(--sui-text-strong-950, #171717);display:inline-flex;align-items:center;gap:3px;white-space:nowrap}.store__stat-value svg{color:var(--sui-primary-base, #fa7319);flex-shrink:0}.store__stat--elastico{overflow:hidden}.store__stat--elastico .store__stat-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.store__stat--elastico .store__stat-texto{overflow:hidden;text-overflow:ellipsis;min-width:0}.store__stat-chevron{color:var(--sui-text-soft-400, #a3a3a3);margin-left:-1px}\n"] }]
16274
+ }], propDecorators: { store: [{ type: i0.Input, args: [{ isSignal: true, alias: "store", required: true }] }], isFavorite: [{ type: i0.Input, args: [{ isSignal: true, alias: "isFavorite", required: false }] }], disableLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableLink", required: false }] }], deliveryText: [{ type: i0.Input, args: [{ isSignal: true, alias: "deliveryText", required: false }] }], distanceText: [{ type: i0.Input, args: [{ isSignal: true, alias: "distanceText", required: false }] }], toggleFavorite: [{ type: i0.Output, args: ["toggleFavorite"] }], ratingClicked: [{ type: i0.Output, args: ["ratingClicked"] }] } });
15776
16275
 
15777
16276
  /**
15778
16277
  * Card de producto (catálogo del cliente). Presentacional: recibe los datos por
@@ -16826,7 +17325,7 @@ class SuiTable {
16826
17325
  return this.columns().map((_, i) => i);
16827
17326
  }
16828
17327
  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 });
17328
+ 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
17329
  }
16831
17330
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiTable, decorators: [{
16832
17331
  type: Component,
@@ -16836,7 +17335,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
16836
17335
  '[attr.data-sui-selectable]': 'selectable() ? "" : null',
16837
17336
  '[attr.data-sui-loading]': 'loading() ? "" : null',
16838
17337
  '[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"] }]
17338
+ }, 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
17339
  }], 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
17340
  type: ContentChildren,
16842
17341
  args: [SuiTableCellDirective]
@@ -19159,5 +19658,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
19159
19658
  * Generated bundle index. Do not edit.
19160
19659
  */
19161
19660
 
19162
- export { DAY_LABELS_ES, DEFAULT_DURATION_PRESETS, DEFAULT_PRESETS, EMPTY_STATE_FOX_EMOJI, SUI_BRAND_LOGO_COMPANIES, SUI_CHART_LEGEND_COLORS, SUI_CHART_LEGEND_HEX, SUI_CHART_SERIES_COLORS, SUI_COLOR_DOT_COLORS, SUI_COLOR_DOT_HEX, SUI_CUSTOM_ICONS, SUI_EMOJI_MAP, SUI_EMOJI_STATIC, SUI_FLAG_NAMES, SUI_HEX_TO_COLOR, SUI_KEY_ICON_COLORS, SUI_KEY_ICON_SIZES, SUI_NAVBAR_VISIBILITY, SUI_PASSWORD_STRENGTH_DEFAULT_CONDITIONS, SUI_PASSWORD_STRENGTH_DEFAULT_LEVEL_LABELS, SUI_PAYMENT_ICON_TYPES, SUI_PRODUCT_FALLBACK_COLORS, SUI_TAB_BAR, SuiAccordion, SuiAccordionContent, SuiActivityFeed, SuiActivityFilter, SuiAlert, SuiAppStoreBadge, SuiAvatar, SuiAvatarGroup, SuiBadge, SuiBanner, SuiBrandLogo, SuiBreadcrumbItem, SuiBreadcrumbs, SuiButton, SuiButtonGroup, SuiButtonGroupItem, SuiCard, SuiChartLegend, SuiChartLegendDot, SuiCheckbox, SuiCheckboxCard, SuiCheckboxLabel, SuiCircularProgressBar, SuiColorDot, SuiColorPicker, SuiCommandMenuFooter, SuiCommandMenuItem, SuiCommandMenuSearch, SuiCompactAvatarGroup, SuiCompactButton, SuiCompactSelect, SuiCompactSelectForInput, SuiContentCard, SuiContentDivider, SuiContentLabel, SuiCounterInput, SuiDateSelector, SuiDatepicker, SuiDayCell, SuiDayLabel, SuiDivider, SuiDrawerFooter, SuiDrawerHeader, SuiDropdownCaption, SuiDropdownItem, SuiDropdownMenu, SuiDropdownPanel, SuiDropdownSearch, SuiEmoji, SuiEmptyState, SuiFancyButton, SuiFileIcon, SuiFileUpload, SuiFileUploadCard, SuiFilterBar, SuiFilterItem, SuiFilterPanelFooter, SuiFilterPanelHeader, SuiFlag, SuiFormHint, SuiFormLabel, SuiHref, SuiIcon, SuiImageUpload, SuiImageUploadProfile, SuiImgRetry, SuiInlineInput, SuiInlineSelect, SuiInput, SuiIntegrationSwitch, SuiKbd, SuiKeyIcon, SuiLinkButton, SuiModal, SuiModalFooter, SuiModalHeader, SuiModalSheet, SuiNotification, SuiNotificationFooter, SuiNotificationTabMenu, SuiOtpInput, SuiPageHeader, SuiPagination, SuiPasswordStrength, SuiPaymentIcon, SuiPeriodRange, SuiPopover, SuiProductCard, SuiProgressBar, SuiProgressBarLabel, SuiRadio, SuiRadioCard, SuiRadioGroup, SuiRadioLabel, SuiRating, SuiRichEditor, SuiRichEditorItem, SuiSegmentedControl, SuiSelect, SuiSidebar, SuiSlider, SuiSocialButton, SuiStatusBadge, SuiStepper, SuiStoreCard, SuiSwitch, SuiSwitchCard, SuiSwitchLabel, SuiTabChips, SuiTabMenuHorizontal, SuiTabMenuVertical, SuiTable, SuiTableCellDirective, SuiTag, SuiTagInput, SuiTextarea, SuiTimePicker, SuiTimePickerDuration, SuiTimePickerItem, SuiTimePickerStatus, SuiToastOutlet, SuiToastService, SuiTooltip, SuiTooltipPanel, SuiTopbar, SuiTopbarButton, SuiTopbarItem, SuiTopbarUser, buildCalendarGrid, buildHourList, buildMinuteList, formatDateInput, formatDateShort, formatMonthYear, formatTime, isSameTime, normalizeHex, pad2, parseTime, to12h, to24h };
19661
+ export { DAY_LABELS_ES, DEFAULT_DURATION_PRESETS, DEFAULT_PRESETS, EMPTY_STATE_FOX_EMOJI, SUI_BRAND_LOGO_COMPANIES, SUI_CHART_LEGEND_COLORS, SUI_CHART_LEGEND_HEX, SUI_CHART_SERIES_COLORS, SUI_COLOR_DOT_COLORS, SUI_COLOR_DOT_HEX, SUI_CUSTOM_ICONS, SUI_EMOJI_MAP, SUI_EMOJI_STATIC, SUI_FLAG_NAMES, SUI_HEX_TO_COLOR, SUI_KEY_ICON_COLORS, SUI_KEY_ICON_SIZES, SUI_NAVBAR_VISIBILITY, SUI_PASSWORD_STRENGTH_DEFAULT_CONDITIONS, SUI_PASSWORD_STRENGTH_DEFAULT_LEVEL_LABELS, SUI_PAYMENT_ICON_TYPES, SUI_PRODUCT_FALLBACK_COLORS, SUI_TAB_BAR, SuiAccordion, SuiAccordionContent, SuiActivityFeed, SuiActivityFilter, SuiAlert, SuiAppStoreBadge, SuiAvatar, SuiAvatarGroup, SuiBadge, SuiBanner, SuiBrandLogo, SuiBreadcrumbItem, SuiBreadcrumbs, SuiButton, SuiButtonGroup, SuiButtonGroupItem, SuiCard, SuiChartLegend, SuiChartLegendDot, SuiCheckbox, SuiCheckboxCard, SuiCheckboxLabel, SuiCircularProgressBar, SuiColorDot, SuiColorPicker, SuiCommandMenuFooter, SuiCommandMenuItem, SuiCommandMenuSearch, SuiCompactAvatarGroup, SuiCompactButton, SuiCompactSelect, SuiCompactSelectForInput, SuiContentCard, SuiContentDivider, SuiContentLabel, SuiCounterInput, SuiDateSelector, SuiDatepicker, SuiDayCell, SuiDayLabel, SuiDivider, SuiDrawerFooter, SuiDrawerHeader, SuiDropdownCaption, SuiDropdownItem, SuiDropdownMenu, SuiDropdownPanel, SuiDropdownSearch, SuiEmoji, SuiEmptyState, SuiFancyButton, SuiFileIcon, SuiFileUpload, SuiFileUploadCard, SuiFilterBar, SuiFilterItem, SuiFilterPanelFooter, SuiFilterPanelHeader, SuiFlag, SuiFormHint, SuiFormLabel, SuiHref, SuiIcon, SuiImageUpload, SuiImageUploadProfile, SuiImgRetry, SuiInlineInput, SuiInlineSelect, SuiInput, SuiIntegrationSwitch, SuiKbd, SuiKeyIcon, SuiLinkButton, SuiLogo, SuiModal, SuiModalFooter, SuiModalHeader, SuiModalSheet, SuiNotification, SuiNotificationFooter, SuiNotificationTabMenu, SuiOtpInput, SuiPageHeader, SuiPagination, SuiPasswordStrength, SuiPaymentIcon, SuiPeriodRange, SuiPopover, SuiProductCard, SuiProgressBar, SuiProgressBarLabel, SuiRadio, SuiRadioCard, SuiRadioGroup, SuiRadioLabel, SuiRating, SuiRichEditor, SuiRichEditorItem, SuiSegmentedControl, SuiSelect, SuiSidebar, SuiSlider, SuiSocialButton, SuiStatusBadge, SuiStepper, SuiStoreCard, SuiSwitch, SuiSwitchCard, SuiSwitchLabel, SuiTabChips, SuiTabMenuHorizontal, SuiTabMenuVertical, SuiTable, SuiTableCellDirective, SuiTag, SuiTagInput, SuiTextarea, SuiTimePicker, SuiTimePickerDuration, SuiTimePickerItem, SuiTimePickerStatus, SuiToastOutlet, SuiToastService, SuiTooltip, SuiTooltipPanel, SuiTopbar, SuiTopbarButton, SuiTopbarItem, SuiTopbarUser, buildCalendarGrid, buildHourList, buildMinuteList, formatDateInput, formatDateShort, formatMonthYear, formatTime, isSameTime, normalizeHex, pad2, parseTime, to12h, to24h };
19163
19662
  //# sourceMappingURL=ajuarezso-sui-design-system.mjs.map