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