@ajuarezso/sui-design-system 0.2.2 → 0.2.3
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, model, signal, viewChild, effect, untracked, output, inject, ElementRef, forwardRef,
|
|
2
|
+
import { InjectionToken, input, computed, ChangeDetectionStrategy, Component, model, signal, viewChild, effect, untracked, output, inject, ElementRef, forwardRef, TemplateRef, Directive, ViewContainerRef, DestroyRef, ContentChild, ViewChild, ViewEncapsulation, Renderer2, DOCUMENT, HostListener, viewChildren, afterNextRender, ContentChildren, ViewChildren, Injectable } from '@angular/core';
|
|
3
3
|
import { NgTemplateOutlet, DOCUMENT as DOCUMENT$1 } from '@angular/common';
|
|
4
4
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
5
5
|
import { Subscription } from 'rxjs';
|
|
@@ -3143,6 +3143,218 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
3143
3143
|
}, template: "<button\n type=\"button\"\n class=\"sui-color-dot__inner\"\n role=\"radio\"\n [disabled]=\"state() === 'disabled' || null\"\n [attr.aria-checked]=\"state() === 'selected' ? 'true' : 'false'\"\n [attr.aria-label]=\"ariaLabel() || defaultAriaLabel()\"\n (click)=\"onClick()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n></button>\n", styles: ["@charset \"UTF-8\";:host{display:inline-block;width:24px;height:24px;vertical-align:middle;--c: var(--sui-neutral-500)}:host([data-sui-color=gray]){--c: var(--sui-neutral-500)}:host([data-sui-color=blue]){--c: var(--sui-blue-500)}:host([data-sui-color=orange]){--c: var(--sui-orange-500)}:host([data-sui-color=red]){--c: var(--sui-red-500)}:host([data-sui-color=green]){--c: var(--sui-green-500)}:host([data-sui-color=yellow]){--c: var(--sui-yellow-500)}:host([data-sui-color=purple]){--c: var(--sui-purple-500)}:host([data-sui-color=sky]){--c: var(--sui-sky-500)}:host([data-sui-color=pink]){--c: var(--sui-pink-500)}:host([data-sui-color=teal]){--c: var(--sui-teal-500)}:host([data-sui-state=disabled]){--c: var(--sui-bg-soft-200)}.sui-color-dot__inner{position:relative;display:block;width:24px;height:24px;padding:0;margin:0;border:none;background:transparent;cursor:pointer;appearance:none;outline:none;border-radius:50%;transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-dot__inner:after{content:\"\";position:absolute;inset:4px;border-radius:50%;background:var(--c);transition:inset var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-state=selected]) .sui-color-dot__inner:after{inset:6px}.sui-color-dot__inner:before{content:\"\";position:absolute;inset:3px;border-radius:50%;border:2px solid transparent;transition:border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-state=selected]) .sui-color-dot__inner:before{border-color:var(--c)}.sui-color-dot__inner:active{transform:none}:host([data-sui-state=default]) .sui-color-dot__inner:hover:after,:host([data-sui-state=hover]) .sui-color-dot__inner:after{inset:5px}.sui-color-dot__inner:focus-visible{outline:2px solid var(--c);outline-offset:2px}:host([data-sui-state=disabled]) .sui-color-dot__inner{cursor:not-allowed;pointer-events:none}\n"] }]
|
|
3144
3144
|
}], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], customHex: [{ type: i0.Input, args: [{ isSignal: true, alias: "customHex", required: false }] }], state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
|
|
3145
3145
|
|
|
3146
|
+
/**
|
|
3147
|
+
* Structural directive — marca un `<ng-template>` como panel del
|
|
3148
|
+
* sui-dropdown-menu. El componente padre captura este TemplateRef
|
|
3149
|
+
* via `@ContentChild(SuiDropdownPanel)` y lo monta en el CDK Overlay
|
|
3150
|
+
* cuando se abre el menu.
|
|
3151
|
+
*
|
|
3152
|
+
* Usa el patrón canon Angular (similar a `*matMenuContent` de Material):
|
|
3153
|
+
* un directive que se aplica al `<ng-template>` SE convierte en una
|
|
3154
|
+
* marca semántica, evitando que Angular renderee el contenido inline
|
|
3155
|
+
* cuando no hay `<ng-content>` matching para el template.
|
|
3156
|
+
*
|
|
3157
|
+
* Uso:
|
|
3158
|
+
* <sui-dropdown-menu>
|
|
3159
|
+
* <sui-compact-select trigger ... />
|
|
3160
|
+
* <ng-template suiDropdownPanel>
|
|
3161
|
+
* <sui-dropdown-item ...></sui-dropdown-item>
|
|
3162
|
+
* </ng-template>
|
|
3163
|
+
* </sui-dropdown-menu>
|
|
3164
|
+
*/
|
|
3165
|
+
class SuiDropdownPanel {
|
|
3166
|
+
template = inject(TemplateRef);
|
|
3167
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownPanel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
3168
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: SuiDropdownPanel, isStandalone: true, selector: "ng-template[suiDropdownPanel]", ngImport: i0 });
|
|
3169
|
+
}
|
|
3170
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownPanel, decorators: [{
|
|
3171
|
+
type: Directive,
|
|
3172
|
+
args: [{
|
|
3173
|
+
selector: 'ng-template[suiDropdownPanel]',
|
|
3174
|
+
standalone: true,
|
|
3175
|
+
}]
|
|
3176
|
+
}] });
|
|
3177
|
+
|
|
3178
|
+
/* Posiciones con fallback HORIZONTAL: la primera (start-aligned, abre a la
|
|
3179
|
+
derecha) es la default; si el trigger está pegado al borde derecho y no entra,
|
|
3180
|
+
CDK cae a la end-aligned (abre hacia la izquierda) y recién después flipea
|
|
3181
|
+
vertical. Sin esto, un trigger en la esquina derecha (ej. kebab ⋮ de una card)
|
|
3182
|
+
recorta el panel fuera del viewport. */
|
|
3183
|
+
const POSITIONS_BELOW = [
|
|
3184
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
3185
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
3186
|
+
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
3187
|
+
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
3188
|
+
];
|
|
3189
|
+
const POSITIONS_ABOVE = [
|
|
3190
|
+
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
3191
|
+
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
3192
|
+
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
3193
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
3194
|
+
];
|
|
3195
|
+
class SuiDropdownMenu {
|
|
3196
|
+
/** Si true, el panel matchea el ancho del trigger. Default: auto width. */
|
|
3197
|
+
matchWidth = input(false, ...(ngDevMode ? [{ debugName: "matchWidth" }] : /* istanbul ignore next */ []));
|
|
3198
|
+
/** Min-width fijo del panel (px). Si matchWidth + minWidth: `max(triggerWidth, minWidth)`. */
|
|
3199
|
+
minWidth = input(null, ...(ngDevMode ? [{ debugName: "minWidth" }] : /* istanbul ignore next */ []));
|
|
3200
|
+
/** Position primary. Default: auto = below con fallback above. */
|
|
3201
|
+
position = input('auto', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
3202
|
+
/** Margen 8px del viewport edge (canon SUI). */
|
|
3203
|
+
viewportMargin = input(8, ...(ngDevMode ? [{ debugName: "viewportMargin" }] : /* istanbul ignore next */ []));
|
|
3204
|
+
/** Panel custom class para overrides de bg/padding/etc desde el consumer. */
|
|
3205
|
+
panelClass = input('', ...(ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []));
|
|
3206
|
+
/** Disabled — no abre el menu al clickear el trigger. */
|
|
3207
|
+
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
3208
|
+
/**
|
|
3209
|
+
* Rol del popup para `aria-haspopup` del trigger. Default 'menu' (los items
|
|
3210
|
+
* proyectados llevan role="menuitem"). Los consumers de tipo listbox
|
|
3211
|
+
* (sui-select / compact-selects, items con role="option") DEBEN pasar
|
|
3212
|
+
* `popupRole="listbox"`. Ver SuiDropdownMenuPopupRole.
|
|
3213
|
+
*/
|
|
3214
|
+
popupRole = input('menu', ...(ngDevMode ? [{ debugName: "popupRole" }] : /* istanbul ignore next */ []));
|
|
3215
|
+
/**
|
|
3216
|
+
* Origin externo. Si presente, el menu se ancla a ese elemento y NO renderea
|
|
3217
|
+
* el trigger wrapper interno (el parent maneja el click). Caso de uso:
|
|
3218
|
+
* compact-selects donde el host element es el trigger visual.
|
|
3219
|
+
*/
|
|
3220
|
+
origin = input(null, ...(ngDevMode ? [{ debugName: "origin" }] : /* istanbul ignore next */ []));
|
|
3221
|
+
openedChange = output();
|
|
3222
|
+
/** Signal pública — wire al `[open]` del trigger para visual state. */
|
|
3223
|
+
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
3224
|
+
/** Wrapper del trigger projection — captura el click. NO existe si `[origin]` se pasa. */
|
|
3225
|
+
_triggerWrap;
|
|
3226
|
+
/** Panel directive proyectado — capturado via `[suiDropdownPanel]` en un ng-template. */
|
|
3227
|
+
_panel;
|
|
3228
|
+
_getTriggerEl() {
|
|
3229
|
+
const o = this.origin();
|
|
3230
|
+
if (o)
|
|
3231
|
+
return o instanceof ElementRef ? o.nativeElement : o;
|
|
3232
|
+
return this._triggerWrap?.nativeElement ?? null;
|
|
3233
|
+
}
|
|
3234
|
+
_vcr = inject(ViewContainerRef);
|
|
3235
|
+
_destroyRef = inject(DestroyRef);
|
|
3236
|
+
_overlay = inject(Overlay);
|
|
3237
|
+
_overlayRef = null;
|
|
3238
|
+
_overlaySubs = null;
|
|
3239
|
+
_resizeObserver = null;
|
|
3240
|
+
constructor() {
|
|
3241
|
+
this._destroyRef.onDestroy(() => this.close());
|
|
3242
|
+
}
|
|
3243
|
+
onTriggerClick(event) {
|
|
3244
|
+
if (this.disabled())
|
|
3245
|
+
return;
|
|
3246
|
+
event.stopPropagation();
|
|
3247
|
+
this.toggle();
|
|
3248
|
+
}
|
|
3249
|
+
onTriggerKeydown(event) {
|
|
3250
|
+
if (this.disabled())
|
|
3251
|
+
return;
|
|
3252
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
3253
|
+
event.preventDefault();
|
|
3254
|
+
this.toggle();
|
|
3255
|
+
}
|
|
3256
|
+
else if (event.key === 'ArrowDown') {
|
|
3257
|
+
event.preventDefault();
|
|
3258
|
+
this.open();
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
toggle() {
|
|
3262
|
+
if (this.isOpen())
|
|
3263
|
+
this.close();
|
|
3264
|
+
else
|
|
3265
|
+
this.open();
|
|
3266
|
+
}
|
|
3267
|
+
open() {
|
|
3268
|
+
if (this.disabled() || this._overlayRef || !this._panel)
|
|
3269
|
+
return;
|
|
3270
|
+
const triggerEl = this._getTriggerEl();
|
|
3271
|
+
if (!triggerEl)
|
|
3272
|
+
return;
|
|
3273
|
+
const positions = this.position() === 'above' ? POSITIONS_ABOVE : POSITIONS_BELOW;
|
|
3274
|
+
const positionStrategy = this._overlay
|
|
3275
|
+
.position()
|
|
3276
|
+
.flexibleConnectedTo(triggerEl)
|
|
3277
|
+
.withPositions(positions)
|
|
3278
|
+
.withPush(false)
|
|
3279
|
+
.withFlexibleDimensions(true)
|
|
3280
|
+
.withViewportMargin(this.viewportMargin());
|
|
3281
|
+
const triggerWidth = triggerEl.getBoundingClientRect().width;
|
|
3282
|
+
const minW = this.minWidth();
|
|
3283
|
+
const effectiveMinWidth = this.matchWidth() && minW !== null
|
|
3284
|
+
? Math.max(triggerWidth, minW)
|
|
3285
|
+
: minW;
|
|
3286
|
+
const config = {
|
|
3287
|
+
positionStrategy,
|
|
3288
|
+
scrollStrategy: this._overlay.scrollStrategies.reposition(),
|
|
3289
|
+
hasBackdrop: true,
|
|
3290
|
+
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
3291
|
+
panelClass: ['sui-dropdown-menu__overlay-pane', this.panelClass()].filter(Boolean),
|
|
3292
|
+
disposeOnNavigation: true,
|
|
3293
|
+
};
|
|
3294
|
+
if (this.matchWidth() && minW === null) {
|
|
3295
|
+
config.width = `${triggerWidth}px`;
|
|
3296
|
+
}
|
|
3297
|
+
if (effectiveMinWidth !== null) {
|
|
3298
|
+
config.minWidth = effectiveMinWidth;
|
|
3299
|
+
}
|
|
3300
|
+
this._overlayRef = this._overlay.create(config);
|
|
3301
|
+
const portal = new TemplatePortal(this._panel.template, this._vcr);
|
|
3302
|
+
this._overlayRef.attach(portal);
|
|
3303
|
+
/* Width sync mientras el viewport cambia (canon sui-select). Solo aplica
|
|
3304
|
+
cuando matchWidth fija width o minWidth — para que el panel siga el trigger. */
|
|
3305
|
+
if (this.matchWidth() && typeof ResizeObserver !== 'undefined') {
|
|
3306
|
+
this._resizeObserver = new ResizeObserver(() => {
|
|
3307
|
+
if (!this._overlayRef)
|
|
3308
|
+
return;
|
|
3309
|
+
const w = triggerEl.getBoundingClientRect().width;
|
|
3310
|
+
if (minW === null) {
|
|
3311
|
+
this._overlayRef.updateSize({ width: `${w}px` });
|
|
3312
|
+
}
|
|
3313
|
+
else {
|
|
3314
|
+
this._overlayRef.updateSize({ minWidth: Math.max(w, minW) });
|
|
3315
|
+
}
|
|
3316
|
+
this._overlayRef.updatePosition();
|
|
3317
|
+
});
|
|
3318
|
+
this._resizeObserver.observe(triggerEl);
|
|
3319
|
+
}
|
|
3320
|
+
this._overlaySubs = new Subscription();
|
|
3321
|
+
this._overlaySubs.add(this._overlayRef.backdropClick().subscribe(() => this.close()));
|
|
3322
|
+
this._overlaySubs.add(this._overlayRef.keydownEvents().subscribe((e) => {
|
|
3323
|
+
if (e.key === 'Escape')
|
|
3324
|
+
this.close();
|
|
3325
|
+
}));
|
|
3326
|
+
this._overlaySubs.add(this._overlayRef.detachments().subscribe(() => {
|
|
3327
|
+
this.isOpen.set(false);
|
|
3328
|
+
}));
|
|
3329
|
+
this.isOpen.set(true);
|
|
3330
|
+
this.openedChange.emit(true);
|
|
3331
|
+
}
|
|
3332
|
+
close() {
|
|
3333
|
+
if (!this._overlayRef)
|
|
3334
|
+
return;
|
|
3335
|
+
this._overlaySubs?.unsubscribe();
|
|
3336
|
+
this._overlaySubs = null;
|
|
3337
|
+
this._resizeObserver?.disconnect();
|
|
3338
|
+
this._resizeObserver = null;
|
|
3339
|
+
this._overlayRef.dispose();
|
|
3340
|
+
this._overlayRef = null;
|
|
3341
|
+
this.isOpen.set(false);
|
|
3342
|
+
this.openedChange.emit(false);
|
|
3343
|
+
}
|
|
3344
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3345
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiDropdownMenu, isStandalone: true, selector: "sui-dropdown-menu", inputs: { matchWidth: { classPropertyName: "matchWidth", publicName: "matchWidth", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, viewportMargin: { classPropertyName: "viewportMargin", publicName: "viewportMargin", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, popupRole: { classPropertyName: "popupRole", publicName: "popupRole", isSignal: true, isRequired: false, transformFunction: null }, origin: { classPropertyName: "origin", publicName: "origin", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedChange: "openedChange" }, queries: [{ propertyName: "_panel", first: true, predicate: SuiDropdownPanel, descendants: true }], viewQueries: [{ propertyName: "_triggerWrap", first: true, predicate: ["triggerWrap"], descendants: true }], exportAs: ["suiDropdownMenu"], ngImport: i0, template: "<!-- Trigger wrapper \u2014 captura click y keydown del trigger child. Solo se\n renderea cuando NO se pasa [origin] (modo content-projection canon).\n Cuando se pasa [origin], el parent maneja el trigger y llama\n menu.toggle() desde su propio click handler. -->\n@if (!origin()) {\n <span\n #triggerWrap\n class=\"sui-dropdown-menu__trigger\"\n [attr.aria-haspopup]=\"popupRole()\"\n [attr.aria-expanded]=\"isOpen()\"\n (click)=\"onTriggerClick($event)\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <ng-content select=\"[trigger]\" />\n </span>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-dropdown-menu__trigger{display:inline-block;cursor:pointer;outline:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3346
|
+
}
|
|
3347
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownMenu, decorators: [{
|
|
3348
|
+
type: Component,
|
|
3349
|
+
args: [{ selector: 'sui-dropdown-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, exportAs: 'suiDropdownMenu', template: "<!-- Trigger wrapper \u2014 captura click y keydown del trigger child. Solo se\n renderea cuando NO se pasa [origin] (modo content-projection canon).\n Cuando se pasa [origin], el parent maneja el trigger y llama\n menu.toggle() desde su propio click handler. -->\n@if (!origin()) {\n <span\n #triggerWrap\n class=\"sui-dropdown-menu__trigger\"\n [attr.aria-haspopup]=\"popupRole()\"\n [attr.aria-expanded]=\"isOpen()\"\n (click)=\"onTriggerClick($event)\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <ng-content select=\"[trigger]\" />\n </span>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-dropdown-menu__trigger{display:inline-block;cursor:pointer;outline:none}\n"] }]
|
|
3350
|
+
}], ctorParameters: () => [], propDecorators: { matchWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "matchWidth", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], viewportMargin: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportMargin", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], popupRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupRole", required: false }] }], origin: [{ type: i0.Input, args: [{ isSignal: true, alias: "origin", required: false }] }], openedChange: [{ type: i0.Output, args: ["openedChange"] }], _triggerWrap: [{
|
|
3351
|
+
type: ViewChild,
|
|
3352
|
+
args: ['triggerWrap', { static: false }]
|
|
3353
|
+
}], _panel: [{
|
|
3354
|
+
type: ContentChild,
|
|
3355
|
+
args: [SuiDropdownPanel]
|
|
3356
|
+
}] } });
|
|
3357
|
+
|
|
3146
3358
|
/* ════════════════════════════════════════════════════════════════════════
|
|
3147
3359
|
* HSV ↔ RGB ↔ HEX conversion helpers
|
|
3148
3360
|
*
|
|
@@ -3391,6 +3603,7 @@ class SuiColorPicker {
|
|
|
3391
3603
|
/** Hex input visible (separate del value model para validación en blur). */
|
|
3392
3604
|
hexInput = signal('', ...(ngDevMode ? [{ debugName: "hexInput" }] : /* istanbul ignore next */ []));
|
|
3393
3605
|
/** Refs del spectrum y sliders para cálculos de bounds */
|
|
3606
|
+
_menu = viewChild(SuiDropdownMenu, ...(ngDevMode ? [{ debugName: "_menu" }] : /* istanbul ignore next */ []));
|
|
3394
3607
|
canvasRef = viewChild('canvas', ...(ngDevMode ? [{ debugName: "canvasRef" }] : /* istanbul ignore next */ []));
|
|
3395
3608
|
hueRef = viewChild('hueSlider', ...(ngDevMode ? [{ debugName: "hueRef" }] : /* istanbul ignore next */ []));
|
|
3396
3609
|
opacityRef = viewChild('opacitySlider', ...(ngDevMode ? [{ debugName: "opacityRef" }] : /* istanbul ignore next */ []));
|
|
@@ -3577,17 +3790,21 @@ class SuiColorPicker {
|
|
|
3577
3790
|
toggle() {
|
|
3578
3791
|
if (this.disabled())
|
|
3579
3792
|
return;
|
|
3580
|
-
this.
|
|
3581
|
-
|
|
3582
|
-
|
|
3793
|
+
this._menu()?.toggle();
|
|
3794
|
+
}
|
|
3795
|
+
close() {
|
|
3796
|
+
this._menu()?.close();
|
|
3797
|
+
}
|
|
3798
|
+
/** El sui-dropdown-menu (CDK overlay) es el dueño del open/close: acá solo se
|
|
3799
|
+
sincroniza el signal `open` (aria-expanded, chevron, data-sui-open) y el
|
|
3800
|
+
hex input al abrir. Backdrop + Esc + detachments los maneja el menu. */
|
|
3801
|
+
onMenuOpenedChange(opened) {
|
|
3802
|
+
this.open.set(opened);
|
|
3803
|
+
if (opened) {
|
|
3583
3804
|
const parsed = parseHexWithAlpha(this.value());
|
|
3584
3805
|
this.hexInput.set(parsed?.hex ?? '');
|
|
3585
3806
|
}
|
|
3586
3807
|
}
|
|
3587
|
-
close() {
|
|
3588
|
-
if (this.open())
|
|
3589
|
-
this.open.set(false);
|
|
3590
|
-
}
|
|
3591
3808
|
/* ─────────── Recommended dot click ─────────── */
|
|
3592
3809
|
onPresetClick(preset) {
|
|
3593
3810
|
// setColor atómico → garantiza que value, HSV y hexInput queden
|
|
@@ -3761,34 +3978,17 @@ class SuiColorPicker {
|
|
|
3761
3978
|
// user canceló (Esc) — no-op.
|
|
3762
3979
|
}
|
|
3763
3980
|
}
|
|
3764
|
-
/* ─────────── Outside click + Esc ─────────── */
|
|
3765
|
-
onDocumentClick(target) {
|
|
3766
|
-
if (!this.open())
|
|
3767
|
-
return;
|
|
3768
|
-
if (target instanceof Node && !this.hostRef.nativeElement.contains(target)) {
|
|
3769
|
-
this.close();
|
|
3770
|
-
}
|
|
3771
|
-
}
|
|
3772
|
-
onEscape() {
|
|
3773
|
-
this.close();
|
|
3774
|
-
}
|
|
3775
3981
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiColorPicker, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3776
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiColorPicker, isStandalone: true, selector: "sui-color-picker", inputs: { colors: { classPropertyName: "colors", publicName: "colors", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, recommendedLabel: { classPropertyName: "recommendedLabel", publicName: "recommendedLabel", isSignal: true, isRequired: false, transformFunction: null }, presetsOnly: { classPropertyName: "presetsOnly", publicName: "presetsOnly", isSignal: true, isRequired: false, transformFunction: null }, alpha: { classPropertyName: "alpha", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null }, eyedropper: { classPropertyName: "eyedropper", publicName: "eyedropper", isSignal: true, isRequired: false, transformFunction: null }, showFormatLabel: { classPropertyName: "showFormatLabel", publicName: "showFormatLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", change: "change" }, host: { listeners: { "document:click": "onDocumentClick($event.target)", "document:keydown.escape": "onEscape()" }, properties: { "attr.data-sui-open": "open() ? \"\" : null", "attr.data-sui-disabled": "disabled() ? \"\" : null", "attr.data-sui-presets-only": "presetsOnly() ? \"\" : null" } }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }, { propertyName: "hueRef", first: true, predicate: ["hueSlider"], descendants: true, isSignal: true }, { propertyName: "opacityRef", first: true, predicate: ["opacitySlider"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n type=\"button\"\n class=\"sui-color-picker__trigger\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"open() ? 'true' : 'false'\"\n (click)=\"toggle()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n>\n @if (value()) {\n @if (currentPreset()) {\n <sui-color-dot [color]=\"currentPreset()!\" state=\"selected\" class=\"sui-color-picker__preview\" />\n } @else {\n <sui-color-dot [customHex]=\"previewColor()\" state=\"selected\" class=\"sui-color-picker__preview\" />\n }\n } @else {\n <span class=\"sui-color-picker__placeholder-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"sui-color-picker__label\">{{ currentLabel() }}</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"16\" class=\"sui-color-picker__chevron\" />\n</button>\n\n@if (open()) {\n <div\n class=\"sui-color-picker__panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n @if (!presetsOnly()) {\n <!-- Secci\u00F3n \"Colors\" \u2014 Figma 4456:115716 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--colors\">\n <!-- HSV Color Spectrum \u2014 Figma 4456:115425 -->\n <div\n #canvas\n class=\"sui-color-picker__canvas\"\n role=\"application\"\n aria-label=\"Saturaci\u00F3n y brillo\"\n [style.--hue-color]=\"hueColor()\"\n (pointerdown)=\"onCanvasPointerDown($event)\"\n (pointermove)=\"onCanvasPointerMove($event)\"\n (pointerup)=\"onCanvasPointerUp($event)\"\n (pointercancel)=\"onCanvasPointerUp($event)\"\n >\n <div\n class=\"sui-color-picker__canvas-thumb\"\n [style.left]=\"canvasThumbX()\"\n [style.top]=\"canvasThumbY()\"\n [style.background-color]=\"currentHex()\"\n ></div>\n </div>\n\n <!-- Hue slider \u2014 Figma 4415:53669 -->\n <div\n #hueSlider\n class=\"sui-color-picker__slider sui-color-picker__hue\"\n role=\"slider\"\n aria-label=\"Matiz\"\n aria-valuemin=\"0\"\n aria-valuemax=\"360\"\n [attr.aria-valuenow]=\"hueRounded()\"\n (pointerdown)=\"onHuePointerDown($event)\"\n (pointermove)=\"onHuePointerMove($event)\"\n (pointerup)=\"onHuePointerUp($event)\"\n (pointercancel)=\"onHuePointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"hueThumbX()\"\n [style.background-color]=\"hueColor()\"\n ></div>\n </div>\n\n <!-- Opacity slider \u2014 Figma 4415:53670. Visible por default (alpha on);\n ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div\n #opacitySlider\n class=\"sui-color-picker__slider sui-color-picker__opacity\"\n role=\"slider\"\n aria-label=\"Opacidad\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"alphaPercent()\"\n [style.--opacity-color]=\"opacityColor()\"\n (pointerdown)=\"onOpacityPointerDown($event)\"\n (pointermove)=\"onOpacityPointerMove($event)\"\n (pointerup)=\"onOpacityPointerUp($event)\"\n (pointercancel)=\"onOpacityPointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"opacityThumbX()\"\n [style.--thumb-color]=\"opacityThumbColor()\"\n ></div>\n </div>\n }\n\n <!-- Color Input \u2014 Figma 4456:115720 -->\n <div class=\"sui-color-picker__color-input\">\n <!-- Format label \"Hex\" + chevron \u2014 Figma 4456:115721.\n Hex-only por ahora (ver PENDING VERIFY en el .ts). -->\n @if (showFormatLabel()) {\n <div class=\"sui-color-picker__format\" aria-hidden=\"true\">\n <span class=\"sui-color-picker__format-label\">Hex</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"20\" class=\"sui-color-picker__format-chevron\" />\n </div>\n }\n\n <!-- Input row \u2014 Figma 4456:115724: sip | hex | opacity -->\n <div class=\"sui-color-picker__input-row\">\n <!-- Sip (eyedropper) \u2014 Figma 4456:115796. Solo con EyeDropper API. -->\n @if (showEyedropper()) {\n <button\n type=\"button\"\n class=\"sui-color-picker__sip\"\n aria-label=\"Cuentagotas\"\n (click)=\"onEyedropper()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n >\n <sui-icon name=\"sip-line\" [size]=\"20\" />\n </button>\n }\n\n <!-- Hex field \u2014 Figma 4456:115725 / 4456:115726: el texto va SIN\n prefijo '#' (Figma muestra \"335CFF\" pelado dentro de la celda). -->\n <div class=\"sui-color-picker__hex-cell\">\n <input\n class=\"sui-color-picker__hex-field\"\n type=\"text\"\n inputmode=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n maxlength=\"8\"\n aria-label=\"Valor hexadecimal\"\n [value]=\"hexDisplayValue()\"\n (input)=\"onHexInputChange($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n (blur)=\"onHexCommit()\"\n />\n </div>\n\n <!-- Opacity field \"%\" \u2014 Figma 4456:115727. Visible por default\n (alpha on); ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div class=\"sui-color-picker__opacity-cell\">\n <input\n class=\"sui-color-picker__opacity-field\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"3\"\n aria-label=\"Opacidad\"\n [value]=\"alphaPercent()\"\n (change)=\"onOpacityFieldCommit($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n />\n <span class=\"sui-color-picker__opacity-suffix\" aria-hidden=\"true\">%</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Secci\u00F3n \"Recommended Colors\" \u2014 Figma 4456:115765 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--recommended\">\n <p class=\"sui-color-picker__panel-label\">{{ recommendedLabel() }}</p>\n <div class=\"sui-color-picker__grid\" role=\"radiogroup\">\n @for (c of colors(); track c) {\n <sui-color-dot\n [color]=\"c\"\n [state]=\"currentPreset() === c ? 'selected' : 'default'\"\n (clicked)=\"onPresetClick(c)\"\n />\n }\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;display:inline-block;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0}.sui-color-picker__trigger{display:inline-flex;align-items:center;gap:8px;padding:6px 10px 6px 6px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);cursor:pointer;appearance:none;font:inherit;color:var(--sui-text-strong-950);font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__trigger:hover{background:var(--sui-bg-weak-50)}:host([data-sui-open]) .sui-color-picker__trigger{border-color:var(--sui-stroke-strong-950, var(--sui-text-strong-950))}.sui-color-picker__trigger:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:2px}.sui-color-picker__trigger:active{transform:none}:host([data-sui-disabled]) .sui-color-picker__trigger{background:var(--sui-bg-weak-50);color:var(--sui-text-disabled-300);cursor:not-allowed;pointer-events:none}.sui-color-picker__placeholder-dot{display:inline-block;width:24px;height:24px;border-radius:50%;background:var(--sui-bg-soft-200)}.sui-color-picker__label{flex:1 0 auto;white-space:nowrap}.sui-color-picker__chevron{flex-shrink:0;color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-color-picker__chevron{transform:rotate(180deg)}.sui-color-picker__panel{position:absolute;top:calc(100% + 6px);left:0;z-index:100;width:272px;box-sizing:border-box;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-16);box-shadow:var(--sui-shadow-medium);overflow:hidden;display:flex;flex-direction:column;animation:sui-color-picker__fade var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}@keyframes sui-color-picker__fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sui-color-picker__section{box-sizing:border-box;display:flex;flex-direction:column;gap:12px;padding:16px;width:100%}.sui-color-picker__section--colors{border-bottom:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__section--recommended{gap:8px}:host([data-sui-presets-only]) .sui-color-picker__section--recommended{border-bottom:none}.sui-color-picker__canvas{position:relative;width:100%;height:232px;border-radius:var(--sui-radius-8);cursor:crosshair;-webkit-user-select:none;user-select:none;touch-action:none;overflow:hidden;background-color:var(--hue-color, #335cff);background-image:linear-gradient(to top,#000,#0000),linear-gradient(to right,#fff,#fff0)}.sui-color-picker__canvas-thumb{position:absolute;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__slider{position:relative;width:100%;height:16px;cursor:pointer;-webkit-user-select:none;user-select:none;touch-action:none}.sui-color-picker__slider-track{position:absolute;left:0;right:0;top:4px;height:8px;border-radius:var(--sui-radius-full);overflow:hidden}.sui-color-picker__hue .sui-color-picker__slider-track{background-image:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.sui-color-picker__opacity .sui-color-picker__slider-track{background-color:#fff;background-image:linear-gradient(to right,transparent,var(--opacity-color, #335cff)),conic-gradient(#ebebeb 0 25%,transparent 0 50%,#ebebeb 0 75%,transparent 0);background-size:auto,10.88px 10.88px}.sui-color-picker__slider-thumb{position:absolute;top:50%;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__opacity .sui-color-picker__slider-thumb{background-image:linear-gradient(var(--thumb-color, #335cff),var(--thumb-color, #335cff)),conic-gradient(#ebebeb 0 25%,#fff 0 50%,#ebebeb 0 75%,#fff 0);background-size:auto,6px 6px}.sui-color-picker__color-input{display:flex;flex-direction:column;gap:4px;width:100%}.sui-color-picker__format{display:flex;align-items:center;gap:2px;appearance:none;border:none;background:transparent;padding:0;cursor:default;font:inherit;color:var(--sui-text-strong-950)}.sui-color-picker__format-label{font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);white-space:nowrap}.sui-color-picker__format-chevron{flex-shrink:0;color:var(--sui-icon-sub-600)}.sui-color-picker__input-row{box-sizing:border-box;display:flex;align-items:stretch;width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);overflow:hidden}.sui-color-picker__sip{display:flex;align-items:center;justify-content:center;padding:6px;border:none;border-right:1px solid var(--sui-stroke-soft-200);background:var(--sui-bg-white-0);color:var(--sui-icon-sub-600);cursor:pointer;appearance:none;flex-shrink:0;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__sip:hover{background:var(--sui-bg-weak-50)}.sui-color-picker__sip:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:-2px}.sui-color-picker__sip:active{transform:none}.sui-color-picker__hex-cell{box-sizing:border-box;display:flex;align-items:center;flex:1 0 0;min-width:0;padding:6px 10px;border-right:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__hex-cell:last-child{border-right:none}.sui-color-picker__hex-field{flex:1 0 0;min-width:0;width:100%;border:none;outline:none;background:transparent;padding:0;appearance:none;color:var(--sui-text-strong-950);font-family:inherit;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);text-transform:uppercase}.sui-color-picker__hex-field::placeholder{color:var(--sui-text-soft-400);text-transform:none}.sui-color-picker__opacity-cell{box-sizing:border-box;display:flex;align-items:center;flex-shrink:0;padding:6px 10px}.sui-color-picker__opacity-field{width:3.5ch;border:none;outline:none;background:transparent;padding:0;appearance:none;text-align:right;color:var(--sui-text-sub-600);font-family:inherit;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)}.sui-color-picker__opacity-suffix{color:var(--sui-text-sub-600);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)}.sui-color-picker__panel-label{margin:0;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-color-picker__grid{display:flex;flex-wrap:wrap;gap:4px;width:100%}\n"], dependencies: [{ kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "component", type: SuiColorDot, selector: "sui-color-dot", inputs: ["color", "customHex", "state", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3982
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiColorPicker, isStandalone: true, selector: "sui-color-picker", inputs: { colors: { classPropertyName: "colors", publicName: "colors", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, recommendedLabel: { classPropertyName: "recommendedLabel", publicName: "recommendedLabel", isSignal: true, isRequired: false, transformFunction: null }, presetsOnly: { classPropertyName: "presetsOnly", publicName: "presetsOnly", isSignal: true, isRequired: false, transformFunction: null }, alpha: { classPropertyName: "alpha", publicName: "alpha", isSignal: true, isRequired: false, transformFunction: null }, eyedropper: { classPropertyName: "eyedropper", publicName: "eyedropper", isSignal: true, isRequired: false, transformFunction: null }, showFormatLabel: { classPropertyName: "showFormatLabel", publicName: "showFormatLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", change: "change" }, host: { properties: { "attr.data-sui-open": "open() ? \"\" : null", "attr.data-sui-disabled": "disabled() ? \"\" : null", "attr.data-sui-presets-only": "presetsOnly() ? \"\" : null" } }, viewQueries: [{ propertyName: "_menu", first: true, predicate: SuiDropdownMenu, descendants: true, isSignal: true }, { propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }, { propertyName: "hueRef", first: true, predicate: ["hueSlider"], descendants: true, isSignal: true }, { propertyName: "opacityRef", first: true, predicate: ["opacitySlider"], descendants: true, isSignal: true }], ngImport: i0, template: "<button\n #trigger\n type=\"button\"\n class=\"sui-color-picker__trigger\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"open() ? 'true' : 'false'\"\n (click)=\"toggle()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n>\n @if (value()) {\n @if (currentPreset()) {\n <sui-color-dot [color]=\"currentPreset()!\" state=\"selected\" class=\"sui-color-picker__preview\" />\n } @else {\n <sui-color-dot [customHex]=\"previewColor()\" state=\"selected\" class=\"sui-color-picker__preview\" />\n }\n } @else {\n <span class=\"sui-color-picker__placeholder-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"sui-color-picker__label\">{{ currentLabel() }}</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"16\" class=\"sui-color-picker__chevron\" />\n</button>\n\n<!-- Panel en CDK overlay (via sui-dropdown-menu): escapa cualquier overflow\n clipping del contenedor (Storybook docs, modales, tablas). El contenido del\n ng-template mantiene el scoping de estilos del componente. -->\n<sui-dropdown-menu\n [origin]=\"trigger\"\n [disabled]=\"disabled()\"\n panelClass=\"sui-color-picker__overlay-pane\"\n (openedChange)=\"onMenuOpenedChange($event)\"\n>\n <ng-template suiDropdownPanel>\n <div\n class=\"sui-color-picker__panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n @if (!presetsOnly()) {\n <!-- Secci\u00F3n \"Colors\" \u2014 Figma 4456:115716 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--colors\">\n <!-- HSV Color Spectrum \u2014 Figma 4456:115425 -->\n <div\n #canvas\n class=\"sui-color-picker__canvas\"\n role=\"application\"\n aria-label=\"Saturaci\u00F3n y brillo\"\n [style.--hue-color]=\"hueColor()\"\n (pointerdown)=\"onCanvasPointerDown($event)\"\n (pointermove)=\"onCanvasPointerMove($event)\"\n (pointerup)=\"onCanvasPointerUp($event)\"\n (pointercancel)=\"onCanvasPointerUp($event)\"\n >\n <div\n class=\"sui-color-picker__canvas-thumb\"\n [style.left]=\"canvasThumbX()\"\n [style.top]=\"canvasThumbY()\"\n [style.background-color]=\"currentHex()\"\n ></div>\n </div>\n\n <!-- Hue slider \u2014 Figma 4415:53669 -->\n <div\n #hueSlider\n class=\"sui-color-picker__slider sui-color-picker__hue\"\n role=\"slider\"\n aria-label=\"Matiz\"\n aria-valuemin=\"0\"\n aria-valuemax=\"360\"\n [attr.aria-valuenow]=\"hueRounded()\"\n (pointerdown)=\"onHuePointerDown($event)\"\n (pointermove)=\"onHuePointerMove($event)\"\n (pointerup)=\"onHuePointerUp($event)\"\n (pointercancel)=\"onHuePointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"hueThumbX()\"\n [style.background-color]=\"hueColor()\"\n ></div>\n </div>\n\n <!-- Opacity slider \u2014 Figma 4415:53670. Visible por default (alpha on);\n ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div\n #opacitySlider\n class=\"sui-color-picker__slider sui-color-picker__opacity\"\n role=\"slider\"\n aria-label=\"Opacidad\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"alphaPercent()\"\n [style.--opacity-color]=\"opacityColor()\"\n (pointerdown)=\"onOpacityPointerDown($event)\"\n (pointermove)=\"onOpacityPointerMove($event)\"\n (pointerup)=\"onOpacityPointerUp($event)\"\n (pointercancel)=\"onOpacityPointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"opacityThumbX()\"\n [style.--thumb-color]=\"opacityThumbColor()\"\n ></div>\n </div>\n }\n\n <!-- Color Input \u2014 Figma 4456:115720 -->\n <div class=\"sui-color-picker__color-input\">\n <!-- Format label \"Hex\" + chevron \u2014 Figma 4456:115721.\n Hex-only por ahora (ver PENDING VERIFY en el .ts). -->\n @if (showFormatLabel()) {\n <div class=\"sui-color-picker__format\" aria-hidden=\"true\">\n <span class=\"sui-color-picker__format-label\">Hex</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"20\" class=\"sui-color-picker__format-chevron\" />\n </div>\n }\n\n <!-- Input row \u2014 Figma 4456:115724: sip | hex | opacity -->\n <div class=\"sui-color-picker__input-row\">\n <!-- Sip (eyedropper) \u2014 Figma 4456:115796. Solo con EyeDropper API. -->\n @if (showEyedropper()) {\n <button\n type=\"button\"\n class=\"sui-color-picker__sip\"\n aria-label=\"Cuentagotas\"\n (click)=\"onEyedropper()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n >\n <sui-icon name=\"sip-line\" [size]=\"20\" />\n </button>\n }\n\n <!-- Hex field \u2014 Figma 4456:115725 / 4456:115726: el texto va SIN\n prefijo '#' (Figma muestra \"335CFF\" pelado dentro de la celda). -->\n <div class=\"sui-color-picker__hex-cell\">\n <input\n class=\"sui-color-picker__hex-field\"\n type=\"text\"\n inputmode=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n maxlength=\"8\"\n aria-label=\"Valor hexadecimal\"\n [value]=\"hexDisplayValue()\"\n (input)=\"onHexInputChange($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n (blur)=\"onHexCommit()\"\n />\n </div>\n\n <!-- Opacity field \"%\" \u2014 Figma 4456:115727. Visible por default\n (alpha on); ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div class=\"sui-color-picker__opacity-cell\">\n <input\n class=\"sui-color-picker__opacity-field\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"3\"\n aria-label=\"Opacidad\"\n [value]=\"alphaPercent()\"\n (change)=\"onOpacityFieldCommit($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n />\n <span class=\"sui-color-picker__opacity-suffix\" aria-hidden=\"true\">%</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Secci\u00F3n \"Recommended Colors\" \u2014 Figma 4456:115765 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--recommended\">\n <p class=\"sui-color-picker__panel-label\">{{ recommendedLabel() }}</p>\n <div class=\"sui-color-picker__grid\" role=\"radiogroup\">\n @for (c of colors(); track c) {\n <sui-color-dot\n [color]=\"c\"\n [state]=\"currentPreset() === c ? 'selected' : 'default'\"\n (clicked)=\"onPresetClick(c)\"\n />\n }\n </div>\n </div>\n </div>\n </ng-template>\n</sui-dropdown-menu>\n", styles: ["@charset \"UTF-8\";:host{position:relative;display:inline-block;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0}.sui-color-picker__trigger{display:inline-flex;align-items:center;gap:8px;padding:6px 10px 6px 6px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);cursor:pointer;appearance:none;font:inherit;color:var(--sui-text-strong-950);font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__trigger:hover{background:var(--sui-bg-weak-50)}:host([data-sui-open]) .sui-color-picker__trigger{border-color:var(--sui-stroke-strong-950, var(--sui-text-strong-950))}.sui-color-picker__trigger:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:2px}.sui-color-picker__trigger:active{transform:none}:host([data-sui-disabled]) .sui-color-picker__trigger{background:var(--sui-bg-weak-50);color:var(--sui-text-disabled-300);cursor:not-allowed;pointer-events:none}.sui-color-picker__placeholder-dot{display:inline-block;width:24px;height:24px;border-radius:50%;background:var(--sui-bg-soft-200)}.sui-color-picker__label{flex:1 0 auto;white-space:nowrap}.sui-color-picker__chevron{flex-shrink:0;color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-color-picker__chevron{transform:rotate(180deg)}.sui-color-picker__panel{width:272px;margin-top:6px;box-sizing:border-box;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-16);box-shadow:var(--sui-shadow-medium);overflow:hidden;display:flex;flex-direction:column;animation:sui-color-picker__fade var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}@keyframes sui-color-picker__fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sui-color-picker__section{box-sizing:border-box;display:flex;flex-direction:column;gap:12px;padding:16px;width:100%}.sui-color-picker__section--colors{border-bottom:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__section--recommended{gap:8px}:host([data-sui-presets-only]) .sui-color-picker__section--recommended{border-bottom:none}.sui-color-picker__canvas{position:relative;width:100%;height:232px;border-radius:var(--sui-radius-8);cursor:crosshair;-webkit-user-select:none;user-select:none;touch-action:none;overflow:hidden;background-color:var(--hue-color, #335cff);background-image:linear-gradient(to top,#000,#0000),linear-gradient(to right,#fff,#fff0)}.sui-color-picker__canvas-thumb{position:absolute;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__slider{position:relative;width:100%;height:16px;cursor:pointer;-webkit-user-select:none;user-select:none;touch-action:none}.sui-color-picker__slider-track{position:absolute;left:0;right:0;top:4px;height:8px;border-radius:var(--sui-radius-full);overflow:hidden}.sui-color-picker__hue .sui-color-picker__slider-track{background-image:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.sui-color-picker__opacity .sui-color-picker__slider-track{background-color:#fff;background-image:linear-gradient(to right,transparent,var(--opacity-color, #335cff)),conic-gradient(#ebebeb 0 25%,transparent 0 50%,#ebebeb 0 75%,transparent 0);background-size:auto,10.88px 10.88px}.sui-color-picker__slider-thumb{position:absolute;top:50%;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__opacity .sui-color-picker__slider-thumb{background-image:linear-gradient(var(--thumb-color, #335cff),var(--thumb-color, #335cff)),conic-gradient(#ebebeb 0 25%,#fff 0 50%,#ebebeb 0 75%,#fff 0);background-size:auto,6px 6px}.sui-color-picker__color-input{display:flex;flex-direction:column;gap:4px;width:100%}.sui-color-picker__format{display:flex;align-items:center;gap:2px;appearance:none;border:none;background:transparent;padding:0;cursor:default;font:inherit;color:var(--sui-text-strong-950)}.sui-color-picker__format-label{font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);white-space:nowrap}.sui-color-picker__format-chevron{flex-shrink:0;color:var(--sui-icon-sub-600)}.sui-color-picker__input-row{box-sizing:border-box;display:flex;align-items:stretch;width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);overflow:hidden}.sui-color-picker__sip{display:flex;align-items:center;justify-content:center;padding:6px;border:none;border-right:1px solid var(--sui-stroke-soft-200);background:var(--sui-bg-white-0);color:var(--sui-icon-sub-600);cursor:pointer;appearance:none;flex-shrink:0;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__sip:hover{background:var(--sui-bg-weak-50)}.sui-color-picker__sip:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:-2px}.sui-color-picker__sip:active{transform:none}.sui-color-picker__hex-cell{box-sizing:border-box;display:flex;align-items:center;flex:1 0 0;min-width:0;padding:6px 10px;border-right:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__hex-cell:last-child{border-right:none}.sui-color-picker__hex-field{flex:1 0 0;min-width:0;width:100%;border:none;outline:none;background:transparent;padding:0;appearance:none;color:var(--sui-text-strong-950);font-family:inherit;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);text-transform:uppercase}.sui-color-picker__hex-field::placeholder{color:var(--sui-text-soft-400);text-transform:none}.sui-color-picker__opacity-cell{box-sizing:border-box;display:flex;align-items:center;flex-shrink:0;padding:6px 10px}.sui-color-picker__opacity-field{width:3.5ch;border:none;outline:none;background:transparent;padding:0;appearance:none;text-align:right;color:var(--sui-text-sub-600);font-family:inherit;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)}.sui-color-picker__opacity-suffix{color:var(--sui-text-sub-600);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)}.sui-color-picker__panel-label{margin:0;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-color-picker__grid{display:flex;flex-wrap:wrap;gap:4px;width:100%}\n"], dependencies: [{ kind: "component", type: SuiIcon, selector: "sui-icon", inputs: ["name", "size", "color"] }, { kind: "component", type: SuiColorDot, selector: "sui-color-dot", inputs: ["color", "customHex", "state", "ariaLabel"], outputs: ["clicked"] }, { kind: "component", type: SuiDropdownMenu, selector: "sui-dropdown-menu", inputs: ["matchWidth", "minWidth", "position", "viewportMargin", "panelClass", "disabled", "popupRole", "origin"], outputs: ["openedChange"], exportAs: ["suiDropdownMenu"] }, { kind: "directive", type: SuiDropdownPanel, selector: "ng-template[suiDropdownPanel]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3777
3983
|
}
|
|
3778
3984
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiColorPicker, decorators: [{
|
|
3779
3985
|
type: Component,
|
|
3780
|
-
args: [{ selector: 'sui-color-picker', standalone: true, imports: [SuiIcon, SuiColorDot], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
3986
|
+
args: [{ selector: 'sui-color-picker', standalone: true, imports: [SuiIcon, SuiColorDot, SuiDropdownMenu, SuiDropdownPanel], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
3781
3987
|
'[attr.data-sui-open]': 'open() ? "" : null',
|
|
3782
3988
|
'[attr.data-sui-disabled]': 'disabled() ? "" : null',
|
|
3783
3989
|
'[attr.data-sui-presets-only]': 'presetsOnly() ? "" : null',
|
|
3784
|
-
}, template: "<button\n type=\"button\"\n class=\"sui-color-picker__trigger\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"open() ? 'true' : 'false'\"\n (click)=\"toggle()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n>\n @if (value()) {\n @if (currentPreset()) {\n <sui-color-dot [color]=\"currentPreset()!\" state=\"selected\" class=\"sui-color-picker__preview\" />\n } @else {\n <sui-color-dot [customHex]=\"previewColor()\" state=\"selected\" class=\"sui-color-picker__preview\" />\n }\n } @else {\n <span class=\"sui-color-picker__placeholder-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"sui-color-picker__label\">{{ currentLabel() }}</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"16\" class=\"sui-color-picker__chevron\" />\n</button>\n\n@if (open()) {\n <div\n class=\"sui-color-picker__panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n @if (!presetsOnly()) {\n <!-- Secci\u00F3n \"Colors\" \u2014 Figma 4456:115716 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--colors\">\n <!-- HSV Color Spectrum \u2014 Figma 4456:115425 -->\n <div\n #canvas\n class=\"sui-color-picker__canvas\"\n role=\"application\"\n aria-label=\"Saturaci\u00F3n y brillo\"\n [style.--hue-color]=\"hueColor()\"\n (pointerdown)=\"onCanvasPointerDown($event)\"\n (pointermove)=\"onCanvasPointerMove($event)\"\n (pointerup)=\"onCanvasPointerUp($event)\"\n (pointercancel)=\"onCanvasPointerUp($event)\"\n >\n <div\n class=\"sui-color-picker__canvas-thumb\"\n [style.left]=\"canvasThumbX()\"\n [style.top]=\"canvasThumbY()\"\n [style.background-color]=\"currentHex()\"\n ></div>\n </div>\n\n <!-- Hue slider \u2014 Figma 4415:53669 -->\n <div\n #hueSlider\n class=\"sui-color-picker__slider sui-color-picker__hue\"\n role=\"slider\"\n aria-label=\"Matiz\"\n aria-valuemin=\"0\"\n aria-valuemax=\"360\"\n [attr.aria-valuenow]=\"hueRounded()\"\n (pointerdown)=\"onHuePointerDown($event)\"\n (pointermove)=\"onHuePointerMove($event)\"\n (pointerup)=\"onHuePointerUp($event)\"\n (pointercancel)=\"onHuePointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"hueThumbX()\"\n [style.background-color]=\"hueColor()\"\n ></div>\n </div>\n\n <!-- Opacity slider \u2014 Figma 4415:53670. Visible por default (alpha on);\n ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div\n #opacitySlider\n class=\"sui-color-picker__slider sui-color-picker__opacity\"\n role=\"slider\"\n aria-label=\"Opacidad\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"alphaPercent()\"\n [style.--opacity-color]=\"opacityColor()\"\n (pointerdown)=\"onOpacityPointerDown($event)\"\n (pointermove)=\"onOpacityPointerMove($event)\"\n (pointerup)=\"onOpacityPointerUp($event)\"\n (pointercancel)=\"onOpacityPointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"opacityThumbX()\"\n [style.--thumb-color]=\"opacityThumbColor()\"\n ></div>\n </div>\n }\n\n <!-- Color Input \u2014 Figma 4456:115720 -->\n <div class=\"sui-color-picker__color-input\">\n <!-- Format label \"Hex\" + chevron \u2014 Figma 4456:115721.\n Hex-only por ahora (ver PENDING VERIFY en el .ts). -->\n @if (showFormatLabel()) {\n <div class=\"sui-color-picker__format\" aria-hidden=\"true\">\n <span class=\"sui-color-picker__format-label\">Hex</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"20\" class=\"sui-color-picker__format-chevron\" />\n </div>\n }\n\n <!-- Input row \u2014 Figma 4456:115724: sip | hex | opacity -->\n <div class=\"sui-color-picker__input-row\">\n <!-- Sip (eyedropper) \u2014 Figma 4456:115796. Solo con EyeDropper API. -->\n @if (showEyedropper()) {\n <button\n type=\"button\"\n class=\"sui-color-picker__sip\"\n aria-label=\"Cuentagotas\"\n (click)=\"onEyedropper()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n >\n <sui-icon name=\"sip-line\" [size]=\"20\" />\n </button>\n }\n\n <!-- Hex field \u2014 Figma 4456:115725 / 4456:115726: el texto va SIN\n prefijo '#' (Figma muestra \"335CFF\" pelado dentro de la celda). -->\n <div class=\"sui-color-picker__hex-cell\">\n <input\n class=\"sui-color-picker__hex-field\"\n type=\"text\"\n inputmode=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n maxlength=\"8\"\n aria-label=\"Valor hexadecimal\"\n [value]=\"hexDisplayValue()\"\n (input)=\"onHexInputChange($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n (blur)=\"onHexCommit()\"\n />\n </div>\n\n <!-- Opacity field \"%\" \u2014 Figma 4456:115727. Visible por default\n (alpha on); ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div class=\"sui-color-picker__opacity-cell\">\n <input\n class=\"sui-color-picker__opacity-field\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"3\"\n aria-label=\"Opacidad\"\n [value]=\"alphaPercent()\"\n (change)=\"onOpacityFieldCommit($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n />\n <span class=\"sui-color-picker__opacity-suffix\" aria-hidden=\"true\">%</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Secci\u00F3n \"Recommended Colors\" \u2014 Figma 4456:115765 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--recommended\">\n <p class=\"sui-color-picker__panel-label\">{{ recommendedLabel() }}</p>\n <div class=\"sui-color-picker__grid\" role=\"radiogroup\">\n @for (c of colors(); track c) {\n <sui-color-dot\n [color]=\"c\"\n [state]=\"currentPreset() === c ? 'selected' : 'default'\"\n (clicked)=\"onPresetClick(c)\"\n />\n }\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;display:inline-block;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0}.sui-color-picker__trigger{display:inline-flex;align-items:center;gap:8px;padding:6px 10px 6px 6px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);cursor:pointer;appearance:none;font:inherit;color:var(--sui-text-strong-950);font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__trigger:hover{background:var(--sui-bg-weak-50)}:host([data-sui-open]) .sui-color-picker__trigger{border-color:var(--sui-stroke-strong-950, var(--sui-text-strong-950))}.sui-color-picker__trigger:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:2px}.sui-color-picker__trigger:active{transform:none}:host([data-sui-disabled]) .sui-color-picker__trigger{background:var(--sui-bg-weak-50);color:var(--sui-text-disabled-300);cursor:not-allowed;pointer-events:none}.sui-color-picker__placeholder-dot{display:inline-block;width:24px;height:24px;border-radius:50%;background:var(--sui-bg-soft-200)}.sui-color-picker__label{flex:1 0 auto;white-space:nowrap}.sui-color-picker__chevron{flex-shrink:0;color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-color-picker__chevron{transform:rotate(180deg)}.sui-color-picker__panel{position:absolute;top:calc(100% + 6px);left:0;z-index:100;width:272px;box-sizing:border-box;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-16);box-shadow:var(--sui-shadow-medium);overflow:hidden;display:flex;flex-direction:column;animation:sui-color-picker__fade var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}@keyframes sui-color-picker__fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sui-color-picker__section{box-sizing:border-box;display:flex;flex-direction:column;gap:12px;padding:16px;width:100%}.sui-color-picker__section--colors{border-bottom:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__section--recommended{gap:8px}:host([data-sui-presets-only]) .sui-color-picker__section--recommended{border-bottom:none}.sui-color-picker__canvas{position:relative;width:100%;height:232px;border-radius:var(--sui-radius-8);cursor:crosshair;-webkit-user-select:none;user-select:none;touch-action:none;overflow:hidden;background-color:var(--hue-color, #335cff);background-image:linear-gradient(to top,#000,#0000),linear-gradient(to right,#fff,#fff0)}.sui-color-picker__canvas-thumb{position:absolute;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__slider{position:relative;width:100%;height:16px;cursor:pointer;-webkit-user-select:none;user-select:none;touch-action:none}.sui-color-picker__slider-track{position:absolute;left:0;right:0;top:4px;height:8px;border-radius:var(--sui-radius-full);overflow:hidden}.sui-color-picker__hue .sui-color-picker__slider-track{background-image:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.sui-color-picker__opacity .sui-color-picker__slider-track{background-color:#fff;background-image:linear-gradient(to right,transparent,var(--opacity-color, #335cff)),conic-gradient(#ebebeb 0 25%,transparent 0 50%,#ebebeb 0 75%,transparent 0);background-size:auto,10.88px 10.88px}.sui-color-picker__slider-thumb{position:absolute;top:50%;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__opacity .sui-color-picker__slider-thumb{background-image:linear-gradient(var(--thumb-color, #335cff),var(--thumb-color, #335cff)),conic-gradient(#ebebeb 0 25%,#fff 0 50%,#ebebeb 0 75%,#fff 0);background-size:auto,6px 6px}.sui-color-picker__color-input{display:flex;flex-direction:column;gap:4px;width:100%}.sui-color-picker__format{display:flex;align-items:center;gap:2px;appearance:none;border:none;background:transparent;padding:0;cursor:default;font:inherit;color:var(--sui-text-strong-950)}.sui-color-picker__format-label{font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);white-space:nowrap}.sui-color-picker__format-chevron{flex-shrink:0;color:var(--sui-icon-sub-600)}.sui-color-picker__input-row{box-sizing:border-box;display:flex;align-items:stretch;width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);overflow:hidden}.sui-color-picker__sip{display:flex;align-items:center;justify-content:center;padding:6px;border:none;border-right:1px solid var(--sui-stroke-soft-200);background:var(--sui-bg-white-0);color:var(--sui-icon-sub-600);cursor:pointer;appearance:none;flex-shrink:0;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__sip:hover{background:var(--sui-bg-weak-50)}.sui-color-picker__sip:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:-2px}.sui-color-picker__sip:active{transform:none}.sui-color-picker__hex-cell{box-sizing:border-box;display:flex;align-items:center;flex:1 0 0;min-width:0;padding:6px 10px;border-right:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__hex-cell:last-child{border-right:none}.sui-color-picker__hex-field{flex:1 0 0;min-width:0;width:100%;border:none;outline:none;background:transparent;padding:0;appearance:none;color:var(--sui-text-strong-950);font-family:inherit;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);text-transform:uppercase}.sui-color-picker__hex-field::placeholder{color:var(--sui-text-soft-400);text-transform:none}.sui-color-picker__opacity-cell{box-sizing:border-box;display:flex;align-items:center;flex-shrink:0;padding:6px 10px}.sui-color-picker__opacity-field{width:3.5ch;border:none;outline:none;background:transparent;padding:0;appearance:none;text-align:right;color:var(--sui-text-sub-600);font-family:inherit;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)}.sui-color-picker__opacity-suffix{color:var(--sui-text-sub-600);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)}.sui-color-picker__panel-label{margin:0;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-color-picker__grid{display:flex;flex-wrap:wrap;gap:4px;width:100%}\n"] }]
|
|
3785
|
-
}], propDecorators: { colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], recommendedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "recommendedLabel", required: false }] }], presetsOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "presetsOnly", required: false }] }], alpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "alpha", required: false }] }], eyedropper: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyedropper", required: false }] }], showFormatLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFormatLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], change: [{ type: i0.Output, args: ["change"] }], canvasRef: [{ type: i0.ViewChild, args: ['canvas', { isSignal: true }] }], hueRef: [{ type: i0.ViewChild, args: ['hueSlider', { isSignal: true }] }], opacityRef: [{ type: i0.ViewChild, args: ['opacitySlider', { isSignal: true }] }]
|
|
3786
|
-
type: HostListener,
|
|
3787
|
-
args: ['document:click', ['$event.target']]
|
|
3788
|
-
}], onEscape: [{
|
|
3789
|
-
type: HostListener,
|
|
3790
|
-
args: ['document:keydown.escape']
|
|
3791
|
-
}] } });
|
|
3990
|
+
}, template: "<button\n #trigger\n type=\"button\"\n class=\"sui-color-picker__trigger\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-expanded]=\"open() ? 'true' : 'false'\"\n (click)=\"toggle()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n>\n @if (value()) {\n @if (currentPreset()) {\n <sui-color-dot [color]=\"currentPreset()!\" state=\"selected\" class=\"sui-color-picker__preview\" />\n } @else {\n <sui-color-dot [customHex]=\"previewColor()\" state=\"selected\" class=\"sui-color-picker__preview\" />\n }\n } @else {\n <span class=\"sui-color-picker__placeholder-dot\" aria-hidden=\"true\"></span>\n }\n <span class=\"sui-color-picker__label\">{{ currentLabel() }}</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"16\" class=\"sui-color-picker__chevron\" />\n</button>\n\n<!-- Panel en CDK overlay (via sui-dropdown-menu): escapa cualquier overflow\n clipping del contenedor (Storybook docs, modales, tablas). El contenido del\n ng-template mantiene el scoping de estilos del componente. -->\n<sui-dropdown-menu\n [origin]=\"trigger\"\n [disabled]=\"disabled()\"\n panelClass=\"sui-color-picker__overlay-pane\"\n (openedChange)=\"onMenuOpenedChange($event)\"\n>\n <ng-template suiDropdownPanel>\n <div\n class=\"sui-color-picker__panel\"\n role=\"dialog\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n @if (!presetsOnly()) {\n <!-- Secci\u00F3n \"Colors\" \u2014 Figma 4456:115716 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--colors\">\n <!-- HSV Color Spectrum \u2014 Figma 4456:115425 -->\n <div\n #canvas\n class=\"sui-color-picker__canvas\"\n role=\"application\"\n aria-label=\"Saturaci\u00F3n y brillo\"\n [style.--hue-color]=\"hueColor()\"\n (pointerdown)=\"onCanvasPointerDown($event)\"\n (pointermove)=\"onCanvasPointerMove($event)\"\n (pointerup)=\"onCanvasPointerUp($event)\"\n (pointercancel)=\"onCanvasPointerUp($event)\"\n >\n <div\n class=\"sui-color-picker__canvas-thumb\"\n [style.left]=\"canvasThumbX()\"\n [style.top]=\"canvasThumbY()\"\n [style.background-color]=\"currentHex()\"\n ></div>\n </div>\n\n <!-- Hue slider \u2014 Figma 4415:53669 -->\n <div\n #hueSlider\n class=\"sui-color-picker__slider sui-color-picker__hue\"\n role=\"slider\"\n aria-label=\"Matiz\"\n aria-valuemin=\"0\"\n aria-valuemax=\"360\"\n [attr.aria-valuenow]=\"hueRounded()\"\n (pointerdown)=\"onHuePointerDown($event)\"\n (pointermove)=\"onHuePointerMove($event)\"\n (pointerup)=\"onHuePointerUp($event)\"\n (pointercancel)=\"onHuePointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"hueThumbX()\"\n [style.background-color]=\"hueColor()\"\n ></div>\n </div>\n\n <!-- Opacity slider \u2014 Figma 4415:53670. Visible por default (alpha on);\n ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div\n #opacitySlider\n class=\"sui-color-picker__slider sui-color-picker__opacity\"\n role=\"slider\"\n aria-label=\"Opacidad\"\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n [attr.aria-valuenow]=\"alphaPercent()\"\n [style.--opacity-color]=\"opacityColor()\"\n (pointerdown)=\"onOpacityPointerDown($event)\"\n (pointermove)=\"onOpacityPointerMove($event)\"\n (pointerup)=\"onOpacityPointerUp($event)\"\n (pointercancel)=\"onOpacityPointerUp($event)\"\n >\n <div class=\"sui-color-picker__slider-track\"></div>\n <div\n class=\"sui-color-picker__slider-thumb\"\n [style.left]=\"opacityThumbX()\"\n [style.--thumb-color]=\"opacityThumbColor()\"\n ></div>\n </div>\n }\n\n <!-- Color Input \u2014 Figma 4456:115720 -->\n <div class=\"sui-color-picker__color-input\">\n <!-- Format label \"Hex\" + chevron \u2014 Figma 4456:115721.\n Hex-only por ahora (ver PENDING VERIFY en el .ts). -->\n @if (showFormatLabel()) {\n <div class=\"sui-color-picker__format\" aria-hidden=\"true\">\n <span class=\"sui-color-picker__format-label\">Hex</span>\n <sui-icon name=\"arrow-down-s-line\" [size]=\"20\" class=\"sui-color-picker__format-chevron\" />\n </div>\n }\n\n <!-- Input row \u2014 Figma 4456:115724: sip | hex | opacity -->\n <div class=\"sui-color-picker__input-row\">\n <!-- Sip (eyedropper) \u2014 Figma 4456:115796. Solo con EyeDropper API. -->\n @if (showEyedropper()) {\n <button\n type=\"button\"\n class=\"sui-color-picker__sip\"\n aria-label=\"Cuentagotas\"\n (click)=\"onEyedropper()\"\n (touchstart)=\"$event.currentTarget\"\n (touchend)=\"$any($event.currentTarget).blur()\"\n >\n <sui-icon name=\"sip-line\" [size]=\"20\" />\n </button>\n }\n\n <!-- Hex field \u2014 Figma 4456:115725 / 4456:115726: el texto va SIN\n prefijo '#' (Figma muestra \"335CFF\" pelado dentro de la celda). -->\n <div class=\"sui-color-picker__hex-cell\">\n <input\n class=\"sui-color-picker__hex-field\"\n type=\"text\"\n inputmode=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n maxlength=\"8\"\n aria-label=\"Valor hexadecimal\"\n [value]=\"hexDisplayValue()\"\n (input)=\"onHexInputChange($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n (blur)=\"onHexCommit()\"\n />\n </div>\n\n <!-- Opacity field \"%\" \u2014 Figma 4456:115727. Visible por default\n (alpha on); ocultable con [alpha]=false. -->\n @if (alpha()) {\n <div class=\"sui-color-picker__opacity-cell\">\n <input\n class=\"sui-color-picker__opacity-field\"\n type=\"text\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"3\"\n aria-label=\"Opacidad\"\n [value]=\"alphaPercent()\"\n (change)=\"onOpacityFieldCommit($event)\"\n (keydown)=\"onHexKeyDown($event)\"\n />\n <span class=\"sui-color-picker__opacity-suffix\" aria-hidden=\"true\">%</span>\n </div>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- Secci\u00F3n \"Recommended Colors\" \u2014 Figma 4456:115765 -->\n <div class=\"sui-color-picker__section sui-color-picker__section--recommended\">\n <p class=\"sui-color-picker__panel-label\">{{ recommendedLabel() }}</p>\n <div class=\"sui-color-picker__grid\" role=\"radiogroup\">\n @for (c of colors(); track c) {\n <sui-color-dot\n [color]=\"c\"\n [state]=\"currentPreset() === c ? 'selected' : 'default'\"\n (clicked)=\"onPresetClick(c)\"\n />\n }\n </div>\n </div>\n </div>\n </ng-template>\n</sui-dropdown-menu>\n", styles: ["@charset \"UTF-8\";:host{position:relative;display:inline-block;font-family:var(--sui-font-sans);font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0}.sui-color-picker__trigger{display:inline-flex;align-items:center;gap:8px;padding:6px 10px 6px 6px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);cursor:pointer;appearance:none;font:inherit;color:var(--sui-text-strong-950);font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out),border-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__trigger:hover{background:var(--sui-bg-weak-50)}:host([data-sui-open]) .sui-color-picker__trigger{border-color:var(--sui-stroke-strong-950, var(--sui-text-strong-950))}.sui-color-picker__trigger:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:2px}.sui-color-picker__trigger:active{transform:none}:host([data-sui-disabled]) .sui-color-picker__trigger{background:var(--sui-bg-weak-50);color:var(--sui-text-disabled-300);cursor:not-allowed;pointer-events:none}.sui-color-picker__placeholder-dot{display:inline-block;width:24px;height:24px;border-radius:50%;background:var(--sui-bg-soft-200)}.sui-color-picker__label{flex:1 0 auto;white-space:nowrap}.sui-color-picker__chevron{flex-shrink:0;color:var(--sui-icon-sub-600);transition:transform var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}:host([data-sui-open]) .sui-color-picker__chevron{transform:rotate(180deg)}.sui-color-picker__panel{width:272px;margin-top:6px;box-sizing:border-box;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-16);box-shadow:var(--sui-shadow-medium);overflow:hidden;display:flex;flex-direction:column;animation:sui-color-picker__fade var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}@keyframes sui-color-picker__fade{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sui-color-picker__section{box-sizing:border-box;display:flex;flex-direction:column;gap:12px;padding:16px;width:100%}.sui-color-picker__section--colors{border-bottom:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__section--recommended{gap:8px}:host([data-sui-presets-only]) .sui-color-picker__section--recommended{border-bottom:none}.sui-color-picker__canvas{position:relative;width:100%;height:232px;border-radius:var(--sui-radius-8);cursor:crosshair;-webkit-user-select:none;user-select:none;touch-action:none;overflow:hidden;background-color:var(--hue-color, #335cff);background-image:linear-gradient(to top,#000,#0000),linear-gradient(to right,#fff,#fff0)}.sui-color-picker__canvas-thumb{position:absolute;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__slider{position:relative;width:100%;height:16px;cursor:pointer;-webkit-user-select:none;user-select:none;touch-action:none}.sui-color-picker__slider-track{position:absolute;left:0;right:0;top:4px;height:8px;border-radius:var(--sui-radius-full);overflow:hidden}.sui-color-picker__hue .sui-color-picker__slider-track{background-image:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.sui-color-picker__opacity .sui-color-picker__slider-track{background-color:#fff;background-image:linear-gradient(to right,transparent,var(--opacity-color, #335cff)),conic-gradient(#ebebeb 0 25%,transparent 0 50%,#ebebeb 0 75%,transparent 0);background-size:auto,10.88px 10.88px}.sui-color-picker__slider-thumb{position:absolute;top:50%;width:16px;height:16px;border-radius:50%;border:2px solid var(--sui-static-white, #fff);box-shadow:0 0 0 1px #00000026,0 1px 2px #0003;transform:translate(-50%,-50%);pointer-events:none}.sui-color-picker__opacity .sui-color-picker__slider-thumb{background-image:linear-gradient(var(--thumb-color, #335cff),var(--thumb-color, #335cff)),conic-gradient(#ebebeb 0 25%,#fff 0 50%,#ebebeb 0 75%,#fff 0);background-size:auto,6px 6px}.sui-color-picker__color-input{display:flex;flex-direction:column;gap:4px;width:100%}.sui-color-picker__format{display:flex;align-items:center;gap:2px;appearance:none;border:none;background:transparent;padding:0;cursor:default;font:inherit;color:var(--sui-text-strong-950)}.sui-color-picker__format-label{font-size:var(--sui-type-label-sm-size);font-weight:var(--sui-type-label-sm-weight);line-height:var(--sui-type-label-sm-line);letter-spacing:var(--sui-type-label-sm-spacing);white-space:nowrap}.sui-color-picker__format-chevron{flex-shrink:0;color:var(--sui-icon-sub-600)}.sui-color-picker__input-row{box-sizing:border-box;display:flex;align-items:stretch;width:100%;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-8);overflow:hidden}.sui-color-picker__sip{display:flex;align-items:center;justify-content:center;padding:6px;border:none;border-right:1px solid var(--sui-stroke-soft-200);background:var(--sui-bg-white-0);color:var(--sui-icon-sub-600);cursor:pointer;appearance:none;flex-shrink:0;transition:background-color var(--sui-motion-duration-x-fast) var(--sui-motion-ease-out)}.sui-color-picker__sip:hover{background:var(--sui-bg-weak-50)}.sui-color-picker__sip:focus-visible{outline:2px solid var(--sui-stroke-strong-950, var(--sui-text-strong-950));outline-offset:-2px}.sui-color-picker__sip:active{transform:none}.sui-color-picker__hex-cell{box-sizing:border-box;display:flex;align-items:center;flex:1 0 0;min-width:0;padding:6px 10px;border-right:1px solid var(--sui-stroke-soft-200)}.sui-color-picker__hex-cell:last-child{border-right:none}.sui-color-picker__hex-field{flex:1 0 0;min-width:0;width:100%;border:none;outline:none;background:transparent;padding:0;appearance:none;color:var(--sui-text-strong-950);font-family:inherit;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);text-transform:uppercase}.sui-color-picker__hex-field::placeholder{color:var(--sui-text-soft-400);text-transform:none}.sui-color-picker__opacity-cell{box-sizing:border-box;display:flex;align-items:center;flex-shrink:0;padding:6px 10px}.sui-color-picker__opacity-field{width:3.5ch;border:none;outline:none;background:transparent;padding:0;appearance:none;text-align:right;color:var(--sui-text-sub-600);font-family:inherit;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)}.sui-color-picker__opacity-suffix{color:var(--sui-text-sub-600);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)}.sui-color-picker__panel-label{margin:0;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-color-picker__grid{display:flex;flex-wrap:wrap;gap:4px;width:100%}\n"] }]
|
|
3991
|
+
}], propDecorators: { colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], recommendedLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "recommendedLabel", required: false }] }], presetsOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "presetsOnly", required: false }] }], alpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "alpha", required: false }] }], eyedropper: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyedropper", required: false }] }], showFormatLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFormatLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], change: [{ type: i0.Output, args: ["change"] }], _menu: [{ type: i0.ViewChild, args: [i0.forwardRef(() => SuiDropdownMenu), { isSignal: true }] }], canvasRef: [{ type: i0.ViewChild, args: ['canvas', { isSignal: true }] }], hueRef: [{ type: i0.ViewChild, args: ['hueSlider', { isSignal: true }] }], opacityRef: [{ type: i0.ViewChild, args: ['opacitySlider', { isSignal: true }] }] } });
|
|
3792
3992
|
|
|
3793
3993
|
class SuiKbd {
|
|
3794
3994
|
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
@@ -4476,218 +4676,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
4476
4676
|
}, template: "<div class=\"sui-dropdown-item__leading\">\n <ng-content select=\"[slot=leading]\" />\n</div>\n\n<div class=\"sui-dropdown-item__text\">\n <span class=\"sui-dropdown-item__label\">{{ label() }}</span>\n @if (hasSublabel()) {\n <span class=\"sui-dropdown-item__sublabel\">{{ sublabel() }}</span>\n }\n @if (hasDescription()) {\n <span class=\"sui-dropdown-item__description\">{{ description() }}</span>\n }\n</div>\n\n<div class=\"sui-dropdown-item__trailing\">\n <!-- Canon trailing-slot (Figma 405:6432): el consumer proyecta en este orden DOM\n fijo \u2192 badge primero, luego shortcut (provisto por el input shortcut() abajo),\n luego toggle/button al final. El gap del flex (8px) los separa.\n Pill button (variante Large): bg primary-alpha-10, p-6, radius-8, label primary\n Inter Medium 14/20. Link button (variante Small): texto primary sin bg.\n El componente no fija sublots \u2014 el orden lo controla el consumer seg\u00FAn este\n patr\u00F3n para mantener consistencia visual vs Figma. -->\n <ng-content select=\"[slot=trailing]\" />\n @if (shortcut()) {\n <span class=\"sui-dropdown-item__shortcut\">{{ shortcut() }}</span>\n }\n @if (showCheck()) {\n <!-- Check icon autom\u00E1tico en mode='option' cuando selected=true.\n Remixicon check-line (ri-check-line) v\u00EDa sui-icon \u2014 mismo glyph que\n el resto del proyecto, color heredado de .sui-dropdown-item__check. -->\n <sui-icon class=\"sui-dropdown-item__check\" name=\"check-line\" [size]=\"20\" />\n }\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:center;gap:8px;padding:8px;background:var(--sui-bg-white-0);border-radius:var(--sui-radius-8, 8px);cursor:pointer;outline:none;width:100%;box-sizing:border-box;font-family:var(--sui-font-sans);transition:background .1s ease-out,box-shadow .1s ease-out;-webkit-user-select:none;user-select:none}:host:hover{background:var(--sui-bg-weak-50)}:host:active:not([data-sui-disabled]),:host:focus-visible{box-shadow:0 0 0 2px var(--sui-bg-white-0),0 0 0 4px var(--sui-primary-alpha-10)}:host([data-sui-size=small]){min-height:36px;padding:8px;gap:8px}:host([data-sui-size=large]){min-height:56px;padding:8px;gap:12px;border-radius:var(--sui-radius-10, 10px)}:host([data-sui-size=large]) .sui-dropdown-item__text{flex-direction:column;align-items:flex-start;gap:4px}:host([data-sui-size=large]) .sui-dropdown-item__label{font-weight:var(--sui-type-label-sm-weight, 500)}:host([data-sui-size=xlarge]){min-height:76px;padding:8px;gap:16px;border-radius:var(--sui-radius-12, 12px)}:host([data-sui-size=xlarge]) .sui-dropdown-item__text{flex-direction:column;align-items:flex-start;gap:4px}:host([data-sui-size=xlarge]) .sui-dropdown-item__label{font-size:var(--sui-type-label-md-size, 16px);line-height:var(--sui-type-label-md-line, 24px);letter-spacing:var(--sui-type-label-md-spacing, -.011em);font-weight:var(--sui-type-label-md-weight, 500)}:host([data-sui-size=xlarge]) .sui-dropdown-item__description{font-size:var(--sui-type-paragraph-sm-size, 14px);line-height:var(--sui-type-paragraph-sm-line, 20px);letter-spacing:var(--sui-type-paragraph-sm-spacing, -.006em)}.sui-dropdown-item__leading{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center}.sui-dropdown-item__leading:empty{display:none}:host([data-sui-size=large][data-sui-framed]) .sui-dropdown-item__leading,:host([data-sui-size=xlarge][data-sui-framed]) .sui-dropdown-item__leading{padding:10px;border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-full, 999px);box-shadow:var(--sui-regular-shadow-x-small, 0 1px 2px 0 rgba(10, 13, 20, .031372549));box-sizing:border-box}:host([data-sui-size=xlarge][data-sui-framed]) .sui-dropdown-item__leading{padding:12px}.sui-dropdown-item__text{flex:1 1 0;min-width:0;display:flex;align-items:center;gap:4px;font-feature-settings:\"ss11\" 1,\"calt\" 0,\"liga\" 0}.sui-dropdown-item__label{font-size:var(--sui-type-paragraph-sm-size, 14px);line-height:var(--sui-type-paragraph-sm-line, 20px);letter-spacing:var(--sui-type-paragraph-sm-spacing, -.006em);font-weight:var(--sui-type-paragraph-sm-weight, 400);color:var(--sui-text-strong-950);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sui-dropdown-item__sublabel{font-size:var(--sui-type-paragraph-xs-size, 12px);line-height:var(--sui-type-paragraph-xs-line, 16px);letter-spacing:var(--sui-type-paragraph-xs-spacing, 0);font-weight:var(--sui-type-paragraph-xs-weight, 400);color:var(--sui-text-soft-400);flex-shrink:0}.sui-dropdown-item__description{font-size:var(--sui-type-paragraph-xs-size, 12px);line-height:var(--sui-type-paragraph-xs-line, 16px);letter-spacing:var(--sui-type-paragraph-xs-spacing, 0);font-weight:var(--sui-type-paragraph-xs-weight, 400);color:var(--sui-text-sub-600);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.sui-dropdown-item__trailing{flex-shrink:0;display:inline-flex;align-items:center;gap:8px}.sui-dropdown-item__trailing:empty{display:none}.sui-dropdown-item__shortcut{display:inline-flex;align-items:center;padding:2px 6px;background:var(--sui-bg-white-0);border:1px solid var(--sui-stroke-soft-200);border-radius:var(--sui-radius-4, 4px);font-family:var(--sui-font-sans);font-size:12px;line-height:16px;font-weight:500;color:var(--sui-text-sub-600);letter-spacing:.04em;text-transform:uppercase;white-space:nowrap;flex-shrink:0}:host([data-sui-mode=option][data-sui-selected]){background:var(--sui-primary-alpha-10)}:host([data-sui-mode=option][data-sui-selected]) .sui-dropdown-item__label,:host([data-sui-mode=option][data-sui-selected]) .sui-dropdown-item__sublabel,:host([data-sui-mode=option][data-sui-selected]) .sui-dropdown-item__check{color:var(--sui-primary-base)}:host([data-sui-mode=option][data-sui-selected]):hover{background:var(--sui-primary-alpha-16)}.sui-dropdown-item__check{width:20px;height:20px;flex-shrink:0;color:var(--sui-primary-base)}:host([data-sui-highlighted]:not([data-sui-selected])){background:var(--sui-bg-weak-50)}:host([data-sui-disabled]){cursor:not-allowed;pointer-events:none}:host([data-sui-disabled]) .sui-dropdown-item__label,:host([data-sui-disabled]) .sui-dropdown-item__sublabel,:host([data-sui-disabled]) .sui-dropdown-item__description{color:var(--sui-text-disabled-300)}:host([data-sui-disabled]) .sui-dropdown-item__leading{color:var(--sui-icon-disabled-300, #d1d1d1)}:host([data-sui-disabled]) .sui-dropdown-item__leading>:not(sui-icon){opacity:.48}:host([data-sui-disabled]):hover{background:var(--sui-bg-white-0)}\n"] }]
|
|
4477
4677
|
}], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], sublabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "sublabel", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], leadingFramed: [{ type: i0.Input, args: [{ isSignal: true, alias: "leadingFramed", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], selected: [{ type: i0.Input, args: [{ isSignal: true, alias: "selected", required: false }] }], highlighted: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlighted", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
|
|
4478
4678
|
|
|
4479
|
-
/**
|
|
4480
|
-
* Structural directive — marca un `<ng-template>` como panel del
|
|
4481
|
-
* sui-dropdown-menu. El componente padre captura este TemplateRef
|
|
4482
|
-
* via `@ContentChild(SuiDropdownPanel)` y lo monta en el CDK Overlay
|
|
4483
|
-
* cuando se abre el menu.
|
|
4484
|
-
*
|
|
4485
|
-
* Usa el patrón canon Angular (similar a `*matMenuContent` de Material):
|
|
4486
|
-
* un directive que se aplica al `<ng-template>` SE convierte en una
|
|
4487
|
-
* marca semántica, evitando que Angular renderee el contenido inline
|
|
4488
|
-
* cuando no hay `<ng-content>` matching para el template.
|
|
4489
|
-
*
|
|
4490
|
-
* Uso:
|
|
4491
|
-
* <sui-dropdown-menu>
|
|
4492
|
-
* <sui-compact-select trigger ... />
|
|
4493
|
-
* <ng-template suiDropdownPanel>
|
|
4494
|
-
* <sui-dropdown-item ...></sui-dropdown-item>
|
|
4495
|
-
* </ng-template>
|
|
4496
|
-
* </sui-dropdown-menu>
|
|
4497
|
-
*/
|
|
4498
|
-
class SuiDropdownPanel {
|
|
4499
|
-
template = inject(TemplateRef);
|
|
4500
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownPanel, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
4501
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.17", type: SuiDropdownPanel, isStandalone: true, selector: "ng-template[suiDropdownPanel]", ngImport: i0 });
|
|
4502
|
-
}
|
|
4503
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownPanel, decorators: [{
|
|
4504
|
-
type: Directive,
|
|
4505
|
-
args: [{
|
|
4506
|
-
selector: 'ng-template[suiDropdownPanel]',
|
|
4507
|
-
standalone: true,
|
|
4508
|
-
}]
|
|
4509
|
-
}] });
|
|
4510
|
-
|
|
4511
|
-
/* Posiciones con fallback HORIZONTAL: la primera (start-aligned, abre a la
|
|
4512
|
-
derecha) es la default; si el trigger está pegado al borde derecho y no entra,
|
|
4513
|
-
CDK cae a la end-aligned (abre hacia la izquierda) y recién después flipea
|
|
4514
|
-
vertical. Sin esto, un trigger en la esquina derecha (ej. kebab ⋮ de una card)
|
|
4515
|
-
recorta el panel fuera del viewport. */
|
|
4516
|
-
const POSITIONS_BELOW = [
|
|
4517
|
-
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
4518
|
-
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
4519
|
-
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
4520
|
-
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
4521
|
-
];
|
|
4522
|
-
const POSITIONS_ABOVE = [
|
|
4523
|
-
{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom', offsetY: -4 },
|
|
4524
|
-
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -4 },
|
|
4525
|
-
{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4 },
|
|
4526
|
-
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 4 },
|
|
4527
|
-
];
|
|
4528
|
-
class SuiDropdownMenu {
|
|
4529
|
-
/** Si true, el panel matchea el ancho del trigger. Default: auto width. */
|
|
4530
|
-
matchWidth = input(false, ...(ngDevMode ? [{ debugName: "matchWidth" }] : /* istanbul ignore next */ []));
|
|
4531
|
-
/** Min-width fijo del panel (px). Si matchWidth + minWidth: `max(triggerWidth, minWidth)`. */
|
|
4532
|
-
minWidth = input(null, ...(ngDevMode ? [{ debugName: "minWidth" }] : /* istanbul ignore next */ []));
|
|
4533
|
-
/** Position primary. Default: auto = below con fallback above. */
|
|
4534
|
-
position = input('auto', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
4535
|
-
/** Margen 8px del viewport edge (canon SUI). */
|
|
4536
|
-
viewportMargin = input(8, ...(ngDevMode ? [{ debugName: "viewportMargin" }] : /* istanbul ignore next */ []));
|
|
4537
|
-
/** Panel custom class para overrides de bg/padding/etc desde el consumer. */
|
|
4538
|
-
panelClass = input('', ...(ngDevMode ? [{ debugName: "panelClass" }] : /* istanbul ignore next */ []));
|
|
4539
|
-
/** Disabled — no abre el menu al clickear el trigger. */
|
|
4540
|
-
disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
|
|
4541
|
-
/**
|
|
4542
|
-
* Rol del popup para `aria-haspopup` del trigger. Default 'menu' (los items
|
|
4543
|
-
* proyectados llevan role="menuitem"). Los consumers de tipo listbox
|
|
4544
|
-
* (sui-select / compact-selects, items con role="option") DEBEN pasar
|
|
4545
|
-
* `popupRole="listbox"`. Ver SuiDropdownMenuPopupRole.
|
|
4546
|
-
*/
|
|
4547
|
-
popupRole = input('menu', ...(ngDevMode ? [{ debugName: "popupRole" }] : /* istanbul ignore next */ []));
|
|
4548
|
-
/**
|
|
4549
|
-
* Origin externo. Si presente, el menu se ancla a ese elemento y NO renderea
|
|
4550
|
-
* el trigger wrapper interno (el parent maneja el click). Caso de uso:
|
|
4551
|
-
* compact-selects donde el host element es el trigger visual.
|
|
4552
|
-
*/
|
|
4553
|
-
origin = input(null, ...(ngDevMode ? [{ debugName: "origin" }] : /* istanbul ignore next */ []));
|
|
4554
|
-
openedChange = output();
|
|
4555
|
-
/** Signal pública — wire al `[open]` del trigger para visual state. */
|
|
4556
|
-
isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
|
|
4557
|
-
/** Wrapper del trigger projection — captura el click. NO existe si `[origin]` se pasa. */
|
|
4558
|
-
_triggerWrap;
|
|
4559
|
-
/** Panel directive proyectado — capturado via `[suiDropdownPanel]` en un ng-template. */
|
|
4560
|
-
_panel;
|
|
4561
|
-
_getTriggerEl() {
|
|
4562
|
-
const o = this.origin();
|
|
4563
|
-
if (o)
|
|
4564
|
-
return o instanceof ElementRef ? o.nativeElement : o;
|
|
4565
|
-
return this._triggerWrap?.nativeElement ?? null;
|
|
4566
|
-
}
|
|
4567
|
-
_vcr = inject(ViewContainerRef);
|
|
4568
|
-
_destroyRef = inject(DestroyRef);
|
|
4569
|
-
_overlay = inject(Overlay);
|
|
4570
|
-
_overlayRef = null;
|
|
4571
|
-
_overlaySubs = null;
|
|
4572
|
-
_resizeObserver = null;
|
|
4573
|
-
constructor() {
|
|
4574
|
-
this._destroyRef.onDestroy(() => this.close());
|
|
4575
|
-
}
|
|
4576
|
-
onTriggerClick(event) {
|
|
4577
|
-
if (this.disabled())
|
|
4578
|
-
return;
|
|
4579
|
-
event.stopPropagation();
|
|
4580
|
-
this.toggle();
|
|
4581
|
-
}
|
|
4582
|
-
onTriggerKeydown(event) {
|
|
4583
|
-
if (this.disabled())
|
|
4584
|
-
return;
|
|
4585
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
4586
|
-
event.preventDefault();
|
|
4587
|
-
this.toggle();
|
|
4588
|
-
}
|
|
4589
|
-
else if (event.key === 'ArrowDown') {
|
|
4590
|
-
event.preventDefault();
|
|
4591
|
-
this.open();
|
|
4592
|
-
}
|
|
4593
|
-
}
|
|
4594
|
-
toggle() {
|
|
4595
|
-
if (this.isOpen())
|
|
4596
|
-
this.close();
|
|
4597
|
-
else
|
|
4598
|
-
this.open();
|
|
4599
|
-
}
|
|
4600
|
-
open() {
|
|
4601
|
-
if (this.disabled() || this._overlayRef || !this._panel)
|
|
4602
|
-
return;
|
|
4603
|
-
const triggerEl = this._getTriggerEl();
|
|
4604
|
-
if (!triggerEl)
|
|
4605
|
-
return;
|
|
4606
|
-
const positions = this.position() === 'above' ? POSITIONS_ABOVE : POSITIONS_BELOW;
|
|
4607
|
-
const positionStrategy = this._overlay
|
|
4608
|
-
.position()
|
|
4609
|
-
.flexibleConnectedTo(triggerEl)
|
|
4610
|
-
.withPositions(positions)
|
|
4611
|
-
.withPush(false)
|
|
4612
|
-
.withFlexibleDimensions(true)
|
|
4613
|
-
.withViewportMargin(this.viewportMargin());
|
|
4614
|
-
const triggerWidth = triggerEl.getBoundingClientRect().width;
|
|
4615
|
-
const minW = this.minWidth();
|
|
4616
|
-
const effectiveMinWidth = this.matchWidth() && minW !== null
|
|
4617
|
-
? Math.max(triggerWidth, minW)
|
|
4618
|
-
: minW;
|
|
4619
|
-
const config = {
|
|
4620
|
-
positionStrategy,
|
|
4621
|
-
scrollStrategy: this._overlay.scrollStrategies.reposition(),
|
|
4622
|
-
hasBackdrop: true,
|
|
4623
|
-
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
4624
|
-
panelClass: ['sui-dropdown-menu__overlay-pane', this.panelClass()].filter(Boolean),
|
|
4625
|
-
disposeOnNavigation: true,
|
|
4626
|
-
};
|
|
4627
|
-
if (this.matchWidth() && minW === null) {
|
|
4628
|
-
config.width = `${triggerWidth}px`;
|
|
4629
|
-
}
|
|
4630
|
-
if (effectiveMinWidth !== null) {
|
|
4631
|
-
config.minWidth = effectiveMinWidth;
|
|
4632
|
-
}
|
|
4633
|
-
this._overlayRef = this._overlay.create(config);
|
|
4634
|
-
const portal = new TemplatePortal(this._panel.template, this._vcr);
|
|
4635
|
-
this._overlayRef.attach(portal);
|
|
4636
|
-
/* Width sync mientras el viewport cambia (canon sui-select). Solo aplica
|
|
4637
|
-
cuando matchWidth fija width o minWidth — para que el panel siga el trigger. */
|
|
4638
|
-
if (this.matchWidth() && typeof ResizeObserver !== 'undefined') {
|
|
4639
|
-
this._resizeObserver = new ResizeObserver(() => {
|
|
4640
|
-
if (!this._overlayRef)
|
|
4641
|
-
return;
|
|
4642
|
-
const w = triggerEl.getBoundingClientRect().width;
|
|
4643
|
-
if (minW === null) {
|
|
4644
|
-
this._overlayRef.updateSize({ width: `${w}px` });
|
|
4645
|
-
}
|
|
4646
|
-
else {
|
|
4647
|
-
this._overlayRef.updateSize({ minWidth: Math.max(w, minW) });
|
|
4648
|
-
}
|
|
4649
|
-
this._overlayRef.updatePosition();
|
|
4650
|
-
});
|
|
4651
|
-
this._resizeObserver.observe(triggerEl);
|
|
4652
|
-
}
|
|
4653
|
-
this._overlaySubs = new Subscription();
|
|
4654
|
-
this._overlaySubs.add(this._overlayRef.backdropClick().subscribe(() => this.close()));
|
|
4655
|
-
this._overlaySubs.add(this._overlayRef.keydownEvents().subscribe((e) => {
|
|
4656
|
-
if (e.key === 'Escape')
|
|
4657
|
-
this.close();
|
|
4658
|
-
}));
|
|
4659
|
-
this._overlaySubs.add(this._overlayRef.detachments().subscribe(() => {
|
|
4660
|
-
this.isOpen.set(false);
|
|
4661
|
-
}));
|
|
4662
|
-
this.isOpen.set(true);
|
|
4663
|
-
this.openedChange.emit(true);
|
|
4664
|
-
}
|
|
4665
|
-
close() {
|
|
4666
|
-
if (!this._overlayRef)
|
|
4667
|
-
return;
|
|
4668
|
-
this._overlaySubs?.unsubscribe();
|
|
4669
|
-
this._overlaySubs = null;
|
|
4670
|
-
this._resizeObserver?.disconnect();
|
|
4671
|
-
this._resizeObserver = null;
|
|
4672
|
-
this._overlayRef.dispose();
|
|
4673
|
-
this._overlayRef = null;
|
|
4674
|
-
this.isOpen.set(false);
|
|
4675
|
-
this.openedChange.emit(false);
|
|
4676
|
-
}
|
|
4677
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
4678
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: SuiDropdownMenu, isStandalone: true, selector: "sui-dropdown-menu", inputs: { matchWidth: { classPropertyName: "matchWidth", publicName: "matchWidth", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, viewportMargin: { classPropertyName: "viewportMargin", publicName: "viewportMargin", isSignal: true, isRequired: false, transformFunction: null }, panelClass: { classPropertyName: "panelClass", publicName: "panelClass", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, popupRole: { classPropertyName: "popupRole", publicName: "popupRole", isSignal: true, isRequired: false, transformFunction: null }, origin: { classPropertyName: "origin", publicName: "origin", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { openedChange: "openedChange" }, queries: [{ propertyName: "_panel", first: true, predicate: SuiDropdownPanel, descendants: true }], viewQueries: [{ propertyName: "_triggerWrap", first: true, predicate: ["triggerWrap"], descendants: true }], exportAs: ["suiDropdownMenu"], ngImport: i0, template: "<!-- Trigger wrapper \u2014 captura click y keydown del trigger child. Solo se\n renderea cuando NO se pasa [origin] (modo content-projection canon).\n Cuando se pasa [origin], el parent maneja el trigger y llama\n menu.toggle() desde su propio click handler. -->\n@if (!origin()) {\n <span\n #triggerWrap\n class=\"sui-dropdown-menu__trigger\"\n [attr.aria-haspopup]=\"popupRole()\"\n [attr.aria-expanded]=\"isOpen()\"\n (click)=\"onTriggerClick($event)\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <ng-content select=\"[trigger]\" />\n </span>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-dropdown-menu__trigger{display:inline-block;cursor:pointer;outline:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
4679
|
-
}
|
|
4680
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: SuiDropdownMenu, decorators: [{
|
|
4681
|
-
type: Component,
|
|
4682
|
-
args: [{ selector: 'sui-dropdown-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, exportAs: 'suiDropdownMenu', template: "<!-- Trigger wrapper \u2014 captura click y keydown del trigger child. Solo se\n renderea cuando NO se pasa [origin] (modo content-projection canon).\n Cuando se pasa [origin], el parent maneja el trigger y llama\n menu.toggle() desde su propio click handler. -->\n@if (!origin()) {\n <span\n #triggerWrap\n class=\"sui-dropdown-menu__trigger\"\n [attr.aria-haspopup]=\"popupRole()\"\n [attr.aria-expanded]=\"isOpen()\"\n (click)=\"onTriggerClick($event)\"\n (keydown)=\"onTriggerKeydown($event)\"\n >\n <ng-content select=\"[trigger]\" />\n </span>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.sui-dropdown-menu__trigger{display:inline-block;cursor:pointer;outline:none}\n"] }]
|
|
4683
|
-
}], ctorParameters: () => [], propDecorators: { matchWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "matchWidth", required: false }] }], minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], viewportMargin: [{ type: i0.Input, args: [{ isSignal: true, alias: "viewportMargin", required: false }] }], panelClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelClass", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], popupRole: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupRole", required: false }] }], origin: [{ type: i0.Input, args: [{ isSignal: true, alias: "origin", required: false }] }], openedChange: [{ type: i0.Output, args: ["openedChange"] }], _triggerWrap: [{
|
|
4684
|
-
type: ViewChild,
|
|
4685
|
-
args: ['triggerWrap', { static: false }]
|
|
4686
|
-
}], _panel: [{
|
|
4687
|
-
type: ContentChild,
|
|
4688
|
-
args: [SuiDropdownPanel]
|
|
4689
|
-
}] } });
|
|
4690
|
-
|
|
4691
4679
|
class SuiCompactSelectForInput {
|
|
4692
4680
|
size = input('medium', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
|
|
4693
4681
|
value = input('', ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
@@ -14603,8 +14591,13 @@ class SuiTable {
|
|
|
14603
14591
|
let sx = 0, sy = 0, lx = 0, ly = 0;
|
|
14604
14592
|
let axis = null;
|
|
14605
14593
|
let pageScroller = null;
|
|
14606
|
-
/* Velocidad vertical (px/ms)
|
|
14607
|
-
|
|
14594
|
+
/* Velocidad vertical (px/ms) para el fling. CRÍTICO: se estima con una
|
|
14595
|
+
ventana de samples (~100ms) tipo VelocityTracker de Android — NO con el
|
|
14596
|
+
último move suelto: el dedo siempre desacelera antes de soltar, así que
|
|
14597
|
+
la velocidad instantánea final es ~0 y el fling moría → scroll "lento". */
|
|
14598
|
+
let vy = 0, momentumRaf = 0, momentumTs = 0;
|
|
14599
|
+
const samples = [];
|
|
14600
|
+
const VELOCITY_WINDOW_MS = 100;
|
|
14608
14601
|
const findPageScroller = () => {
|
|
14609
14602
|
let n = el.parentElement;
|
|
14610
14603
|
while (n && n !== this.doc.body) {
|
|
@@ -14631,7 +14624,8 @@ class SuiTable {
|
|
|
14631
14624
|
sy = ly = t.clientY;
|
|
14632
14625
|
axis = null;
|
|
14633
14626
|
vy = 0;
|
|
14634
|
-
|
|
14627
|
+
samples.length = 0;
|
|
14628
|
+
samples.push({ y: t.clientY, t: e.timeStamp });
|
|
14635
14629
|
pageScroller = findPageScroller();
|
|
14636
14630
|
};
|
|
14637
14631
|
const onMove = (e) => {
|
|
@@ -14657,22 +14651,27 @@ class SuiTable {
|
|
|
14657
14651
|
el.scrollLeft -= t.clientX - lx;
|
|
14658
14652
|
}
|
|
14659
14653
|
else if (pageScroller) {
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
vy = dy / dt; // px/ms (positivo = dedo bajando)
|
|
14654
|
+
pageScroller.scrollTop -= t.clientY - ly;
|
|
14655
|
+
samples.push({ y: t.clientY, t: e.timeStamp });
|
|
14656
|
+
while (samples.length > 1 && e.timeStamp - samples[0].t > VELOCITY_WINDOW_MS)
|
|
14657
|
+
samples.shift();
|
|
14665
14658
|
}
|
|
14666
14659
|
e.preventDefault();
|
|
14667
14660
|
lx = t.clientX;
|
|
14668
14661
|
ly = t.clientY;
|
|
14669
|
-
lastT = e.timeStamp;
|
|
14670
14662
|
};
|
|
14671
14663
|
const onEnd = () => {
|
|
14672
14664
|
/* Fling: continúa el scroll de la página con la velocidad de salida y
|
|
14673
14665
|
fricción exponencial frame-rate-independent (para que en 120Hz no vuele).
|
|
14674
14666
|
Replica el momentum nativo que el manejo manual del touch pierde. */
|
|
14675
|
-
if (axis !== 'y' || !pageScroller
|
|
14667
|
+
if (axis !== 'y' || !pageScroller)
|
|
14668
|
+
return;
|
|
14669
|
+
/* Velocidad de salida = promedio de la ventana (primer→último sample). */
|
|
14670
|
+
const first = samples[0];
|
|
14671
|
+
const last = samples[samples.length - 1];
|
|
14672
|
+
const win = last && first ? last.t - first.t : 0;
|
|
14673
|
+
vy = win > 0 ? (last.y - first.y) / win : 0;
|
|
14674
|
+
if (Math.abs(vy) < 0.05)
|
|
14676
14675
|
return;
|
|
14677
14676
|
const scroller = pageScroller;
|
|
14678
14677
|
momentumTs = 0;
|