@eagami/ui 1.5.0 → 2.0.0

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, makeEnvironmentProviders, inject, signal, computed, Injectable, input, ChangeDetectionStrategy, Component, HostBinding, Directive, model, output, viewChild, forwardRef, HostListener, ElementRef, Renderer2, Injector, effect, untracked, afterNextRender, ViewEncapsulation, DestroyRef, contentChild, viewChildren } from '@angular/core';
2
+ import { InjectionToken, makeEnvironmentProviders, signal, inject, effect, computed, Injectable, input, ChangeDetectionStrategy, Component, HostBinding, Directive, model, output, viewChild, forwardRef, HostListener, ElementRef, Renderer2, Injector, untracked, afterNextRender, ViewEncapsulation, DestroyRef, contentChild, viewChildren } from '@angular/core';
3
3
  import { NgClass, NgTemplateOutlet } from '@angular/common';
4
4
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
5
5
 
@@ -34,6 +34,18 @@ function provideEagamiUi(config = {}) {
34
34
  return makeEnvironmentProviders([{ provide: EAGAMI_I18N_CONFIG, useValue: config }]);
35
35
  }
36
36
 
37
+ /**
38
+ * Module-level signal that lets external tooling (notably the Storybook
39
+ * preview decorator) imperatively override the active locale on a running
40
+ * `EagamiI18nService` without re-bootstrapping the Angular application.
41
+ *
42
+ * `null` means "no override" — the service uses its constructor-time locale.
43
+ *
44
+ * @internal Not part of the public API. Library consumers should call
45
+ * `EagamiI18nService.setLocale()` instead.
46
+ */
47
+ const _eagamiI18nLocaleOverride = signal(null, ...(ngDevMode ? [{ debugName: "_eagamiI18nLocaleOverride" }] : /* istanbul ignore next */ []));
48
+
37
49
  /** Greek messages. */
38
50
  const el = {
39
51
  alert: {
@@ -98,6 +110,15 @@ const el = {
98
110
  menu: {
99
111
  label: 'Μενού',
100
112
  },
113
+ multiSelect: {
114
+ placeholder: 'Επιλέξτε…',
115
+ searchPlaceholder: 'Αναζήτηση…',
116
+ searchEmpty: 'Δεν βρέθηκαν αποτελέσματα',
117
+ selectAll: 'Επιλογή όλων',
118
+ clearAll: 'Εκκαθάριση επιλογής',
119
+ removeOption: label => `Αφαίρεση ${label}`,
120
+ selectedCount: count => `${count} επιλεγμέν${count === 1 ? 'ο' : 'α'}`,
121
+ },
101
122
  paginator: {
102
123
  label: 'Σελιδοποίηση',
103
124
  rowsPerPage: 'Γραμμές ανά σελίδα:',
@@ -111,9 +132,27 @@ const el = {
111
132
  spinner: {
112
133
  label: 'Φόρτωση',
113
134
  },
135
+ stepper: {
136
+ optional: 'προαιρετικό',
137
+ },
114
138
  tag: {
115
139
  remove: 'Αφαίρεση',
116
140
  },
141
+ timePicker: {
142
+ placeholder: 'Επιλογή ώρας…',
143
+ clear: 'Καθαρισμός ώρας',
144
+ hoursLabel: 'Ώρες',
145
+ minutesLabel: 'Λεπτά',
146
+ secondsLabel: 'Δευτερόλεπτα',
147
+ incrementHours: 'Αύξηση ωρών',
148
+ decrementHours: 'Μείωση ωρών',
149
+ incrementMinutes: 'Αύξηση λεπτών',
150
+ decrementMinutes: 'Μείωση λεπτών',
151
+ incrementSeconds: 'Αύξηση δευτερολέπτων',
152
+ decrementSeconds: 'Μείωση δευτερολέπτων',
153
+ amLabel: 'πμ',
154
+ pmLabel: 'μμ',
155
+ },
117
156
  toast: {
118
157
  dismiss: 'Απόρριψη',
119
158
  },
@@ -187,6 +226,15 @@ const en = {
187
226
  menu: {
188
227
  label: 'Menu',
189
228
  },
229
+ multiSelect: {
230
+ placeholder: 'Select…',
231
+ searchPlaceholder: 'Search…',
232
+ searchEmpty: 'No matches',
233
+ selectAll: 'Select all',
234
+ clearAll: 'Clear selection',
235
+ removeOption: label => `Remove ${label}`,
236
+ selectedCount: count => `${count} selected`,
237
+ },
190
238
  paginator: {
191
239
  label: 'Pagination',
192
240
  rowsPerPage: 'Rows per page:',
@@ -200,9 +248,27 @@ const en = {
200
248
  spinner: {
201
249
  label: 'Loading',
202
250
  },
251
+ stepper: {
252
+ optional: 'optional',
253
+ },
203
254
  tag: {
204
255
  remove: 'Remove',
205
256
  },
257
+ timePicker: {
258
+ placeholder: 'Select time…',
259
+ clear: 'Clear time',
260
+ hoursLabel: 'Hours',
261
+ minutesLabel: 'Minutes',
262
+ secondsLabel: 'Seconds',
263
+ incrementHours: 'Increment hours',
264
+ decrementHours: 'Decrement hours',
265
+ incrementMinutes: 'Increment minutes',
266
+ decrementMinutes: 'Decrement minutes',
267
+ incrementSeconds: 'Increment seconds',
268
+ decrementSeconds: 'Decrement seconds',
269
+ amLabel: 'AM',
270
+ pmLabel: 'PM',
271
+ },
206
272
  toast: {
207
273
  dismiss: 'Dismiss',
208
274
  },
@@ -276,6 +342,15 @@ const esES = {
276
342
  menu: {
277
343
  label: 'Menú',
278
344
  },
345
+ multiSelect: {
346
+ placeholder: 'Seleccionar…',
347
+ searchPlaceholder: 'Buscar…',
348
+ searchEmpty: 'Sin coincidencias',
349
+ selectAll: 'Seleccionar todo',
350
+ clearAll: 'Borrar selección',
351
+ removeOption: label => `Eliminar ${label}`,
352
+ selectedCount: count => `${count} seleccionado${count === 1 ? '' : 's'}`,
353
+ },
279
354
  paginator: {
280
355
  label: 'Paginación',
281
356
  rowsPerPage: 'Filas por página:',
@@ -289,9 +364,27 @@ const esES = {
289
364
  spinner: {
290
365
  label: 'Cargando',
291
366
  },
367
+ stepper: {
368
+ optional: 'opcional',
369
+ },
292
370
  tag: {
293
371
  remove: 'Eliminar',
294
372
  },
373
+ timePicker: {
374
+ placeholder: 'Seleccionar hora…',
375
+ clear: 'Borrar hora',
376
+ hoursLabel: 'Horas',
377
+ minutesLabel: 'Minutos',
378
+ secondsLabel: 'Segundos',
379
+ incrementHours: 'Aumentar horas',
380
+ decrementHours: 'Disminuir horas',
381
+ incrementMinutes: 'Aumentar minutos',
382
+ decrementMinutes: 'Disminuir minutos',
383
+ incrementSeconds: 'Aumentar segundos',
384
+ decrementSeconds: 'Disminuir segundos',
385
+ amLabel: 'AM',
386
+ pmLabel: 'PM',
387
+ },
295
388
  toast: {
296
389
  dismiss: 'Descartar',
297
390
  },
@@ -365,6 +458,15 @@ const frFR = {
365
458
  menu: {
366
459
  label: 'Menu',
367
460
  },
461
+ multiSelect: {
462
+ placeholder: 'Sélectionner…',
463
+ searchPlaceholder: 'Rechercher…',
464
+ searchEmpty: 'Aucun résultat',
465
+ selectAll: 'Tout sélectionner',
466
+ clearAll: 'Effacer la sélection',
467
+ removeOption: label => `Supprimer ${label}`,
468
+ selectedCount: count => `${count} sélectionné${count > 1 ? 's' : ''}`,
469
+ },
368
470
  paginator: {
369
471
  label: 'Pagination',
370
472
  rowsPerPage: 'Lignes par page :',
@@ -378,9 +480,27 @@ const frFR = {
378
480
  spinner: {
379
481
  label: 'Chargement',
380
482
  },
483
+ stepper: {
484
+ optional: 'facultatif',
485
+ },
381
486
  tag: {
382
487
  remove: 'Supprimer',
383
488
  },
489
+ timePicker: {
490
+ placeholder: 'Sélectionner une heure…',
491
+ clear: "Effacer l'heure",
492
+ hoursLabel: 'Heures',
493
+ minutesLabel: 'Minutes',
494
+ secondsLabel: 'Secondes',
495
+ incrementHours: 'Augmenter les heures',
496
+ decrementHours: 'Diminuer les heures',
497
+ incrementMinutes: 'Augmenter les minutes',
498
+ decrementMinutes: 'Diminuer les minutes',
499
+ incrementSeconds: 'Augmenter les secondes',
500
+ decrementSeconds: 'Diminuer les secondes',
501
+ amLabel: 'AM',
502
+ pmLabel: 'PM',
503
+ },
384
504
  toast: {
385
505
  dismiss: 'Fermer',
386
506
  },
@@ -454,6 +574,15 @@ const pl = {
454
574
  menu: {
455
575
  label: 'Menu',
456
576
  },
577
+ multiSelect: {
578
+ placeholder: 'Wybierz…',
579
+ searchPlaceholder: 'Szukaj…',
580
+ searchEmpty: 'Brak wyników',
581
+ selectAll: 'Zaznacz wszystko',
582
+ clearAll: 'Wyczyść wybór',
583
+ removeOption: label => `Usuń ${label}`,
584
+ selectedCount: count => `Wybrano: ${count}`,
585
+ },
457
586
  paginator: {
458
587
  label: 'Paginacja',
459
588
  rowsPerPage: 'Wierszy na stronę:',
@@ -467,9 +596,27 @@ const pl = {
467
596
  spinner: {
468
597
  label: 'Ładowanie',
469
598
  },
599
+ stepper: {
600
+ optional: 'opcjonalny',
601
+ },
470
602
  tag: {
471
603
  remove: 'Usuń',
472
604
  },
605
+ timePicker: {
606
+ placeholder: 'Wybierz godzinę…',
607
+ clear: 'Wyczyść godzinę',
608
+ hoursLabel: 'Godziny',
609
+ minutesLabel: 'Minuty',
610
+ secondsLabel: 'Sekundy',
611
+ incrementHours: 'Zwiększ godziny',
612
+ decrementHours: 'Zmniejsz godziny',
613
+ incrementMinutes: 'Zwiększ minuty',
614
+ decrementMinutes: 'Zmniejsz minuty',
615
+ incrementSeconds: 'Zwiększ sekundy',
616
+ decrementSeconds: 'Zmniejsz sekundy',
617
+ amLabel: 'AM',
618
+ pmLabel: 'PM',
619
+ },
473
620
  toast: {
474
621
  dismiss: 'Zamknij',
475
622
  },
@@ -504,9 +651,20 @@ function applyOverrides(base, overrides) {
504
651
  */
505
652
  class EagamiI18nService {
506
653
  config = inject(EAGAMI_I18N_CONFIG, { optional: true });
507
- _locale = signal(this.config?.locale ?? 'en', ...(ngDevMode ? [{ debugName: "_locale" }] : /* istanbul ignore next */ []));
654
+ _locale = signal(_eagamiI18nLocaleOverride() ?? this.config?.locale ?? 'en', ...(ngDevMode ? [{ debugName: "_locale" }] : /* istanbul ignore next */ []));
508
655
  /** The currently active locale. Read it reactively or call `setLocale()`. */
509
656
  locale = this._locale.asReadonly();
657
+ constructor() {
658
+ // Pick up tooling-driven locale changes (Storybook globals dropdown). The
659
+ // override signal is `null` in production — this effect is a no-op for
660
+ // real applications.
661
+ effect(() => {
662
+ const override = _eagamiI18nLocaleOverride();
663
+ if (override !== null && EAGAMI_MESSAGES[override]) {
664
+ this._locale.set(override);
665
+ }
666
+ });
667
+ }
510
668
  /** The resolved message dictionary for the active locale. */
511
669
  messages = computed(() => {
512
670
  const base = EAGAMI_MESSAGES[this._locale()] ?? en;
@@ -523,7 +681,7 @@ class EagamiI18nService {
523
681
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: EagamiI18nService, decorators: [{
524
682
  type: Injectable,
525
683
  args: [{ providedIn: 'root' }]
526
- }] });
684
+ }], ctorParameters: () => [] });
527
685
 
528
686
  // =============================================================================
529
687
  // EAGAMI UI — French spacing helper
@@ -1630,6 +1788,149 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
1630
1788
  args: [{ selector: 'ea-skeleton', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ea-skeleton\"\n [class.ea-skeleton--text]=\"variant() === 'text'\"\n [class.ea-skeleton--circle]=\"variant() === 'circle'\"\n [class.ea-skeleton--rect]=\"variant() === 'rect'\"\n [class.ea-skeleton--animated]=\"animated()\"\n [style]=\"hostStyles()\"\n aria-hidden=\"true\">\n</div>\n", styles: [".ea-skeleton{display:block;background-color:var(--color-bg-muted);border-radius:var(--radius-md)}.ea-skeleton--text{width:100%;height:1rem;border-radius:var(--radius-sm)}.ea-skeleton--circle{width:2.5rem;height:2.5rem;border-radius:var(--radius-full)}.ea-skeleton--rect{width:100%;height:6rem}.ea-skeleton--animated{animation:ea-skeleton-pulse 1.5s ease-in-out infinite}@keyframes ea-skeleton-pulse{0%,to{opacity:1}50%{opacity:.4}}@media(prefers-reduced-motion:reduce){.ea-skeleton--animated{animation:none}}\n"] }]
1631
1789
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], width: [{ type: i0.Input, args: [{ isSignal: true, alias: "width", required: false }] }], height: [{ type: i0.Input, args: [{ isSignal: true, alias: "height", required: false }] }], animated: [{ type: i0.Input, args: [{ isSignal: true, alias: "animated", required: false }] }] } });
1632
1790
 
1791
+ /** True for cardinal placements that centre the popover on the perpendicular axis. */
1792
+ function isCardinal(placement) {
1793
+ return (placement === 'top' ||
1794
+ placement === 'bottom' ||
1795
+ placement === 'left' ||
1796
+ placement === 'right');
1797
+ }
1798
+ /** The dominant side of a placement (`top-start` → `top`, `bottom` → `bottom`, etc.). */
1799
+ function side(placement) {
1800
+ if (placement.startsWith('top'))
1801
+ return 'top';
1802
+ if (placement.startsWith('bottom'))
1803
+ return 'bottom';
1804
+ if (placement === 'left')
1805
+ return 'left';
1806
+ return 'right';
1807
+ }
1808
+ /** Maps `top → bottom`, `bottom-start → top-start`, etc. for flip logic. */
1809
+ function flipPlacement(placement) {
1810
+ if (placement === 'top')
1811
+ return 'bottom';
1812
+ if (placement === 'bottom')
1813
+ return 'top';
1814
+ if (placement === 'left')
1815
+ return 'right';
1816
+ if (placement === 'right')
1817
+ return 'left';
1818
+ if (placement === 'top-start')
1819
+ return 'bottom-start';
1820
+ if (placement === 'top-end')
1821
+ return 'bottom-end';
1822
+ if (placement === 'bottom-start')
1823
+ return 'top-start';
1824
+ return 'top-end';
1825
+ }
1826
+ /** Computes the top/left for a given placement without any flip or clamp logic. */
1827
+ function placeRaw(anchor, popover, placement, offset) {
1828
+ const s = side(placement);
1829
+ let top = 0;
1830
+ let left = 0;
1831
+ if (s === 'top') {
1832
+ top = anchor.top - popover.height - offset;
1833
+ }
1834
+ else if (s === 'bottom') {
1835
+ top = anchor.bottom + offset;
1836
+ }
1837
+ else if (s === 'left') {
1838
+ left = anchor.left - popover.width - offset;
1839
+ }
1840
+ else {
1841
+ left = anchor.right + offset;
1842
+ }
1843
+ if (s === 'top' || s === 'bottom') {
1844
+ if (isCardinal(placement)) {
1845
+ left = anchor.left + (anchor.width - popover.width) / 2;
1846
+ }
1847
+ else if (placement === 'top-start' || placement === 'bottom-start') {
1848
+ left = anchor.left;
1849
+ }
1850
+ else {
1851
+ left = anchor.right - popover.width;
1852
+ }
1853
+ }
1854
+ else {
1855
+ top = anchor.top + (anchor.height - popover.height) / 2;
1856
+ }
1857
+ return { top, left };
1858
+ }
1859
+ /**
1860
+ * Computes the viewport-space top/left for a popover anchored to `anchorRect`,
1861
+ * applying optional flip-on-overflow and edge-clamp logic. Pure function — no
1862
+ * DOM access. Both `<ea-popover>` and `[eaTooltip]` consume this.
1863
+ *
1864
+ * @param anchorRect The anchor element's `getBoundingClientRect()`.
1865
+ * @param popoverRect Width and height of the popover (post-render measurement).
1866
+ * @param viewport Viewport dimensions (`window.innerWidth/Height`).
1867
+ * @param options Placement and behavior flags.
1868
+ */
1869
+ function computePopoverPosition(anchorRect, popoverRect, viewport, options) {
1870
+ const offset = options.offset ?? 4;
1871
+ const margin = options.margin ?? 8;
1872
+ const flip = options.flip ?? true;
1873
+ const clamp = options.clamp ?? true;
1874
+ let placement = options.placement;
1875
+ let pos = placeRaw(anchorRect, popoverRect, placement, offset);
1876
+ if (flip) {
1877
+ const overflowsTop = pos.top < margin;
1878
+ const overflowsBottom = pos.top + popoverRect.height > viewport.height - margin;
1879
+ const overflowsLeft = pos.left < margin;
1880
+ const overflowsRight = pos.left + popoverRect.width > viewport.width - margin;
1881
+ const s = side(placement);
1882
+ const shouldFlip = (s === 'top' && overflowsTop) ||
1883
+ (s === 'bottom' && overflowsBottom) ||
1884
+ (s === 'left' && overflowsLeft) ||
1885
+ (s === 'right' && overflowsRight);
1886
+ if (shouldFlip) {
1887
+ const flipped = flipPlacement(placement);
1888
+ const flippedPos = placeRaw(anchorRect, popoverRect, flipped, offset);
1889
+ const flippedFitsBetter = (s === 'top' &&
1890
+ flippedPos.top + popoverRect.height <= viewport.height - margin) ||
1891
+ (s === 'bottom' && flippedPos.top >= margin) ||
1892
+ (s === 'left' &&
1893
+ flippedPos.left + popoverRect.width <= viewport.width - margin) ||
1894
+ (s === 'right' && flippedPos.left >= margin);
1895
+ if (flippedFitsBetter) {
1896
+ placement = flipped;
1897
+ pos = flippedPos;
1898
+ }
1899
+ }
1900
+ }
1901
+ if (clamp) {
1902
+ // Only clamp the cross-axis (perpendicular to the placement). For
1903
+ // bottom-side placements we clamp `left` so the popover doesn't slip off
1904
+ // the left/right of the viewport, but we leave `top` alone — clamping it
1905
+ // when the popover is taller than the available space below the anchor
1906
+ // would yank it up over the anchor itself (the common Storybook-docs-
1907
+ // iframe failure mode where viewports are short). Better to let it
1908
+ // overflow and scroll than to overlap its own trigger.
1909
+ const s = side(placement);
1910
+ const isVertical = s === 'top' || s === 'bottom';
1911
+ if (isVertical) {
1912
+ const maxLeft = viewport.width - popoverRect.width - margin;
1913
+ pos = {
1914
+ top: pos.top,
1915
+ left: Math.max(margin, Math.min(pos.left, Math.max(margin, maxLeft))),
1916
+ };
1917
+ }
1918
+ else {
1919
+ const maxTop = viewport.height - popoverRect.height - margin;
1920
+ pos = {
1921
+ top: Math.max(margin, Math.min(pos.top, Math.max(margin, maxTop))),
1922
+ left: pos.left,
1923
+ };
1924
+ }
1925
+ }
1926
+ return {
1927
+ top: pos.top,
1928
+ left: pos.left,
1929
+ placement,
1930
+ ...(options.matchAnchorWidth ? { width: anchorRect.width } : {}),
1931
+ };
1932
+ }
1933
+
1633
1934
  /**
1634
1935
  * Attaches a positioned tooltip to its host element. Shows on hover and
1635
1936
  * focus, hides on leave/blur or Escape, and wires up `aria-describedby` so
@@ -1822,39 +2123,17 @@ class TooltipDirective {
1822
2123
  }
1823
2124
  }
1824
2125
  const tooltipRect = this.tooltipEl.getBoundingClientRect();
1825
- const gap = 8;
1826
- /* Keep at least this much breathing room between the tooltip and the
1827
- viewport edge so the rounded corner and shadow don't kiss the chrome. */
1828
- const edgePadding = 8;
1829
- let top;
1830
- let left;
1831
- switch (this.tooltipPosition()) {
1832
- case 'top':
1833
- top = hostRect.top - tooltipRect.height - gap;
1834
- left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
1835
- break;
1836
- case 'bottom':
1837
- top = hostRect.bottom + gap;
1838
- left = hostRect.left + (hostRect.width - tooltipRect.width) / 2;
1839
- break;
1840
- case 'left':
1841
- top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
1842
- left = hostRect.left - tooltipRect.width - gap;
1843
- break;
1844
- case 'right':
1845
- top = hostRect.top + (hostRect.height - tooltipRect.height) / 2;
1846
- left = hostRect.right + gap;
1847
- break;
1848
- }
1849
- /* Clamp to the viewport so tooltips on near-edge triggers shift inward
1850
- rather than getting clipped by the chrome. The position arrow (the small
1851
- caret) stays centered on the host because the clamp only moves the
1852
- bubble; we don't try to flip placement here, just nudge along the
1853
- cross-axis. */
1854
- const viewportWidth = document.documentElement.clientWidth;
1855
- const viewportHeight = document.documentElement.clientHeight;
1856
- left = Math.max(edgePadding, Math.min(left, viewportWidth - tooltipRect.width - edgePadding));
1857
- top = Math.max(edgePadding, Math.min(top, viewportHeight - tooltipRect.height - edgePadding));
2126
+ /* Defer placement math to the shared popover positioning helper. `flip:
2127
+ false` preserves the tooltip's long-standing "stay on the requested
2128
+ side, just nudge inward at the edges" behavior the caret is centered
2129
+ on the host and would point at empty space if we flipped. `margin: 8`
2130
+ keeps the same breathing room between the bubble and the viewport edge
2131
+ as before. */
2132
+ const placed = computePopoverPosition(hostRect, { width: tooltipRect.width, height: tooltipRect.height }, {
2133
+ width: document.documentElement.clientWidth,
2134
+ height: document.documentElement.clientHeight,
2135
+ }, { placement: this.tooltipPosition(), offset: 8, flip: false, margin: 8 });
2136
+ const { top, left } = placed;
1858
2137
  /* Hide if the calculated bubble would render on top of a sticky/fixed
1859
2138
  overlay (typically the app header). Catches the case where the trigger
1860
2139
  is visible just below the header but a `position: top` tooltip would
@@ -1947,6 +2226,8 @@ class AvatarEditorComponent {
1947
2226
  [`ea-avatar-editor--${this.shape()}`]: true,
1948
2227
  'ea-avatar-editor--has-image': this.hasImage(),
1949
2228
  'ea-avatar-editor--drag-over': this.isDragOver(),
2229
+ 'ea-avatar-editor--compact': this.canvasSize() <= 150,
2230
+ 'ea-avatar-editor--ultra-compact': this.canvasSize() <= 100,
1950
2231
  }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
1951
2232
  injector = inject(Injector);
1952
2233
  boundWheel = (e) => this.onWheel(e);
@@ -1968,6 +2249,11 @@ class AvatarEditorComponent {
1968
2249
  this.originalCropState = null;
1969
2250
  this.loadFromUrl(src, untracked(() => this.cropState()) ?? null, true);
1970
2251
  });
2252
+ effect(() => {
2253
+ this.canvasSize();
2254
+ if (this.image)
2255
+ this.draw();
2256
+ });
1971
2257
  }
1972
2258
  ngOnDestroy() {
1973
2259
  const canvas = this.canvasEl()?.nativeElement;
@@ -2423,7 +2709,7 @@ class AvatarEditorComponent {
2423
2709
  ctx.clearRect(0, 0, canvas.width, canvas.height);
2424
2710
  }
2425
2711
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: AvatarEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2426
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: AvatarEditorComponent, isStandalone: true, selector: "ea-avatar-editor", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: false, transformFunction: null }, currentSrc: { classPropertyName: "currentSrc", publicName: "currentSrc", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: true, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: true, isRequired: false, transformFunction: null }, exportQuality: { classPropertyName: "exportQuality", publicName: "exportQuality", isSignal: true, isRequired: false, transformFunction: null }, exportType: { classPropertyName: "exportType", publicName: "exportType", isSignal: true, isRequired: false, transformFunction: null }, cropState: { classPropertyName: "cropState", publicName: "cropState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cropped: "cropped", fileSelected: "fileSelected", removed: "removed", errored: "errored", cropStateChanged: "cropStateChanged" }, viewQueries: [{ propertyName: "canvasEl", first: true, predicate: ["canvasEl"], descendants: true, isSignal: true }, { propertyName: "fileInputEl", first: true, predicate: ["fileInputEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ea-avatar-editor\"\n [ngClass]=\"hostClasses()\">\n <input\n #fileInputEl\n type=\"file\"\n class=\"ea-avatar-editor__file-input\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.upload\"\n [accept]=\"accept()\"\n (change)=\"onFileSelected($event)\" />\n\n @if (!hasImage() && !isLoading()) {\n <button\n type=\"button\"\n class=\"ea-avatar-editor__dropzone\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (click)=\"openFilePicker()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <ea-icon-upload class=\"ea-avatar-editor__upload-icon\" />\n <span class=\"ea-avatar-editor__dropzone-text\">\n {{ i18n.messages().avatarEditor.dropzone }}\n </span>\n </button>\n }\n\n @if (hasImage() || isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-wrapper\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (isLoading()) {\n <ea-skeleton\n [variant]=\"shape() === 'circle' ? 'circle' : 'rect'\"\n [width]=\"canvasSize() + 'px'\"\n [height]=\"canvasSize() + 'px'\" />\n }\n\n @if (hasImage()) {\n <canvas\n #canvasEl\n class=\"ea-avatar-editor__canvas\"\n role=\"img\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.canvas\"\n [style.display]=\"isLoading() ? 'none' : 'block'\"\n [width]=\"canvasSize()\"\n [height]=\"canvasSize()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (keydown)=\"onCanvasKeydown($event)\"></canvas>\n\n @if (!isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-overlay\"\n [class.ea-avatar-editor__canvas-overlay--on-light]=\"!isImageDark()\">\n <ea-icon-camera class=\"ea-avatar-editor__overlay-icon\" />\n <span>{{ i18n.messages().avatarEditor.change }}</span>\n </div>\n }\n }\n </div>\n }\n\n <div class=\"ea-avatar-editor__controls\">\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.revert\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.revert\"\n [disabled]=\"!canRevert() || isLoading()\"\n (click)=\"revertImage()\">\n <ea-icon-rotate-ccw />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomOut\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomOut\"\n [disabled]=\"!hasImage() || isLoading() || zoom() <= minZoom()\"\n (click)=\"setZoom(zoom() - 0.1)\">\n <ea-icon-minus />\n </button>\n\n <input\n type=\"range\"\n class=\"ea-avatar-editor__zoom-slider\"\n [min]=\"minZoom()\"\n [max]=\"maxZoom()\"\n step=\"0.01\"\n [value]=\"zoom()\"\n [disabled]=\"!hasImage() || isLoading()\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoom\"\n (input)=\"onZoomInput($event)\" />\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomIn\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomIn\"\n [disabled]=\"!hasImage() || isLoading() || zoom() >= maxZoom()\"\n (click)=\"setZoom(zoom() + 0.1)\">\n <ea-icon-plus />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn ea-avatar-editor__icon-btn--danger\"\n [eaTooltip]=\"i18n.messages().avatarEditor.remove\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.remove\"\n [disabled]=\"!hasImage() || isLoading()\"\n (click)=\"removeImage()\">\n <ea-icon-trash />\n </button>\n </div>\n</div>\n", styles: [".ea-avatar-editor{display:inline-flex;flex-direction:column;align-items:center;gap:var(--space-3);font-family:var(--font-family-sans)}.ea-avatar-editor__file-input{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;margin:-1px;border:0;white-space:nowrap;clip:rect(0,0,0,0);clip-path:inset(50%)}.ea-avatar-editor__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-2);padding:var(--space-4);font-family:inherit;font-size:var(--font-size-sm);line-height:var(--line-height-normal);border:2px dashed var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-tertiary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__dropzone:hover{border-color:var(--color-border-focus);background-color:var(--color-bg-muted);color:var(--color-text-secondary)}.ea-avatar-editor__dropzone:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor--drag-over .ea-avatar-editor__dropzone{border-color:var(--color-primary-500);background-color:var(--color-primary-50);color:var(--color-primary-600)}.ea-avatar-editor--circle .ea-avatar-editor__dropzone{border-radius:var(--radius-full)}.ea-avatar-editor__upload-icon{width:32px;height:32px;opacity:.6}.ea-avatar-editor__dropzone-text{text-align:center}.ea-avatar-editor__canvas-wrapper{position:relative;overflow:hidden;border-radius:var(--radius-lg)}.ea-avatar-editor--circle .ea-avatar-editor__canvas-wrapper{border-radius:var(--radius-full)}.ea-avatar-editor__canvas{display:block;cursor:grab}.ea-avatar-editor__canvas:active{cursor:grabbing}.ea-avatar-editor__canvas-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-neutral-0);opacity:0;pointer-events:none;transition:opacity var(--duration-fast) var(--easing-default),color var(--duration-fast) var(--easing-default)}.ea-avatar-editor__canvas-overlay--on-light{color:var(--color-neutral-950)}.ea-avatar-editor__overlay-icon{width:24px;height:24px}.ea-avatar-editor__canvas-wrapper:hover .ea-avatar-editor__canvas-overlay{opacity:1}.ea-avatar-editor__controls{display:flex;align-items:center;gap:var(--space-2)}.ea-avatar-editor__icon-btn{display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0}.ea-avatar-editor__icon-btn ea-icon-rotate-ccw,.ea-avatar-editor__icon-btn ea-icon-minus,.ea-avatar-editor__icon-btn ea-icon-plus,.ea-avatar-editor__icon-btn ea-icon-trash{width:1rem;height:1rem}.ea-avatar-editor__icon-btn{border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__icon-btn:hover:not(:disabled){border-color:var(--color-border-focus)}.ea-avatar-editor__icon-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__icon-btn:disabled{opacity:.4;cursor:not-allowed}.ea-avatar-editor__icon-btn--danger{color:var(--color-error-default)}.ea-avatar-editor__icon-btn--danger:hover:not(:disabled){border-color:var(--color-error-default)}.ea-avatar-editor__zoom-slider{width:7rem;height:4px;border-radius:var(--radius-full);background:var(--color-neutral-200);appearance:none;cursor:pointer}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);appearance:none;cursor:grab}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider::-moz-range-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);cursor:grab}.ea-avatar-editor__zoom-slider::-moz-range-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider:focus-visible{outline:none}.ea-avatar-editor__zoom-slider:focus-visible::-webkit-slider-thumb{box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__zoom-slider:disabled{opacity:.4;cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: CameraIconComponent, selector: "ea-icon-camera" }, { kind: "component", type: MinusIconComponent, selector: "ea-icon-minus" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PlusIconComponent, selector: "ea-icon-plus" }, { kind: "component", type: RotateCcwIconComponent, selector: "ea-icon-rotate-ccw" }, { kind: "component", type: SkeletonComponent, selector: "ea-skeleton", inputs: ["variant", "width", "height", "animated"] }, { kind: "directive", type: TooltipDirective, selector: "[eaTooltip]", inputs: ["eaTooltip", "tooltipPosition"] }, { kind: "component", type: TrashIconComponent, selector: "ea-icon-trash" }, { kind: "component", type: UploadIconComponent, selector: "ea-icon-upload" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2712
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: AvatarEditorComponent, isStandalone: true, selector: "ea-avatar-editor", inputs: { shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: false, transformFunction: null }, currentSrc: { classPropertyName: "currentSrc", publicName: "currentSrc", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: true, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: true, isRequired: false, transformFunction: null }, exportQuality: { classPropertyName: "exportQuality", publicName: "exportQuality", isSignal: true, isRequired: false, transformFunction: null }, exportType: { classPropertyName: "exportType", publicName: "exportType", isSignal: true, isRequired: false, transformFunction: null }, cropState: { classPropertyName: "cropState", publicName: "cropState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cropped: "cropped", fileSelected: "fileSelected", removed: "removed", errored: "errored", cropStateChanged: "cropStateChanged" }, viewQueries: [{ propertyName: "canvasEl", first: true, predicate: ["canvasEl"], descendants: true, isSignal: true }, { propertyName: "fileInputEl", first: true, predicate: ["fileInputEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ea-avatar-editor\"\n [ngClass]=\"hostClasses()\">\n <input\n #fileInputEl\n type=\"file\"\n class=\"ea-avatar-editor__file-input\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.upload\"\n [accept]=\"accept()\"\n (change)=\"onFileSelected($event)\" />\n\n @if (!hasImage() && !isLoading()) {\n <button\n type=\"button\"\n class=\"ea-avatar-editor__dropzone\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (click)=\"openFilePicker()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <ea-icon-upload class=\"ea-avatar-editor__upload-icon\" />\n <span class=\"ea-avatar-editor__dropzone-text\">\n {{ i18n.messages().avatarEditor.dropzone }}\n </span>\n </button>\n }\n\n @if (hasImage() || isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-wrapper\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (isLoading()) {\n <ea-skeleton\n [variant]=\"shape() === 'circle' ? 'circle' : 'rect'\"\n [width]=\"canvasSize() + 'px'\"\n [height]=\"canvasSize() + 'px'\" />\n }\n\n @if (hasImage()) {\n <canvas\n #canvasEl\n class=\"ea-avatar-editor__canvas\"\n role=\"img\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.canvas\"\n [style.display]=\"isLoading() ? 'none' : 'block'\"\n [width]=\"canvasSize()\"\n [height]=\"canvasSize()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (keydown)=\"onCanvasKeydown($event)\"></canvas>\n\n @if (!isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-overlay\"\n [class.ea-avatar-editor__canvas-overlay--on-light]=\"!isImageDark()\">\n <ea-icon-camera class=\"ea-avatar-editor__overlay-icon\" />\n <span>{{ i18n.messages().avatarEditor.change }}</span>\n </div>\n }\n }\n </div>\n }\n\n <div class=\"ea-avatar-editor__controls\">\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.revert\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.revert\"\n [disabled]=\"!canRevert() || isLoading()\"\n (click)=\"revertImage()\">\n <ea-icon-rotate-ccw />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomOut\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomOut\"\n [disabled]=\"!hasImage() || isLoading() || zoom() <= minZoom()\"\n (click)=\"setZoom(zoom() - 0.1)\">\n <ea-icon-minus />\n </button>\n\n <input\n type=\"range\"\n class=\"ea-avatar-editor__zoom-slider\"\n [min]=\"minZoom()\"\n [max]=\"maxZoom()\"\n step=\"0.01\"\n [value]=\"zoom()\"\n [disabled]=\"!hasImage() || isLoading()\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoom\"\n (input)=\"onZoomInput($event)\" />\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomIn\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomIn\"\n [disabled]=\"!hasImage() || isLoading() || zoom() >= maxZoom()\"\n (click)=\"setZoom(zoom() + 0.1)\">\n <ea-icon-plus />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn ea-avatar-editor__icon-btn--danger\"\n [eaTooltip]=\"i18n.messages().avatarEditor.remove\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.remove\"\n [disabled]=\"!hasImage() || isLoading()\"\n (click)=\"removeImage()\">\n <ea-icon-trash />\n </button>\n </div>\n</div>\n", styles: [".ea-avatar-editor{display:inline-flex;flex-direction:column;align-items:center;gap:var(--space-3);font-family:var(--font-family-sans)}.ea-avatar-editor__file-input{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;margin:-1px;border:0;white-space:nowrap;clip:rect(0,0,0,0);clip-path:inset(50%)}.ea-avatar-editor__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-2);padding:var(--space-4);font-family:inherit;font-size:var(--font-size-sm);line-height:var(--line-height-normal);border:2px dashed var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-tertiary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__dropzone:hover{border-color:var(--color-border-focus);background-color:var(--color-bg-muted);color:var(--color-text-secondary)}.ea-avatar-editor__dropzone:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor--drag-over .ea-avatar-editor__dropzone{border-color:var(--color-primary-500);background-color:var(--color-primary-50);color:var(--color-primary-600)}.ea-avatar-editor--circle .ea-avatar-editor__dropzone{border-radius:var(--radius-full)}.ea-avatar-editor__upload-icon{width:32px;height:32px;opacity:.6}.ea-avatar-editor__dropzone-text{text-align:center}.ea-avatar-editor--compact .ea-avatar-editor__dropzone{gap:var(--space-1-5);padding:var(--space-3);font-size:.75rem;line-height:1.35}.ea-avatar-editor--compact .ea-avatar-editor__upload-icon{width:24px;height:24px}.ea-avatar-editor--ultra-compact .ea-avatar-editor__dropzone{gap:var(--space-1);padding:var(--space-2);font-size:.625rem;line-height:1.2}.ea-avatar-editor--ultra-compact .ea-avatar-editor__upload-icon{width:16px;height:16px}.ea-avatar-editor__canvas-wrapper{position:relative;overflow:hidden;border-radius:var(--radius-lg)}.ea-avatar-editor--circle .ea-avatar-editor__canvas-wrapper{border-radius:var(--radius-full)}.ea-avatar-editor__canvas{display:block;cursor:grab}.ea-avatar-editor__canvas:active{cursor:grabbing}.ea-avatar-editor__canvas-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-neutral-0);opacity:0;pointer-events:none;transition:opacity var(--duration-fast) var(--easing-default),color var(--duration-fast) var(--easing-default)}.ea-avatar-editor__canvas-overlay--on-light{color:var(--color-neutral-950)}.ea-avatar-editor__overlay-icon{width:24px;height:24px}.ea-avatar-editor__canvas-wrapper:hover .ea-avatar-editor__canvas-overlay{opacity:1}.ea-avatar-editor__controls{display:flex;align-items:center;gap:var(--space-2)}.ea-avatar-editor__icon-btn{display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0}.ea-avatar-editor__icon-btn ea-icon-rotate-ccw,.ea-avatar-editor__icon-btn ea-icon-minus,.ea-avatar-editor__icon-btn ea-icon-plus,.ea-avatar-editor__icon-btn ea-icon-trash{width:1rem;height:1rem}.ea-avatar-editor__icon-btn{border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__icon-btn:hover:not(:disabled){border-color:var(--color-border-focus)}.ea-avatar-editor__icon-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__icon-btn:disabled{opacity:.4;cursor:not-allowed}.ea-avatar-editor__icon-btn--danger{color:var(--color-error-default)}.ea-avatar-editor__icon-btn--danger:hover:not(:disabled){border-color:var(--color-error-default)}.ea-avatar-editor__zoom-slider{width:7rem;height:4px;border-radius:var(--radius-full);background:var(--color-neutral-200);appearance:none;cursor:pointer}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);appearance:none;cursor:grab}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider::-moz-range-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);cursor:grab}.ea-avatar-editor__zoom-slider::-moz-range-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider:focus-visible{outline:none}.ea-avatar-editor__zoom-slider:focus-visible::-webkit-slider-thumb{box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__zoom-slider:disabled{opacity:.4;cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: CameraIconComponent, selector: "ea-icon-camera" }, { kind: "component", type: MinusIconComponent, selector: "ea-icon-minus" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PlusIconComponent, selector: "ea-icon-plus" }, { kind: "component", type: RotateCcwIconComponent, selector: "ea-icon-rotate-ccw" }, { kind: "component", type: SkeletonComponent, selector: "ea-skeleton", inputs: ["variant", "width", "height", "animated"] }, { kind: "directive", type: TooltipDirective, selector: "[eaTooltip]", inputs: ["eaTooltip", "tooltipPosition"] }, { kind: "component", type: TrashIconComponent, selector: "ea-icon-trash" }, { kind: "component", type: UploadIconComponent, selector: "ea-icon-upload" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2427
2713
  }
2428
2714
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: AvatarEditorComponent, decorators: [{
2429
2715
  type: Component,
@@ -2437,7 +2723,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
2437
2723
  TooltipDirective,
2438
2724
  TrashIconComponent,
2439
2725
  UploadIconComponent,
2440
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-avatar-editor\"\n [ngClass]=\"hostClasses()\">\n <input\n #fileInputEl\n type=\"file\"\n class=\"ea-avatar-editor__file-input\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.upload\"\n [accept]=\"accept()\"\n (change)=\"onFileSelected($event)\" />\n\n @if (!hasImage() && !isLoading()) {\n <button\n type=\"button\"\n class=\"ea-avatar-editor__dropzone\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (click)=\"openFilePicker()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <ea-icon-upload class=\"ea-avatar-editor__upload-icon\" />\n <span class=\"ea-avatar-editor__dropzone-text\">\n {{ i18n.messages().avatarEditor.dropzone }}\n </span>\n </button>\n }\n\n @if (hasImage() || isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-wrapper\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (isLoading()) {\n <ea-skeleton\n [variant]=\"shape() === 'circle' ? 'circle' : 'rect'\"\n [width]=\"canvasSize() + 'px'\"\n [height]=\"canvasSize() + 'px'\" />\n }\n\n @if (hasImage()) {\n <canvas\n #canvasEl\n class=\"ea-avatar-editor__canvas\"\n role=\"img\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.canvas\"\n [style.display]=\"isLoading() ? 'none' : 'block'\"\n [width]=\"canvasSize()\"\n [height]=\"canvasSize()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (keydown)=\"onCanvasKeydown($event)\"></canvas>\n\n @if (!isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-overlay\"\n [class.ea-avatar-editor__canvas-overlay--on-light]=\"!isImageDark()\">\n <ea-icon-camera class=\"ea-avatar-editor__overlay-icon\" />\n <span>{{ i18n.messages().avatarEditor.change }}</span>\n </div>\n }\n }\n </div>\n }\n\n <div class=\"ea-avatar-editor__controls\">\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.revert\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.revert\"\n [disabled]=\"!canRevert() || isLoading()\"\n (click)=\"revertImage()\">\n <ea-icon-rotate-ccw />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomOut\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomOut\"\n [disabled]=\"!hasImage() || isLoading() || zoom() <= minZoom()\"\n (click)=\"setZoom(zoom() - 0.1)\">\n <ea-icon-minus />\n </button>\n\n <input\n type=\"range\"\n class=\"ea-avatar-editor__zoom-slider\"\n [min]=\"minZoom()\"\n [max]=\"maxZoom()\"\n step=\"0.01\"\n [value]=\"zoom()\"\n [disabled]=\"!hasImage() || isLoading()\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoom\"\n (input)=\"onZoomInput($event)\" />\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomIn\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomIn\"\n [disabled]=\"!hasImage() || isLoading() || zoom() >= maxZoom()\"\n (click)=\"setZoom(zoom() + 0.1)\">\n <ea-icon-plus />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn ea-avatar-editor__icon-btn--danger\"\n [eaTooltip]=\"i18n.messages().avatarEditor.remove\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.remove\"\n [disabled]=\"!hasImage() || isLoading()\"\n (click)=\"removeImage()\">\n <ea-icon-trash />\n </button>\n </div>\n</div>\n", styles: [".ea-avatar-editor{display:inline-flex;flex-direction:column;align-items:center;gap:var(--space-3);font-family:var(--font-family-sans)}.ea-avatar-editor__file-input{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;margin:-1px;border:0;white-space:nowrap;clip:rect(0,0,0,0);clip-path:inset(50%)}.ea-avatar-editor__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-2);padding:var(--space-4);font-family:inherit;font-size:var(--font-size-sm);line-height:var(--line-height-normal);border:2px dashed var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-tertiary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__dropzone:hover{border-color:var(--color-border-focus);background-color:var(--color-bg-muted);color:var(--color-text-secondary)}.ea-avatar-editor__dropzone:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor--drag-over .ea-avatar-editor__dropzone{border-color:var(--color-primary-500);background-color:var(--color-primary-50);color:var(--color-primary-600)}.ea-avatar-editor--circle .ea-avatar-editor__dropzone{border-radius:var(--radius-full)}.ea-avatar-editor__upload-icon{width:32px;height:32px;opacity:.6}.ea-avatar-editor__dropzone-text{text-align:center}.ea-avatar-editor__canvas-wrapper{position:relative;overflow:hidden;border-radius:var(--radius-lg)}.ea-avatar-editor--circle .ea-avatar-editor__canvas-wrapper{border-radius:var(--radius-full)}.ea-avatar-editor__canvas{display:block;cursor:grab}.ea-avatar-editor__canvas:active{cursor:grabbing}.ea-avatar-editor__canvas-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-neutral-0);opacity:0;pointer-events:none;transition:opacity var(--duration-fast) var(--easing-default),color var(--duration-fast) var(--easing-default)}.ea-avatar-editor__canvas-overlay--on-light{color:var(--color-neutral-950)}.ea-avatar-editor__overlay-icon{width:24px;height:24px}.ea-avatar-editor__canvas-wrapper:hover .ea-avatar-editor__canvas-overlay{opacity:1}.ea-avatar-editor__controls{display:flex;align-items:center;gap:var(--space-2)}.ea-avatar-editor__icon-btn{display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0}.ea-avatar-editor__icon-btn ea-icon-rotate-ccw,.ea-avatar-editor__icon-btn ea-icon-minus,.ea-avatar-editor__icon-btn ea-icon-plus,.ea-avatar-editor__icon-btn ea-icon-trash{width:1rem;height:1rem}.ea-avatar-editor__icon-btn{border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__icon-btn:hover:not(:disabled){border-color:var(--color-border-focus)}.ea-avatar-editor__icon-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__icon-btn:disabled{opacity:.4;cursor:not-allowed}.ea-avatar-editor__icon-btn--danger{color:var(--color-error-default)}.ea-avatar-editor__icon-btn--danger:hover:not(:disabled){border-color:var(--color-error-default)}.ea-avatar-editor__zoom-slider{width:7rem;height:4px;border-radius:var(--radius-full);background:var(--color-neutral-200);appearance:none;cursor:pointer}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);appearance:none;cursor:grab}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider::-moz-range-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);cursor:grab}.ea-avatar-editor__zoom-slider::-moz-range-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider:focus-visible{outline:none}.ea-avatar-editor__zoom-slider:focus-visible::-webkit-slider-thumb{box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__zoom-slider:disabled{opacity:.4;cursor:not-allowed}\n"] }]
2726
+ ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-avatar-editor\"\n [ngClass]=\"hostClasses()\">\n <input\n #fileInputEl\n type=\"file\"\n class=\"ea-avatar-editor__file-input\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.upload\"\n [accept]=\"accept()\"\n (change)=\"onFileSelected($event)\" />\n\n @if (!hasImage() && !isLoading()) {\n <button\n type=\"button\"\n class=\"ea-avatar-editor__dropzone\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (click)=\"openFilePicker()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n <ea-icon-upload class=\"ea-avatar-editor__upload-icon\" />\n <span class=\"ea-avatar-editor__dropzone-text\">\n {{ i18n.messages().avatarEditor.dropzone }}\n </span>\n </button>\n }\n\n @if (hasImage() || isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-wrapper\"\n [style.width.px]=\"canvasSize()\"\n [style.height.px]=\"canvasSize()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\">\n @if (isLoading()) {\n <ea-skeleton\n [variant]=\"shape() === 'circle' ? 'circle' : 'rect'\"\n [width]=\"canvasSize() + 'px'\"\n [height]=\"canvasSize() + 'px'\" />\n }\n\n @if (hasImage()) {\n <canvas\n #canvasEl\n class=\"ea-avatar-editor__canvas\"\n role=\"img\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.canvas\"\n [style.display]=\"isLoading() ? 'none' : 'block'\"\n [width]=\"canvasSize()\"\n [height]=\"canvasSize()\"\n (mousedown)=\"onMouseDown($event)\"\n (touchstart)=\"onTouchStart($event)\"\n (keydown)=\"onCanvasKeydown($event)\"></canvas>\n\n @if (!isLoading()) {\n <div\n class=\"ea-avatar-editor__canvas-overlay\"\n [class.ea-avatar-editor__canvas-overlay--on-light]=\"!isImageDark()\">\n <ea-icon-camera class=\"ea-avatar-editor__overlay-icon\" />\n <span>{{ i18n.messages().avatarEditor.change }}</span>\n </div>\n }\n }\n </div>\n }\n\n <div class=\"ea-avatar-editor__controls\">\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.revert\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.revert\"\n [disabled]=\"!canRevert() || isLoading()\"\n (click)=\"revertImage()\">\n <ea-icon-rotate-ccw />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomOut\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomOut\"\n [disabled]=\"!hasImage() || isLoading() || zoom() <= minZoom()\"\n (click)=\"setZoom(zoom() - 0.1)\">\n <ea-icon-minus />\n </button>\n\n <input\n type=\"range\"\n class=\"ea-avatar-editor__zoom-slider\"\n [min]=\"minZoom()\"\n [max]=\"maxZoom()\"\n step=\"0.01\"\n [value]=\"zoom()\"\n [disabled]=\"!hasImage() || isLoading()\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoom\"\n (input)=\"onZoomInput($event)\" />\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn\"\n [eaTooltip]=\"i18n.messages().avatarEditor.zoomIn\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.zoomIn\"\n [disabled]=\"!hasImage() || isLoading() || zoom() >= maxZoom()\"\n (click)=\"setZoom(zoom() + 0.1)\">\n <ea-icon-plus />\n </button>\n\n <button\n type=\"button\"\n class=\"ea-avatar-editor__icon-btn ea-avatar-editor__icon-btn--danger\"\n [eaTooltip]=\"i18n.messages().avatarEditor.remove\"\n [attr.aria-label]=\"i18n.messages().avatarEditor.remove\"\n [disabled]=\"!hasImage() || isLoading()\"\n (click)=\"removeImage()\">\n <ea-icon-trash />\n </button>\n </div>\n</div>\n", styles: [".ea-avatar-editor{display:inline-flex;flex-direction:column;align-items:center;gap:var(--space-3);font-family:var(--font-family-sans)}.ea-avatar-editor__file-input{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;margin:-1px;border:0;white-space:nowrap;clip:rect(0,0,0,0);clip-path:inset(50%)}.ea-avatar-editor__dropzone{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-2);padding:var(--space-4);font-family:inherit;font-size:var(--font-size-sm);line-height:var(--line-height-normal);border:2px dashed var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-tertiary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__dropzone:hover{border-color:var(--color-border-focus);background-color:var(--color-bg-muted);color:var(--color-text-secondary)}.ea-avatar-editor__dropzone:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor--drag-over .ea-avatar-editor__dropzone{border-color:var(--color-primary-500);background-color:var(--color-primary-50);color:var(--color-primary-600)}.ea-avatar-editor--circle .ea-avatar-editor__dropzone{border-radius:var(--radius-full)}.ea-avatar-editor__upload-icon{width:32px;height:32px;opacity:.6}.ea-avatar-editor__dropzone-text{text-align:center}.ea-avatar-editor--compact .ea-avatar-editor__dropzone{gap:var(--space-1-5);padding:var(--space-3);font-size:.75rem;line-height:1.35}.ea-avatar-editor--compact .ea-avatar-editor__upload-icon{width:24px;height:24px}.ea-avatar-editor--ultra-compact .ea-avatar-editor__dropzone{gap:var(--space-1);padding:var(--space-2);font-size:.625rem;line-height:1.2}.ea-avatar-editor--ultra-compact .ea-avatar-editor__upload-icon{width:16px;height:16px}.ea-avatar-editor__canvas-wrapper{position:relative;overflow:hidden;border-radius:var(--radius-lg)}.ea-avatar-editor--circle .ea-avatar-editor__canvas-wrapper{border-radius:var(--radius-full)}.ea-avatar-editor__canvas{display:block;cursor:grab}.ea-avatar-editor__canvas:active{cursor:grabbing}.ea-avatar-editor__canvas-overlay{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-1);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-neutral-0);opacity:0;pointer-events:none;transition:opacity var(--duration-fast) var(--easing-default),color var(--duration-fast) var(--easing-default)}.ea-avatar-editor__canvas-overlay--on-light{color:var(--color-neutral-950)}.ea-avatar-editor__overlay-icon{width:24px;height:24px}.ea-avatar-editor__canvas-wrapper:hover .ea-avatar-editor__canvas-overlay{opacity:1}.ea-avatar-editor__controls{display:flex;align-items:center;gap:var(--space-2)}.ea-avatar-editor__icon-btn{display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;padding:0}.ea-avatar-editor__icon-btn ea-icon-rotate-ccw,.ea-avatar-editor__icon-btn ea-icon-minus,.ea-avatar-editor__icon-btn ea-icon-plus,.ea-avatar-editor__icon-btn ea-icon-trash{width:1rem;height:1rem}.ea-avatar-editor__icon-btn{border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-avatar-editor__icon-btn:hover:not(:disabled){border-color:var(--color-border-focus)}.ea-avatar-editor__icon-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__icon-btn:disabled{opacity:.4;cursor:not-allowed}.ea-avatar-editor__icon-btn--danger{color:var(--color-error-default)}.ea-avatar-editor__icon-btn--danger:hover:not(:disabled){border-color:var(--color-error-default)}.ea-avatar-editor__zoom-slider{width:7rem;height:4px;border-radius:var(--radius-full);background:var(--color-neutral-200);appearance:none;cursor:pointer}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);appearance:none;cursor:grab}.ea-avatar-editor__zoom-slider::-webkit-slider-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider::-moz-range-thumb{width:1rem;height:1rem;border:2px solid var(--color-primary-500);border-radius:var(--radius-full);background:var(--color-bg-base);cursor:grab}.ea-avatar-editor__zoom-slider::-moz-range-thumb:active{cursor:grabbing}.ea-avatar-editor__zoom-slider:focus-visible{outline:none}.ea-avatar-editor__zoom-slider:focus-visible::-webkit-slider-thumb{box-shadow:var(--shadow-focus-ring)}.ea-avatar-editor__zoom-slider:disabled{opacity:.4;cursor:not-allowed}\n"] }]
2441
2727
  }], ctorParameters: () => [], propDecorators: { canvasEl: [{ type: i0.ViewChild, args: ['canvasEl', { isSignal: true }] }], fileInputEl: [{ type: i0.ViewChild, args: ['fileInputEl', { isSignal: true }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: false }] }], currentSrc: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentSrc", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], minZoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "minZoom", required: false }] }], maxZoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxZoom", required: false }] }], exportQuality: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportQuality", required: false }] }], exportType: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportType", required: false }] }], cropState: [{ type: i0.Input, args: [{ isSignal: true, alias: "cropState", required: false }] }], cropped: [{ type: i0.Output, args: ["cropped"] }], fileSelected: [{ type: i0.Output, args: ["fileSelected"] }], removed: [{ type: i0.Output, args: ["removed"] }], errored: [{ type: i0.Output, args: ["errored"] }], cropStateChanged: [{ type: i0.Output, args: ["cropStateChanged"] }] } });
2442
2728
 
2443
2729
  class UserIconComponent extends IconComponentBase {
@@ -2534,23 +2820,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
2534
2820
  }], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], alt: [{ type: i0.Input, args: [{ isSignal: true, alias: "alt", required: false }] }], initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }] } });
2535
2821
 
2536
2822
  /**
2537
- * Compact pill-shaped indicator used to communicate status, counts, or labels
2538
- * inline with surrounding content.
2823
+ * Compact indicator used to communicate status, counts, or labels inline with
2824
+ * surrounding content.
2539
2825
  */
2540
2826
  class BadgeComponent {
2541
2827
  variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
2542
2828
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
2829
+ shape = input('pill', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
2543
2830
  hostClasses = computed(() => ({
2544
2831
  [`ea-badge--${this.variant()}`]: true,
2545
2832
  [`ea-badge--${this.size()}`]: true,
2833
+ [`ea-badge--${this.shape()}`]: true,
2546
2834
  }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2547
2835
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: BadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2548
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: BadgeComponent, isStandalone: true, selector: "ea-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<span\n class=\"ea-badge\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n</span>\n", styles: [".ea-badge{display:inline-flex;align-items:center;gap:var(--space-1);font-family:var(--font-family-sans);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;border-radius:var(--radius-full)}.ea-badge--sm{padding:var(--space-0-5) var(--space-2);font-size:var(--font-size-xs)}.ea-badge--md{padding:var(--space-1) var(--space-2-5);font-size:var(--font-size-xs)}.ea-badge--lg{padding:var(--space-1) var(--space-3);font-size:var(--font-size-sm)}.ea-badge--default{background-color:var(--color-bg-muted);color:var(--color-text-secondary)}.ea-badge--success{background-color:var(--color-success-subtle);color:var(--color-success-700)}.ea-badge--warning{background-color:var(--color-warning-subtle);color:var(--color-warning-700)}.ea-badge--error{background-color:var(--color-error-subtle);color:var(--color-error-700)}.ea-badge--info{background-color:var(--color-info-subtle);color:var(--color-info-700)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2836
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: BadgeComponent, isStandalone: true, selector: "ea-badge", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<span\n class=\"ea-badge\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n</span>\n", styles: [".ea-badge{display:inline-flex;align-items:center;gap:var(--space-1);font-family:var(--font-family-sans);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;border-style:solid;border-width:var(--ea-badge-border-width, 0);border-color:var(--ea-badge-border-color, transparent);border-radius:var(--radius-full)}.ea-badge--sm{padding:var(--space-0-5) var(--space-2);font-size:var(--ea-badge-font-size, var(--font-size-xs))}.ea-badge--md{padding:var(--space-1) var(--space-2-5);font-size:var(--ea-badge-font-size, var(--font-size-xs))}.ea-badge--lg{padding:var(--space-1) var(--space-3);font-size:var(--ea-badge-font-size, var(--font-size-sm))}.ea-badge--default{background-color:var(--ea-badge-background-color, var(--color-bg-muted));color:var(--ea-badge-color, var(--color-text-secondary))}.ea-badge--success{background-color:var(--ea-badge-background-color, var(--color-success-subtle));color:var(--ea-badge-color, var(--color-success-700))}.ea-badge--warning{background-color:var(--ea-badge-background-color, var(--color-warning-subtle));color:var(--ea-badge-color, var(--color-warning-700))}.ea-badge--error{background-color:var(--ea-badge-background-color, var(--color-error-subtle));color:var(--ea-badge-color, var(--color-error-700))}.ea-badge--info{background-color:var(--ea-badge-background-color, var(--color-info-subtle));color:var(--ea-badge-color, var(--color-info-700))}.ea-badge--pin{justify-content:center;box-sizing:border-box;padding:0 var(--space-1);font-variant-numeric:tabular-nums}.ea-badge--pin.ea-badge--sm{min-width:var(--ea-badge-size, 16px);height:var(--ea-badge-size, 16px);font-size:var(--ea-badge-font-size, 9px)}.ea-badge--pin.ea-badge--md{min-width:var(--ea-badge-size, 18px);height:var(--ea-badge-size, 18px);font-size:var(--ea-badge-font-size, 10px)}.ea-badge--pin.ea-badge--lg{min-width:var(--ea-badge-size, 22px);height:var(--ea-badge-size, 22px);font-size:var(--ea-badge-font-size, 12px)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2549
2837
  }
2550
2838
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: BadgeComponent, decorators: [{
2551
2839
  type: Component,
2552
- args: [{ selector: 'ea-badge', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<span\n class=\"ea-badge\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n</span>\n", styles: [".ea-badge{display:inline-flex;align-items:center;gap:var(--space-1);font-family:var(--font-family-sans);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;border-radius:var(--radius-full)}.ea-badge--sm{padding:var(--space-0-5) var(--space-2);font-size:var(--font-size-xs)}.ea-badge--md{padding:var(--space-1) var(--space-2-5);font-size:var(--font-size-xs)}.ea-badge--lg{padding:var(--space-1) var(--space-3);font-size:var(--font-size-sm)}.ea-badge--default{background-color:var(--color-bg-muted);color:var(--color-text-secondary)}.ea-badge--success{background-color:var(--color-success-subtle);color:var(--color-success-700)}.ea-badge--warning{background-color:var(--color-warning-subtle);color:var(--color-warning-700)}.ea-badge--error{background-color:var(--color-error-subtle);color:var(--color-error-700)}.ea-badge--info{background-color:var(--color-info-subtle);color:var(--color-info-700)}\n"] }]
2553
- }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }] } });
2840
+ args: [{ selector: 'ea-badge', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<span\n class=\"ea-badge\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n</span>\n", styles: [".ea-badge{display:inline-flex;align-items:center;gap:var(--space-1);font-family:var(--font-family-sans);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;border-style:solid;border-width:var(--ea-badge-border-width, 0);border-color:var(--ea-badge-border-color, transparent);border-radius:var(--radius-full)}.ea-badge--sm{padding:var(--space-0-5) var(--space-2);font-size:var(--ea-badge-font-size, var(--font-size-xs))}.ea-badge--md{padding:var(--space-1) var(--space-2-5);font-size:var(--ea-badge-font-size, var(--font-size-xs))}.ea-badge--lg{padding:var(--space-1) var(--space-3);font-size:var(--ea-badge-font-size, var(--font-size-sm))}.ea-badge--default{background-color:var(--ea-badge-background-color, var(--color-bg-muted));color:var(--ea-badge-color, var(--color-text-secondary))}.ea-badge--success{background-color:var(--ea-badge-background-color, var(--color-success-subtle));color:var(--ea-badge-color, var(--color-success-700))}.ea-badge--warning{background-color:var(--ea-badge-background-color, var(--color-warning-subtle));color:var(--ea-badge-color, var(--color-warning-700))}.ea-badge--error{background-color:var(--ea-badge-background-color, var(--color-error-subtle));color:var(--ea-badge-color, var(--color-error-700))}.ea-badge--info{background-color:var(--ea-badge-background-color, var(--color-info-subtle));color:var(--ea-badge-color, var(--color-info-700))}.ea-badge--pin{justify-content:center;box-sizing:border-box;padding:0 var(--space-1);font-variant-numeric:tabular-nums}.ea-badge--pin.ea-badge--sm{min-width:var(--ea-badge-size, 16px);height:var(--ea-badge-size, 16px);font-size:var(--ea-badge-font-size, 9px)}.ea-badge--pin.ea-badge--md{min-width:var(--ea-badge-size, 18px);height:var(--ea-badge-size, 18px);font-size:var(--ea-badge-font-size, 10px)}.ea-badge--pin.ea-badge--lg{min-width:var(--ea-badge-size, 22px);height:var(--ea-badge-size, 22px);font-size:var(--ea-badge-font-size, 12px)}\n"] }]
2841
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }] } });
2554
2842
 
2555
2843
  class ChevronRightIconComponent extends IconComponentBase {
2556
2844
  static slug = 'chevron-right';
@@ -2672,13 +2960,13 @@ class ButtonComponent {
2672
2960
  this.clicked.emit(event);
2673
2961
  }
2674
2962
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2675
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: ButtonComponent, isStandalone: true, selector: "ea-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaCurrent: { classPropertyName: "ariaCurrent", publicName: "aria-current", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, host: { properties: { "class.ea-button--full-width": "fullWidth()" } }, ngImport: i0, template: "<button\n class=\"ea-button\"\n [ngClass]=\"hostClasses()\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-current]=\"ariaCurrent() || null\"\n [attr.aria-busy]=\"loading() || null\"\n (click)=\"handleClick($event)\">\n @if (loading()) {\n <span\n class=\"ea-button__spinner\"\n aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-dasharray=\"31.4\"\n stroke-dashoffset=\"10\" />\n </svg>\n </span>\n }\n\n <span\n class=\"ea-button__content\"\n [class.ea-button__content--hidden]=\"loading()\">\n <ng-content select=\"[slot=prefix]\" />\n <span class=\"ea-button__label\">\n <ng-content />\n </span>\n <ng-content select=\"[slot=suffix]\" />\n </span>\n</button>\n", styles: [".ea-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--inline-xs);position:relative;white-space:nowrap;-webkit-user-select:none;user-select:none;font-family:var(--font-family-sans);font-weight:var(--ea-button-font-weight, var(--font-weight-medium));letter-spacing:var(--letter-spacing-wide);text-decoration:none;line-height:var(--line-height-none);border-width:var(--border-width-thin);border-style:solid;border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);cursor:pointer}.ea-button:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-button--sm{padding:var(--space-1-5) var(--space-3);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2rem}.ea-button--md{padding:var(--space-2) var(--space-4);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2.5rem}.ea-button--lg{padding:var(--space-2-5) var(--space-6);font-size:var(--ea-button-font-size, var(--font-size-md));min-height:3rem}.ea-button--primary{background-color:var(--color-brand-default);border-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-button--primary:hover:not(.ea-button--disabled){background-color:var(--color-brand-hover);border-color:var(--color-brand-hover)}.ea-button--primary:active:not(.ea-button--disabled){background-color:var(--color-brand-active);border-color:var(--color-brand-active)}.ea-button--secondary{background-color:transparent;border-color:var(--color-border-strong);color:var(--color-text-primary)}.ea-button--secondary:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted);border-color:var(--color-neutral-500)}.ea-button--secondary:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--ghost{background-color:transparent;border-color:transparent;color:var(--color-text-primary)}.ea-button--ghost:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted)}.ea-button--ghost:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--danger{background-color:var(--color-error-default);border-color:var(--color-error-default);color:var(--color-text-inverse)}.ea-button--danger:hover:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700)}.ea-button--danger:active:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700);filter:brightness(.9)}.ea-button--full-width{width:100%}.ea-button--disabled,.ea-button:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ea-button--loading{cursor:wait;pointer-events:none}.ea-button__content{display:inline-flex;align-items:center;gap:var(--inline-xs)}.ea-button__content--hidden{visibility:hidden}.ea-button__label{display:inline-flex;align-items:center}.ea-button__spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.ea-button__spinner svg{width:1.1em;height:1.1em;animation:ea-spin .75s linear infinite}:host(.ea-button--full-width){display:block;width:100%}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2963
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: ButtonComponent, isStandalone: true, selector: "ea-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, ariaCurrent: { classPropertyName: "ariaCurrent", publicName: "aria-current", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, host: { properties: { "class.ea-button--full-width": "fullWidth()" } }, ngImport: i0, template: "<button\n class=\"ea-button\"\n [ngClass]=\"hostClasses()\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-current]=\"ariaCurrent() || null\"\n [attr.aria-busy]=\"loading() || null\"\n (click)=\"handleClick($event)\">\n @if (loading()) {\n <span\n class=\"ea-button__spinner\"\n aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-dasharray=\"31.4\"\n stroke-dashoffset=\"10\" />\n </svg>\n </span>\n }\n\n <span\n class=\"ea-button__content\"\n [class.ea-button__content--hidden]=\"loading()\">\n <ng-content select=\"[slot=prefix]\" />\n <span class=\"ea-button__label\">\n <ng-content />\n </span>\n <ng-content select=\"[slot=suffix]\" />\n </span>\n</button>\n", styles: [":host{display:inline-flex}.ea-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--inline-xs);position:relative;white-space:nowrap;-webkit-user-select:none;user-select:none;font-family:var(--font-family-sans);font-weight:var(--ea-button-font-weight, var(--font-weight-medium));letter-spacing:var(--letter-spacing-wide);text-decoration:none;line-height:var(--line-height-none);border-width:var(--border-width-thin);border-style:solid;border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);cursor:pointer}.ea-button:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-button--sm{padding:var(--space-1-5) var(--space-3);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2rem}.ea-button--md{padding:var(--space-2) var(--space-4);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2.5rem}.ea-button--lg{padding:var(--space-2-5) var(--space-6);font-size:var(--ea-button-font-size, var(--font-size-md));min-height:3rem}.ea-button--primary{background-color:var(--color-brand-default);border-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-button--primary:hover:not(.ea-button--disabled){background-color:var(--color-brand-hover);border-color:var(--color-brand-hover)}.ea-button--primary:active:not(.ea-button--disabled){background-color:var(--color-brand-active);border-color:var(--color-brand-active)}.ea-button--secondary{background-color:transparent;border-color:var(--color-border-strong);color:var(--color-text-primary)}.ea-button--secondary:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted);border-color:var(--color-neutral-500)}.ea-button--secondary:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--ghost{background-color:transparent;border-color:transparent;color:var(--color-text-primary)}.ea-button--ghost:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted)}.ea-button--ghost:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--danger{background-color:var(--color-error-default);border-color:var(--color-error-default);color:var(--color-text-inverse)}.ea-button--danger:hover:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700)}.ea-button--danger:active:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700);filter:brightness(.9)}.ea-button--full-width{width:100%}.ea-button--disabled,.ea-button:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ea-button--loading{cursor:wait;pointer-events:none}.ea-button__content{display:inline-flex;align-items:center;gap:var(--inline-xs)}.ea-button__content--hidden{visibility:hidden}.ea-button__label{display:inline-flex;align-items:center}.ea-button__spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.ea-button__spinner svg{width:1.1em;height:1.1em;animation:ea-spin .75s linear infinite}:host(.ea-button--full-width){display:block;width:100%}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2676
2964
  }
2677
2965
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ButtonComponent, decorators: [{
2678
2966
  type: Component,
2679
2967
  args: [{ selector: 'ea-button', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, host: {
2680
2968
  '[class.ea-button--full-width]': 'fullWidth()',
2681
- }, template: "<button\n class=\"ea-button\"\n [ngClass]=\"hostClasses()\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-current]=\"ariaCurrent() || null\"\n [attr.aria-busy]=\"loading() || null\"\n (click)=\"handleClick($event)\">\n @if (loading()) {\n <span\n class=\"ea-button__spinner\"\n aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-dasharray=\"31.4\"\n stroke-dashoffset=\"10\" />\n </svg>\n </span>\n }\n\n <span\n class=\"ea-button__content\"\n [class.ea-button__content--hidden]=\"loading()\">\n <ng-content select=\"[slot=prefix]\" />\n <span class=\"ea-button__label\">\n <ng-content />\n </span>\n <ng-content select=\"[slot=suffix]\" />\n </span>\n</button>\n", styles: [".ea-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--inline-xs);position:relative;white-space:nowrap;-webkit-user-select:none;user-select:none;font-family:var(--font-family-sans);font-weight:var(--ea-button-font-weight, var(--font-weight-medium));letter-spacing:var(--letter-spacing-wide);text-decoration:none;line-height:var(--line-height-none);border-width:var(--border-width-thin);border-style:solid;border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);cursor:pointer}.ea-button:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-button--sm{padding:var(--space-1-5) var(--space-3);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2rem}.ea-button--md{padding:var(--space-2) var(--space-4);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2.5rem}.ea-button--lg{padding:var(--space-2-5) var(--space-6);font-size:var(--ea-button-font-size, var(--font-size-md));min-height:3rem}.ea-button--primary{background-color:var(--color-brand-default);border-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-button--primary:hover:not(.ea-button--disabled){background-color:var(--color-brand-hover);border-color:var(--color-brand-hover)}.ea-button--primary:active:not(.ea-button--disabled){background-color:var(--color-brand-active);border-color:var(--color-brand-active)}.ea-button--secondary{background-color:transparent;border-color:var(--color-border-strong);color:var(--color-text-primary)}.ea-button--secondary:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted);border-color:var(--color-neutral-500)}.ea-button--secondary:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--ghost{background-color:transparent;border-color:transparent;color:var(--color-text-primary)}.ea-button--ghost:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted)}.ea-button--ghost:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--danger{background-color:var(--color-error-default);border-color:var(--color-error-default);color:var(--color-text-inverse)}.ea-button--danger:hover:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700)}.ea-button--danger:active:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700);filter:brightness(.9)}.ea-button--full-width{width:100%}.ea-button--disabled,.ea-button:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ea-button--loading{cursor:wait;pointer-events:none}.ea-button__content{display:inline-flex;align-items:center;gap:var(--inline-xs)}.ea-button__content--hidden{visibility:hidden}.ea-button__label{display:inline-flex;align-items:center}.ea-button__spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.ea-button__spinner svg{width:1.1em;height:1.1em;animation:ea-spin .75s linear infinite}:host(.ea-button--full-width){display:block;width:100%}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
2969
+ }, template: "<button\n class=\"ea-button\"\n [ngClass]=\"hostClasses()\"\n [type]=\"type()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-current]=\"ariaCurrent() || null\"\n [attr.aria-busy]=\"loading() || null\"\n (click)=\"handleClick($event)\">\n @if (loading()) {\n <span\n class=\"ea-button__spinner\"\n aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-dasharray=\"31.4\"\n stroke-dashoffset=\"10\" />\n </svg>\n </span>\n }\n\n <span\n class=\"ea-button__content\"\n [class.ea-button__content--hidden]=\"loading()\">\n <ng-content select=\"[slot=prefix]\" />\n <span class=\"ea-button__label\">\n <ng-content />\n </span>\n <ng-content select=\"[slot=suffix]\" />\n </span>\n</button>\n", styles: [":host{display:inline-flex}.ea-button{display:inline-flex;align-items:center;justify-content:center;gap:var(--inline-xs);position:relative;white-space:nowrap;-webkit-user-select:none;user-select:none;font-family:var(--font-family-sans);font-weight:var(--ea-button-font-weight, var(--font-weight-medium));letter-spacing:var(--letter-spacing-wide);text-decoration:none;line-height:var(--line-height-none);border-width:var(--border-width-thin);border-style:solid;border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);cursor:pointer}.ea-button:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-button--sm{padding:var(--space-1-5) var(--space-3);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2rem}.ea-button--md{padding:var(--space-2) var(--space-4);font-size:var(--ea-button-font-size, var(--font-size-sm));min-height:2.5rem}.ea-button--lg{padding:var(--space-2-5) var(--space-6);font-size:var(--ea-button-font-size, var(--font-size-md));min-height:3rem}.ea-button--primary{background-color:var(--color-brand-default);border-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-button--primary:hover:not(.ea-button--disabled){background-color:var(--color-brand-hover);border-color:var(--color-brand-hover)}.ea-button--primary:active:not(.ea-button--disabled){background-color:var(--color-brand-active);border-color:var(--color-brand-active)}.ea-button--secondary{background-color:transparent;border-color:var(--color-border-strong);color:var(--color-text-primary)}.ea-button--secondary:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted);border-color:var(--color-neutral-500)}.ea-button--secondary:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--ghost{background-color:transparent;border-color:transparent;color:var(--color-text-primary)}.ea-button--ghost:hover:not(.ea-button--disabled){background-color:var(--color-bg-muted)}.ea-button--ghost:active:not(.ea-button--disabled){background-color:var(--color-neutral-200)}.ea-button--danger{background-color:var(--color-error-default);border-color:var(--color-error-default);color:var(--color-text-inverse)}.ea-button--danger:hover:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700)}.ea-button--danger:active:not(.ea-button--disabled){background-color:var(--color-error-700);border-color:var(--color-error-700);filter:brightness(.9)}.ea-button--full-width{width:100%}.ea-button--disabled,.ea-button:disabled{opacity:.45;cursor:not-allowed;pointer-events:none}.ea-button--loading{cursor:wait;pointer-events:none}.ea-button__content{display:inline-flex;align-items:center;gap:var(--inline-xs)}.ea-button__content--hidden{visibility:hidden}.ea-button__label{display:inline-flex;align-items:center}.ea-button__spinner{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.ea-button__spinner svg{width:1.1em;height:1.1em;animation:ea-spin .75s linear infinite}:host(.ea-button--full-width){display:block;width:100%}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
2682
2970
  }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], ariaCurrent: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-current", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
2683
2971
 
2684
2972
  /**
@@ -2693,11 +2981,11 @@ class DividerComponent {
2693
2981
  'ea-divider--with-label': !!this.label(),
2694
2982
  }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
2695
2983
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DividerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2696
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: DividerComponent, isStandalone: true, selector: "ea-divider", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"ea-divider\"\n [ngClass]=\"hostClasses()\"\n [attr.role]=\"'separator'\"\n [attr.aria-orientation]=\"orientation()\">\n @if (label()) {\n <span class=\"ea-divider__label\">{{ label() }}</span>\n }\n</div>\n", styles: [".ea-divider{flex-shrink:0;border:0;font-family:var(--font-family-sans)}.ea-divider--horizontal{display:flex;align-items:center;width:100%;height:1px;background-color:var(--color-border-default)}.ea-divider--vertical{display:inline-block;width:1px;height:100%;min-height:1rem;background-color:var(--color-border-default)}.ea-divider--with-label{height:auto;background-color:transparent;gap:var(--space-3)}.ea-divider--with-label:before,.ea-divider--with-label:after{content:\"\";flex:1;height:1px;background-color:var(--color-border-default)}.ea-divider__label{flex-shrink:0;font-size:var(--font-size-sm);line-height:var(--line-height-normal);color:var(--color-text-secondary);white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2984
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: DividerComponent, isStandalone: true, selector: "ea-divider", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"ea-divider\"\n [ngClass]=\"hostClasses()\"\n [attr.role]=\"'separator'\"\n [attr.aria-orientation]=\"orientation()\">\n @if (label()) {\n <span class=\"ea-divider__label\">{{ label() }}</span>\n }\n</div>\n", styles: [".ea-divider{flex-shrink:0;border:0;font-family:var(--font-family-sans)}.ea-divider--horizontal{display:flex;align-items:center;width:100%;height:1px;background-color:var(--color-border-default)}.ea-divider--vertical{display:inline-block;width:1px;height:1.5em;min-height:1rem;background-color:var(--color-border-default)}.ea-divider--with-label{height:auto;background-color:transparent;gap:var(--space-3)}.ea-divider--with-label:before,.ea-divider--with-label:after{content:\"\";flex:1;height:1px;background-color:var(--color-border-default)}.ea-divider__label{flex-shrink:0;font-size:var(--font-size-sm);line-height:var(--line-height-normal);color:var(--color-text-secondary);white-space:nowrap}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
2697
2985
  }
2698
2986
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DividerComponent, decorators: [{
2699
2987
  type: Component,
2700
- args: [{ selector: 'ea-divider', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-divider\"\n [ngClass]=\"hostClasses()\"\n [attr.role]=\"'separator'\"\n [attr.aria-orientation]=\"orientation()\">\n @if (label()) {\n <span class=\"ea-divider__label\">{{ label() }}</span>\n }\n</div>\n", styles: [".ea-divider{flex-shrink:0;border:0;font-family:var(--font-family-sans)}.ea-divider--horizontal{display:flex;align-items:center;width:100%;height:1px;background-color:var(--color-border-default)}.ea-divider--vertical{display:inline-block;width:1px;height:100%;min-height:1rem;background-color:var(--color-border-default)}.ea-divider--with-label{height:auto;background-color:transparent;gap:var(--space-3)}.ea-divider--with-label:before,.ea-divider--with-label:after{content:\"\";flex:1;height:1px;background-color:var(--color-border-default)}.ea-divider__label{flex-shrink:0;font-size:var(--font-size-sm);line-height:var(--line-height-normal);color:var(--color-text-secondary);white-space:nowrap}\n"] }]
2988
+ args: [{ selector: 'ea-divider', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-divider\"\n [ngClass]=\"hostClasses()\"\n [attr.role]=\"'separator'\"\n [attr.aria-orientation]=\"orientation()\">\n @if (label()) {\n <span class=\"ea-divider__label\">{{ label() }}</span>\n }\n</div>\n", styles: [".ea-divider{flex-shrink:0;border:0;font-family:var(--font-family-sans)}.ea-divider--horizontal{display:flex;align-items:center;width:100%;height:1px;background-color:var(--color-border-default)}.ea-divider--vertical{display:inline-block;width:1px;height:1.5em;min-height:1rem;background-color:var(--color-border-default)}.ea-divider--with-label{height:auto;background-color:transparent;gap:var(--space-3)}.ea-divider--with-label:before,.ea-divider--with-label:after{content:\"\";flex:1;height:1px;background-color:var(--color-border-default)}.ea-divider__label{flex-shrink:0;font-size:var(--font-size-sm);line-height:var(--line-height-normal);color:var(--color-text-secondary);white-space:nowrap}\n"] }]
2701
2989
  }], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
2702
2990
 
2703
2991
  /**
@@ -2872,6 +3160,237 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
2872
3160
  }]
2873
3161
  }] });
2874
3162
 
3163
+ /**
3164
+ * Floating-element primitive. Renders projected content as `position: fixed`
3165
+ * anchored to an external element, with flip-on-overflow, viewport clamping,
3166
+ * outside-click and Escape dismissal, and SSR-safe scroll / resize handling.
3167
+ *
3168
+ * The primitive is intentionally low-level: a parent component drives the
3169
+ * `[open]` state and listens for `(closeRequested)` to mirror it back. Internal
3170
+ * library components (`<ea-menu>`, `<ea-dropdown>`, `<ea-color-picker>`,
3171
+ * `<ea-date-picker>`, `[eaTooltip]`) compose on top of it; downstream apps can
3172
+ * use it directly to build their own popover-based UI.
3173
+ *
3174
+ * @example
3175
+ * ```html
3176
+ * <button #trigger (click)="open.set(!open())">Open</button>
3177
+ * <ea-popover [anchor]="trigger" [open]="open()" (closeRequested)="open.set(false)">
3178
+ * <div>Popover content</div>
3179
+ * </ea-popover>
3180
+ * ```
3181
+ */
3182
+ class PopoverComponent {
3183
+ destroyRef = inject(DestroyRef);
3184
+ surfaceEl = viewChild('surfaceEl', ...(ngDevMode ? [{ debugName: "surfaceEl" }] : /* istanbul ignore next */ []));
3185
+ /** Anchor element the popover positions itself against. */
3186
+ anchor = input.required(...(ngDevMode ? [{ debugName: "anchor" }] : /* istanbul ignore next */ []));
3187
+ /** Whether the popover is currently open. */
3188
+ open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
3189
+ /** Where the popover attaches relative to the anchor. */
3190
+ placement = input('bottom-start', ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
3191
+ /** ARIA role applied to the popover surface. */
3192
+ role = input('dialog', ...(ngDevMode ? [{ debugName: "role" }] : /* istanbul ignore next */ []));
3193
+ /** Accessible label. Falls back to nothing; consumers should provide one when no visible heading is in the popover. */
3194
+ ariaLabel = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabel" } : /* istanbul ignore next */ {}), alias: 'aria-label' });
3195
+ /** DOM id for the surface so trigger elements can reference it via aria-controls. */
3196
+ surfaceId = input(`ea-popover-${Math.random().toString(36).slice(2, 9)}`, ...(ngDevMode ? [{ debugName: "surfaceId" }] : /* istanbul ignore next */ []));
3197
+ /** Gap in px between the anchor and the popover. */
3198
+ offset = input(0, ...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
3199
+ /** Flip to the opposite side when the requested side overflows the viewport. */
3200
+ flip = input(true, ...(ngDevMode ? [{ debugName: "flip" }] : /* istanbul ignore next */ []));
3201
+ /** Clamp the popover inside the viewport when it would otherwise overflow. */
3202
+ clamp = input(true, ...(ngDevMode ? [{ debugName: "clamp" }] : /* istanbul ignore next */ []));
3203
+ /** Set the popover's `min-width` to match the anchor's width (dropdown pattern). */
3204
+ matchAnchorWidth = input(false, ...(ngDevMode ? [{ debugName: "matchAnchorWidth" }] : /* istanbul ignore next */ []));
3205
+ /** Close on click outside the popover and the anchor. */
3206
+ closeOnOutsideClick = input(true, ...(ngDevMode ? [{ debugName: "closeOnOutsideClick" }] : /* istanbul ignore next */ []));
3207
+ /** Close on Escape. */
3208
+ closeOnEscape = input(true, ...(ngDevMode ? [{ debugName: "closeOnEscape" }] : /* istanbul ignore next */ []));
3209
+ /** What to do on scroll / resize while open. */
3210
+ scrollBehavior = input('reposition', ...(ngDevMode ? [{ debugName: "scrollBehavior" }] : /* istanbul ignore next */ []));
3211
+ /** Requested close. The parent should mirror this into `[open]`. */
3212
+ closeRequested = output();
3213
+ position = signal(null, ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
3214
+ /** True placement after flip, for class-based styling (e.g. arrow direction). */
3215
+ effectivePlacement = computed(() => this.position()?.placement ?? this.placement(), ...(ngDevMode ? [{ debugName: "effectivePlacement" }] : /* istanbul ignore next */ []));
3216
+ /** Inline style applied to the surface element. */
3217
+ surfaceStyle = computed(() => {
3218
+ if (!this.open())
3219
+ return { display: 'none' };
3220
+ const p = this.position();
3221
+ // Before the first reposition, hide the surface — at this point it's
3222
+ // sitting at the top-left of the viewport with no coordinates applied
3223
+ // yet, and we don't want a flash on open.
3224
+ if (!p)
3225
+ return { visibility: 'hidden' };
3226
+ const style = {
3227
+ top: `${p.top}px`,
3228
+ left: `${p.left}px`,
3229
+ };
3230
+ if (p.width !== undefined) {
3231
+ style['min-width'] = `${p.width}px`;
3232
+ }
3233
+ return style;
3234
+ }, ...(ngDevMode ? [{ debugName: "surfaceStyle" }] : /* istanbul ignore next */ []));
3235
+ constructor() {
3236
+ // Re-measure and reposition whenever the anchor, placement, surface, or
3237
+ // open state changes. Reading `surfaceEl()` here makes it a tracked signal
3238
+ // dependency, so the effect re-runs once Angular has rendered the `@if`
3239
+ // block and the viewChild signal has updated — at that point both the
3240
+ // anchor and the surface have a `getBoundingClientRect`, and the position
3241
+ // can be computed. This is more reliable than `afterNextRender` because it
3242
+ // doesn't depend on a single render cycle landing in the expected order
3243
+ // (some host environments — Storybook docs mode, for example — defer that
3244
+ // callback in a way that leaves the surface stuck at `visibility: hidden`).
3245
+ // Naturally SSR-safe: the surface never renders on the server, so the
3246
+ // effect always early-returns during prerender.
3247
+ // Teleport the surface to `document.body` as soon as it exists so
3248
+ // `position: fixed` is always relative to the actual viewport (escaping
3249
+ // any transformed/contained ancestor that would otherwise create a new
3250
+ // containing block). Doing the move on init — not on open — also means
3251
+ // the first `getBoundingClientRect` call inside `reposition()` reads a
3252
+ // surface that's already in its final DOM home, so the browser's layout
3253
+ // is settled and dimensions are accurate. Skipped in SSR (no `document`).
3254
+ effect(() => {
3255
+ const surface = this.surfaceEl()?.nativeElement;
3256
+ if (surface &&
3257
+ typeof document !== 'undefined' &&
3258
+ surface.parentNode !== document.body) {
3259
+ document.body.appendChild(surface);
3260
+ }
3261
+ });
3262
+ effect(() => {
3263
+ const surface = this.surfaceEl()?.nativeElement;
3264
+ const anchor = this.resolveAnchor();
3265
+ const isOpen = this.open();
3266
+ if (!surface || !anchor || !isOpen) {
3267
+ this.position.set(null);
3268
+ return;
3269
+ }
3270
+ // Re-read inputs so signal subscriptions stay current after a re-open.
3271
+ this.placement();
3272
+ this.offset();
3273
+ this.flip();
3274
+ this.clamp();
3275
+ this.matchAnchorWidth();
3276
+ this.reposition();
3277
+ });
3278
+ // Watch the surface's own size and reposition whenever it changes. The
3279
+ // first `reposition()` after open fires synchronously inside the open
3280
+ // effect, while the surface is still transitioning out of `display: none`
3281
+ // — in some browsers the layout pass hasn't completed, so the
3282
+ // `getBoundingClientRect` width can read as the surface's natural width
3283
+ // even when that overflows the viewport, so the clamp can't kick in. The
3284
+ // ResizeObserver fires once the surface has been laid out with its real
3285
+ // dimensions, giving us a second, accurate measurement to clamp against.
3286
+ // Also catches projected-content size changes while the popover is open
3287
+ // (e.g. virtualised lists adding rows).
3288
+ if (typeof ResizeObserver !== 'undefined') {
3289
+ const surfaceResizeObserver = new ResizeObserver(() => {
3290
+ if (this.open())
3291
+ this.reposition();
3292
+ });
3293
+ effect(() => {
3294
+ const surface = this.surfaceEl()?.nativeElement;
3295
+ surfaceResizeObserver.disconnect();
3296
+ if (surface)
3297
+ surfaceResizeObserver.observe(surface);
3298
+ });
3299
+ this.destroyRef.onDestroy(() => surfaceResizeObserver.disconnect());
3300
+ }
3301
+ // Listen for scroll / resize while open. The `scrollBehavior` input picks
3302
+ // the response. SSR guard is required because the website prerenders pages
3303
+ // that mount popovers.
3304
+ if (typeof window !== 'undefined') {
3305
+ const onViewportChange = () => {
3306
+ if (!this.open())
3307
+ return;
3308
+ const behavior = this.scrollBehavior();
3309
+ if (behavior === 'close') {
3310
+ this.closeRequested.emit();
3311
+ }
3312
+ else if (behavior === 'reposition') {
3313
+ this.reposition();
3314
+ }
3315
+ };
3316
+ window.addEventListener('scroll', onViewportChange, {
3317
+ capture: true,
3318
+ passive: true,
3319
+ });
3320
+ window.addEventListener('resize', onViewportChange);
3321
+ this.destroyRef.onDestroy(() => {
3322
+ window.removeEventListener('scroll', onViewportChange, { capture: true });
3323
+ window.removeEventListener('resize', onViewportChange);
3324
+ });
3325
+ }
3326
+ // Explicitly remove the portaled surface on destroy. Angular's view
3327
+ // destruction normally removes nodes the renderer created, but moving the
3328
+ // surface via raw `appendChild` (out of its original anchor slot) is
3329
+ // enough to break that tracking in some host environments — Storybook's
3330
+ // SPA navigation between docs pages, for one, leaves the surface stranded
3331
+ // in `document.body` after the parent component is gone. Removing it here
3332
+ // guarantees cleanup regardless of how Angular's view destruction handles
3333
+ // the relocated node.
3334
+ this.destroyRef.onDestroy(() => {
3335
+ const surface = this.surfaceEl()?.nativeElement;
3336
+ surface?.parentNode?.removeChild(surface);
3337
+ });
3338
+ }
3339
+ resolveAnchor() {
3340
+ const a = this.anchor();
3341
+ if (!a)
3342
+ return null;
3343
+ return a instanceof ElementRef ? a.nativeElement : a;
3344
+ }
3345
+ reposition() {
3346
+ if (typeof window === 'undefined')
3347
+ return;
3348
+ const anchor = this.resolveAnchor();
3349
+ const surface = this.surfaceEl()?.nativeElement;
3350
+ if (!anchor || !surface)
3351
+ return;
3352
+ const anchorRect = anchor.getBoundingClientRect();
3353
+ const surfaceRect = surface.getBoundingClientRect();
3354
+ this.position.set(computePopoverPosition(anchorRect, { width: surfaceRect.width, height: surfaceRect.height }, { width: window.innerWidth, height: window.innerHeight }, {
3355
+ placement: this.placement(),
3356
+ offset: this.offset(),
3357
+ flip: this.flip(),
3358
+ clamp: this.clamp(),
3359
+ matchAnchorWidth: this.matchAnchorWidth(),
3360
+ }));
3361
+ }
3362
+ onDocumentClick(event) {
3363
+ if (!this.open() || !this.closeOnOutsideClick())
3364
+ return;
3365
+ const target = event.target;
3366
+ if (!target)
3367
+ return;
3368
+ const anchor = this.resolveAnchor();
3369
+ if (anchor?.contains(target))
3370
+ return;
3371
+ if (this.surfaceEl()?.nativeElement.contains(target))
3372
+ return;
3373
+ this.closeRequested.emit();
3374
+ }
3375
+ onEscape() {
3376
+ if (!this.open() || !this.closeOnEscape())
3377
+ return;
3378
+ this.closeRequested.emit();
3379
+ }
3380
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3381
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.13", type: PopoverComponent, isStandalone: true, selector: "ea-popover", inputs: { anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: true, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, surfaceId: { classPropertyName: "surfaceId", publicName: "surfaceId", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "flip", isSignal: true, isRequired: false, transformFunction: null }, clamp: { classPropertyName: "clamp", publicName: "clamp", isSignal: true, isRequired: false, transformFunction: null }, matchAnchorWidth: { classPropertyName: "matchAnchorWidth", publicName: "matchAnchorWidth", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsideClick: { classPropertyName: "closeOnOutsideClick", publicName: "closeOnOutsideClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnEscape: { classPropertyName: "closeOnEscape", publicName: "closeOnEscape", isSignal: true, isRequired: false, transformFunction: null }, scrollBehavior: { classPropertyName: "scrollBehavior", publicName: "scrollBehavior", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closeRequested: "closeRequested" }, host: { listeners: { "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "surfaceEl", first: true, predicate: ["surfaceEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<!--\n The surface is rendered unconditionally so the `<ng-content/>` slot always\n exists. If we gated it on `@if (open())`, Angular would re-project the\n consumer's content at the popover host's position whenever the surface was\n absent \u2014 leaking menu items / picker controls into the document flow (made\n worse by `display: contents` on the host). Hiding via `display: none` keeps\n the projected DOM owned by the surface and out of the flow when closed.\n-->\n<div\n #surfaceEl\n class=\"ea-popover__surface\"\n [class]=\"'ea-popover__surface--' + effectivePlacement()\"\n [id]=\"surfaceId()\"\n [attr.role]=\"open() ? role() : null\"\n [attr.aria-label]=\"open() ? ariaLabel() : null\"\n [attr.aria-hidden]=\"open() ? null : true\"\n [style]=\"surfaceStyle()\">\n <ng-content />\n</div>\n", styles: [":host{display:contents}.ea-popover__surface{z-index:var(--z-index-dropdown);position:fixed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3382
+ }
3383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PopoverComponent, decorators: [{
3384
+ type: Component,
3385
+ args: [{ selector: 'ea-popover', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!--\n The surface is rendered unconditionally so the `<ng-content/>` slot always\n exists. If we gated it on `@if (open())`, Angular would re-project the\n consumer's content at the popover host's position whenever the surface was\n absent \u2014 leaking menu items / picker controls into the document flow (made\n worse by `display: contents` on the host). Hiding via `display: none` keeps\n the projected DOM owned by the surface and out of the flow when closed.\n-->\n<div\n #surfaceEl\n class=\"ea-popover__surface\"\n [class]=\"'ea-popover__surface--' + effectivePlacement()\"\n [id]=\"surfaceId()\"\n [attr.role]=\"open() ? role() : null\"\n [attr.aria-label]=\"open() ? ariaLabel() : null\"\n [attr.aria-hidden]=\"open() ? null : true\"\n [style]=\"surfaceStyle()\">\n <ng-content />\n</div>\n", styles: [":host{display:contents}.ea-popover__surface{z-index:var(--z-index-dropdown);position:fixed}\n"] }]
3386
+ }], ctorParameters: () => [], propDecorators: { surfaceEl: [{ type: i0.ViewChild, args: ['surfaceEl', { isSignal: true }] }], anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: true }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], surfaceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "surfaceId", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], flip: [{ type: i0.Input, args: [{ isSignal: true, alias: "flip", required: false }] }], clamp: [{ type: i0.Input, args: [{ isSignal: true, alias: "clamp", required: false }] }], matchAnchorWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "matchAnchorWidth", required: false }] }], closeOnOutsideClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnOutsideClick", required: false }] }], closeOnEscape: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeOnEscape", required: false }] }], scrollBehavior: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollBehavior", required: false }] }], closeRequested: [{ type: i0.Output, args: ["closeRequested"] }], onDocumentClick: [{
3387
+ type: HostListener,
3388
+ args: ['document:click', ['$event']]
3389
+ }], onEscape: [{
3390
+ type: HostListener,
3391
+ args: ['document:keydown.escape']
3392
+ }] } });
3393
+
2875
3394
  const DEFAULT_PRESETS = [
2876
3395
  '#ef4444',
2877
3396
  '#f97316',
@@ -2901,14 +3420,11 @@ const DEFAULT_PRESETS = [
2901
3420
  * `ControlValueAccessor`. Accepts any CSS color string in `writeValue`.
2902
3421
  */
2903
3422
  class ColorPickerComponent {
2904
- hostEl = viewChild('hostEl', ...(ngDevMode ? [{ debugName: "hostEl" }] : /* istanbul ignore next */ []));
2905
3423
  triggerEl = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
2906
- popoverEl = viewChild('popoverEl', ...(ngDevMode ? [{ debugName: "popoverEl" }] : /* istanbul ignore next */ []));
2907
3424
  svAreaEl = viewChild('svAreaEl', ...(ngDevMode ? [{ debugName: "svAreaEl" }] : /* istanbul ignore next */ []));
2908
3425
  hueTrackEl = viewChild('hueTrackEl', ...(ngDevMode ? [{ debugName: "hueTrackEl" }] : /* istanbul ignore next */ []));
2909
3426
  alphaTrackEl = viewChild('alphaTrackEl', ...(ngDevMode ? [{ debugName: "alphaTrackEl" }] : /* istanbul ignore next */ []));
2910
3427
  injector = inject(Injector);
2911
- destroyRef = inject(DestroyRef);
2912
3428
  i18n = inject(EagamiI18nService);
2913
3429
  label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
2914
3430
  placeholder = input(undefined, ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
@@ -2943,10 +3459,6 @@ class ColorPickerComponent {
2943
3459
  * can type a partial value (`#1`, `#12`, `#123…`) without each keystroke being
2944
3460
  * expanded back into a 6-digit canonical form. */
2945
3461
  hexInputValue = signal('', ...(ngDevMode ? [{ debugName: "hexInputValue" }] : /* istanbul ignore next */ []));
2946
- /** Pixel position of the popover when open. Calculated from the trigger's
2947
- * bounding rect so the popover can use `position: fixed` and escape any
2948
- * ancestor with `overflow: hidden`. */
2949
- popoverPosition = signal(null, ...(ngDevMode ? [{ debugName: "popoverPosition" }] : /* istanbul ignore next */ []));
2950
3462
  _formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_formDisabled" }] : /* istanbul ignore next */ []));
2951
3463
  onChange = () => { };
2952
3464
  onTouched = () => { };
@@ -2981,51 +3493,18 @@ class ColorPickerComponent {
2981
3493
  'ea-color-picker__trigger--open': this.isOpen(),
2982
3494
  'ea-color-picker__trigger--disabled': this.isDisabled(),
2983
3495
  }), ...(ngDevMode ? [{ debugName: "triggerClasses" }] : /* istanbul ignore next */ []));
2984
- /** True when the browser supports the EyeDropper API. */
2985
- hasEyeDropper = computed(() => {
3496
+ /**
3497
+ * True when the browser supports the EyeDropper API. Not a `computed`
3498
+ * `window.EyeDropper` isn't a signal, so a memoized computed would cache the
3499
+ * first read (typically `false`, since the popover content's bindings now
3500
+ * evaluate at parent-view creation time via content projection, before any
3501
+ * polyfill / test setup runs). A plain method re-checks on every call.
3502
+ */
3503
+ hasEyeDropper() {
2986
3504
  if (typeof window === 'undefined')
2987
3505
  return false;
2988
3506
  return (typeof window.EyeDropper ===
2989
3507
  'function');
2990
- }, ...(ngDevMode ? [{ debugName: "hasEyeDropper" }] : /* istanbul ignore next */ []));
2991
- constructor() {
2992
- // When the popover opens, anchor it to the trigger using `position: fixed`
2993
- // coordinates so it escapes any ancestor with `overflow: hidden` (a common
2994
- // gotcha in scrollable content panels — same pattern as `<ea-dropdown>`).
2995
- // After the popover renders we measure it and, if it would overflow the
2996
- // viewport bottom, flip it above the trigger (or clamp against the top
2997
- // edge when neither direction fits — better than getting trapped below
2998
- // the fold with no way to scroll, which the page-scroll wouldn't reach
2999
- // because the popover itself is fixed).
3000
- effect(() => {
3001
- const trigger = this.triggerEl()?.nativeElement;
3002
- if (!trigger || !this.isOpen()) {
3003
- this.popoverPosition.set(null);
3004
- return;
3005
- }
3006
- const rect = trigger.getBoundingClientRect();
3007
- this.popoverPosition.set({ top: rect.bottom + 4, left: rect.left });
3008
- // Re-measure once the popover has actually rendered so we know its height.
3009
- afterNextRender(() => this.clampPopoverToViewport(), { injector: this.injector });
3010
- });
3011
- // Close the popover on scroll / resize rather than try to track the trigger
3012
- // — same pattern as `<ea-dropdown>`. SSR-guarded because the website
3013
- // prerenders pages that render this component.
3014
- if (typeof window !== 'undefined') {
3015
- const closeOnViewportChange = () => {
3016
- if (this.isOpen())
3017
- this.close();
3018
- };
3019
- window.addEventListener('scroll', closeOnViewportChange, {
3020
- capture: true,
3021
- passive: true,
3022
- });
3023
- window.addEventListener('resize', closeOnViewportChange);
3024
- this.destroyRef.onDestroy(() => {
3025
- window.removeEventListener('scroll', closeOnViewportChange, { capture: true });
3026
- window.removeEventListener('resize', closeOnViewportChange);
3027
- });
3028
- }
3029
3508
  }
3030
3509
  // ─── ControlValueAccessor ─────────────────────────────────────────────
3031
3510
  writeValue(val) {
@@ -3366,42 +3845,9 @@ class ColorPickerComponent {
3366
3845
  this.triggerEl()?.nativeElement.focus({ preventScroll: true });
3367
3846
  }
3368
3847
  }
3369
- onDocumentClick(event) {
3370
- if (!this.isOpen())
3371
- return;
3372
- const host = this.hostEl()?.nativeElement;
3373
- if (host && !host.contains(event.target))
3374
- this.close();
3375
- }
3376
- /**
3377
- * Repositions the popover when it would extend past the viewport edges.
3378
- * Prefers flipping above the trigger when there's more room there, then
3379
- * clamps so the popover always has a small margin from the viewport edges.
3380
- */
3381
- clampPopoverToViewport() {
3382
- const popover = this.popoverEl()?.nativeElement;
3383
- const trigger = this.triggerEl()?.nativeElement;
3384
- const current = this.popoverPosition();
3385
- if (!popover || !trigger || !current)
3386
- return;
3387
- const margin = 8;
3388
- const triggerRect = trigger.getBoundingClientRect();
3389
- const popoverRect = popover.getBoundingClientRect();
3390
- const viewportH = window.innerHeight;
3391
- const viewportW = window.innerWidth;
3392
- let top = current.top;
3393
- const overflowsBottom = top + popoverRect.height > viewportH - margin;
3394
- const roomAbove = triggerRect.top - margin;
3395
- if (overflowsBottom && roomAbove >= popoverRect.height + 4) {
3396
- top = triggerRect.top - popoverRect.height - 4;
3397
- }
3398
- else if (overflowsBottom) {
3399
- top = Math.max(margin, viewportH - popoverRect.height - margin);
3400
- }
3401
- const left = Math.max(margin, Math.min(current.left, viewportW - popoverRect.width - margin));
3402
- if (top !== current.top || left !== current.left) {
3403
- this.popoverPosition.set({ top, left });
3404
- }
3848
+ /** Called by `<ea-popover>` when the user clicks outside the picker. */
3849
+ onPopoverCloseRequested() {
3850
+ this.close();
3405
3851
  }
3406
3852
  // ─── Internal: applying state and committing ──────────────────────────
3407
3853
  applyHsv(h, s, v) {
@@ -3436,27 +3882,24 @@ class ColorPickerComponent {
3436
3882
  this.hexInputValue.set(this.hexDisplay());
3437
3883
  }
3438
3884
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ColorPickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3439
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: ColorPickerComponent, isStandalone: true, selector: "ea-color-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, showAlpha: { classPropertyName: "showAlpha", publicName: "showAlpha", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
3885
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: ColorPickerComponent, isStandalone: true, selector: "ea-color-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, showAlpha: { classPropertyName: "showAlpha", publicName: "showAlpha", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, presets: { classPropertyName: "presets", publicName: "presets", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, providers: [
3440
3886
  {
3441
3887
  provide: NG_VALUE_ACCESSOR,
3442
3888
  useExisting: forwardRef(() => ColorPickerComponent),
3443
3889
  multi: true,
3444
3890
  },
3445
- ], viewQueries: [{ propertyName: "hostEl", first: true, predicate: ["hostEl"], descendants: true, isSignal: true }, { propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "popoverEl", first: true, predicate: ["popoverEl"], descendants: true, isSignal: true }, { propertyName: "svAreaEl", first: true, predicate: ["svAreaEl"], descendants: true, isSignal: true }, { propertyName: "hueTrackEl", first: true, predicate: ["hueTrackEl"], descendants: true, isSignal: true }, { propertyName: "alphaTrackEl", first: true, predicate: ["alphaTrackEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #hostEl\n class=\"ea-color-picker-field\">\n @if (label()) {\n <label\n class=\"ea-color-picker-field__label\"\n [for]=\"id()\"\n [class.ea-color-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-color-picker\">\n <div class=\"ea-color-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-color-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <span\n class=\"ea-color-picker__swatch\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"value() ? displayColor() : null\">\n </span>\n </span>\n <span\n class=\"ea-color-picker__trigger-value\"\n [class.ea-color-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-color-picker__clear\"\n [attr.aria-label]=\"i18n.messages().colorPicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n @if (isOpen()) {\n <div\n #popoverEl\n class=\"ea-color-picker__popover\"\n role=\"dialog\"\n [attr.aria-label]=\"label() || i18n.messages().colorPicker.placeholder\"\n [style.top.px]=\"popoverPosition()?.top\"\n [style.left.px]=\"popoverPosition()?.left\"\n (keydown)=\"onPopoverKeydown($event)\">\n <div\n #svAreaEl\n class=\"ea-color-picker__sv-area\"\n role=\"application\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.saturationAndValue\"\n [style.background-color]=\"hueColor()\"\n (pointerdown)=\"onSvPointerDown($event)\"\n (pointermove)=\"onSvPointerMove($event)\"\n (pointerup)=\"onSvPointerUp($event)\"\n (pointercancel)=\"onSvPointerUp($event)\"\n (keydown)=\"onSvKeydown($event)\">\n <div class=\"ea-color-picker__sv-area-sat\"></div>\n <div class=\"ea-color-picker__sv-area-val\"></div>\n <div\n class=\"ea-color-picker__sv-pointer\"\n [style.background-color]=\"opaqueColor()\"\n [style.left]=\"svPointerLeft()\"\n [style.top]=\"svPointerTop()\">\n </div>\n </div>\n\n <div class=\"ea-color-picker__sliders\">\n <div class=\"ea-color-picker__slider-row\">\n <span\n class=\"ea-color-picker__swatch ea-color-picker__swatch--lg\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"displayColor()\">\n </span>\n </span>\n <div class=\"ea-color-picker__strip-stack\">\n <div\n #hueTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--hue\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.hue\"\n [attr.aria-valuemin]=\"0\"\n [attr.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 (keydown)=\"onHueKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"huePointerLeft()\">\n </div>\n </div>\n @if (showAlpha()) {\n <div\n #alphaTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--alpha\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.alpha\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuenow]=\"alphaPointerLeft()\"\n [style.--ea-color-picker-alpha-base]=\"opaqueColor()\"\n (pointerdown)=\"onAlphaPointerDown($event)\"\n (pointermove)=\"onAlphaPointerMove($event)\"\n (pointerup)=\"onAlphaPointerUp($event)\"\n (pointercancel)=\"onAlphaPointerUp($event)\"\n (keydown)=\"onAlphaKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"alphaPointerLeft()\">\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <div\n class=\"ea-color-picker__inputs\"\n [class.ea-color-picker__inputs--hex]=\"inputMode() === 'hex'\">\n @if (inputMode() === 'hex') {\n <label class=\"ea-color-picker__input-group ea-color-picker__input-group--hex\">\n <span class=\"ea-color-picker__input-label\">HEX</span>\n <input\n class=\"ea-color-picker__input\"\n type=\"text\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n maxlength=\"9\"\n [value]=\"hexInputValue()\"\n (input)=\"onHexInput($event)\"\n (blur)=\"onHexBlur()\" />\n </label>\n } @else {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">R</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().r\"\n (input)=\"onRgbInput('r', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">G</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().g\"\n (input)=\"onRgbInput('g', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">B</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().b\"\n (input)=\"onRgbInput('b', $event)\" />\n </label>\n @if (showAlpha()) {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">A</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"alphaPercentRounded()\"\n (input)=\"onAlphaInput($event)\" />\n </label>\n }\n }\n <button\n type=\"button\"\n class=\"ea-color-picker__format-toggle\"\n [attr.aria-label]=\"i18n.messages().colorPicker.toggleFormat\"\n (click)=\"cycleInputMode()\">\n {{ inputMode() === 'hex' ? 'HEX' : 'RGB' }}\n </button>\n </div>\n\n @if (hasEyeDropper()) {\n <div class=\"ea-color-picker__tools\">\n <button\n type=\"button\"\n class=\"ea-color-picker__tool-btn\"\n [attr.aria-label]=\"i18n.messages().colorPicker.eyedropper\"\n (click)=\"pickFromScreen()\">\n <ea-icon-droplet aria-hidden=\"true\" />\n <span>{{ i18n.messages().colorPicker.eyedropper }}</span>\n </button>\n </div>\n }\n\n @if (presets().length > 0) {\n <div class=\"ea-color-picker__presets\">\n <span class=\"ea-color-picker__presets-label\">\n {{ i18n.messages().colorPicker.presets }}\n </span>\n <div\n class=\"ea-color-picker__presets-grid\"\n role=\"listbox\">\n @for (preset of presets(); track preset) {\n <button\n type=\"button\"\n class=\"ea-color-picker__preset\"\n role=\"option\"\n [attr.aria-label]=\"preset\"\n [attr.aria-selected]=\"value() === preset\"\n [style.background-color]=\"preset\"\n (click)=\"selectPreset(preset)\">\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-color-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-color-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-color-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-color-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-color-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-color-picker-field__message--hint{color:var(--color-text-secondary)}.ea-color-picker-field__message--error{color:var(--color-error-default)}.ea-color-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-color-picker,.ea-color-picker__trigger-wrapper{position:relative}.ea-color-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-color-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-color-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-color-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-color-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--error{border-color:var(--color-error-default)}.ea-color-picker__trigger--error.ea-color-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-color-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-color-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-family-mono);font-size:.85em}.ea-color-picker__trigger-value--placeholder{color:var(--color-text-tertiary);font-family:var(--font-family-sans);font-size:1em}.ea-color-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-color-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__swatch{position:relative;overflow:hidden;flex-shrink:0;width:1.125rem;height:1.125rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);background-image:linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__swatch--lg{width:2.5rem;height:2.5rem;border-radius:var(--radius-md)}.ea-color-picker__swatch-fill{position:absolute;inset:0;display:block}.ea-color-picker__popover{position:fixed;z-index:var(--z-index-popover);display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-3);width:17.5rem;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg)}.ea-color-picker__sv-area{position:relative;overflow:hidden;width:100%;height:10rem;border-radius:var(--radius-sm);cursor:crosshair;touch-action:none}.ea-color-picker__sv-area:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__sv-area-sat{position:absolute;inset:0;background:linear-gradient(to right,var(--color-picker-sv-white),transparent)}.ea-color-picker__sv-area-val{position:absolute;inset:0;background:linear-gradient(to top,var(--color-picker-sv-black),transparent)}.ea-color-picker__sv-pointer{position:absolute;z-index:1;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__slider-row{display:flex;align-items:center;gap:var(--space-2)}.ea-color-picker__strip-stack{display:flex;flex-direction:column;flex:1;gap:var(--space-2)}.ea-color-picker__strip{position:relative;width:100%;height:.75rem;border-radius:var(--radius-full);cursor:pointer;touch-action:none}.ea-color-picker__strip:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__strip--hue{background:linear-gradient(to right,var(--color-picker-hue-red) 0%,var(--color-picker-hue-yellow) 17%,var(--color-picker-hue-green) 33%,var(--color-picker-hue-cyan) 50%,var(--color-picker-hue-blue) 67%,var(--color-picker-hue-magenta) 83%,var(--color-picker-hue-red) 100%)}.ea-color-picker__strip--alpha{background-color:var(--color-bg-base);background-image:linear-gradient(to right,transparent 0%,var(--ea-color-picker-alpha-base, currentcolor) 100%),linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:100% 100%,8px 8px,8px 8px,8px 8px,8px 8px;background-position:0 0,0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__strip-thumb{position:absolute;top:50%;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__inputs{display:flex;align-items:end;gap:var(--space-1)}.ea-color-picker__input-group{display:flex;flex:1;flex-direction:column;gap:var(--space-1);min-width:0;text-align:center}.ea-color-picker__input-group--hex{flex:1}.ea-color-picker__format-toggle{flex-shrink:0;min-width:3.25rem;padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);letter-spacing:.04em;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__format-toggle:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__format-toggle:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__input{width:100%;min-width:0;padding:var(--space-1) var(--space-1-5);background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);font-family:var(--font-family-mono);font-size:var(--font-size-xs);text-align:center;color:var(--color-text-primary)}.ea-color-picker__input:focus-visible{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input--num{appearance:textfield}.ea-color-picker__input--num::-webkit-outer-spin-button,.ea-color-picker__input--num::-webkit-inner-spin-button{appearance:none;margin:0}.ea-color-picker__tools{display:flex;justify-content:flex-start}.ea-color-picker__tool-btn{display:inline-flex;align-items:center;gap:var(--space-1-5);padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-xs);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__tool-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__tool-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__tool-btn ea-icon-droplet{width:.875em;height:.875em}.ea-color-picker__presets{display:flex;flex-direction:column;gap:var(--space-1-5);padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-color-picker__presets-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__presets-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:var(--space-1)}.ea-color-picker__preset{width:100%;aspect-ratio:1;padding:0;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);cursor:pointer;transition:transform var(--duration-fast) var(--ease-out)}.ea-color-picker__preset:hover{transform:scale(1.1)}.ea-color-picker__preset:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__preset[aria-selected=true]{box-shadow:0 0 0 2px var(--color-brand-default)}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: DropletIconComponent, selector: "ea-icon-droplet" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3891
+ ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "svAreaEl", first: true, predicate: ["svAreaEl"], descendants: true, isSignal: true }, { propertyName: "hueTrackEl", first: true, predicate: ["hueTrackEl"], descendants: true, isSignal: true }, { propertyName: "alphaTrackEl", first: true, predicate: ["alphaTrackEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-color-picker-field\">\n @if (label()) {\n <label\n class=\"ea-color-picker-field__label\"\n [for]=\"id()\"\n [class.ea-color-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-color-picker\">\n <div class=\"ea-color-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-color-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <span\n class=\"ea-color-picker__swatch\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"value() ? displayColor() : null\">\n </span>\n </span>\n <span\n class=\"ea-color-picker__trigger-value\"\n [class.ea-color-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-color-picker__clear\"\n [attr.aria-label]=\"i18n.messages().colorPicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"dialog\"\n [ariaLabel]=\"label() || i18n.messages().colorPicker.placeholder\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div\n class=\"ea-color-picker__popover\"\n (keydown)=\"onPopoverKeydown($event)\">\n <div\n #svAreaEl\n class=\"ea-color-picker__sv-area\"\n role=\"application\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.saturationAndValue\"\n [style.background-color]=\"hueColor()\"\n (pointerdown)=\"onSvPointerDown($event)\"\n (pointermove)=\"onSvPointerMove($event)\"\n (pointerup)=\"onSvPointerUp($event)\"\n (pointercancel)=\"onSvPointerUp($event)\"\n (keydown)=\"onSvKeydown($event)\">\n <div class=\"ea-color-picker__sv-area-sat\"></div>\n <div class=\"ea-color-picker__sv-area-val\"></div>\n <div\n class=\"ea-color-picker__sv-pointer\"\n [style.background-color]=\"opaqueColor()\"\n [style.left]=\"svPointerLeft()\"\n [style.top]=\"svPointerTop()\">\n </div>\n </div>\n\n <div class=\"ea-color-picker__sliders\">\n <div class=\"ea-color-picker__slider-row\">\n <span\n class=\"ea-color-picker__swatch ea-color-picker__swatch--lg\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"displayColor()\">\n </span>\n </span>\n <div class=\"ea-color-picker__strip-stack\">\n <div\n #hueTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--hue\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.hue\"\n [attr.aria-valuemin]=\"0\"\n [attr.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 (keydown)=\"onHueKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"huePointerLeft()\">\n </div>\n </div>\n @if (showAlpha()) {\n <div\n #alphaTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--alpha\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.alpha\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuenow]=\"alphaPointerLeft()\"\n [style.--ea-color-picker-alpha-base]=\"opaqueColor()\"\n (pointerdown)=\"onAlphaPointerDown($event)\"\n (pointermove)=\"onAlphaPointerMove($event)\"\n (pointerup)=\"onAlphaPointerUp($event)\"\n (pointercancel)=\"onAlphaPointerUp($event)\"\n (keydown)=\"onAlphaKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"alphaPointerLeft()\">\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <div\n class=\"ea-color-picker__inputs\"\n [class.ea-color-picker__inputs--hex]=\"inputMode() === 'hex'\">\n @if (inputMode() === 'hex') {\n <label class=\"ea-color-picker__input-group ea-color-picker__input-group--hex\">\n <span class=\"ea-color-picker__input-label\">HEX</span>\n <input\n class=\"ea-color-picker__input\"\n type=\"text\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n maxlength=\"9\"\n [value]=\"hexInputValue()\"\n (input)=\"onHexInput($event)\"\n (blur)=\"onHexBlur()\" />\n </label>\n } @else {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">R</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().r\"\n (input)=\"onRgbInput('r', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">G</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().g\"\n (input)=\"onRgbInput('g', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">B</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().b\"\n (input)=\"onRgbInput('b', $event)\" />\n </label>\n @if (showAlpha()) {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">A</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"alphaPercentRounded()\"\n (input)=\"onAlphaInput($event)\" />\n </label>\n }\n }\n <button\n type=\"button\"\n class=\"ea-color-picker__format-toggle\"\n [attr.aria-label]=\"i18n.messages().colorPicker.toggleFormat\"\n (click)=\"cycleInputMode()\">\n {{ inputMode() === 'hex' ? 'HEX' : 'RGB' }}\n </button>\n </div>\n\n @if (hasEyeDropper()) {\n <div class=\"ea-color-picker__tools\">\n <button\n type=\"button\"\n class=\"ea-color-picker__tool-btn\"\n [attr.aria-label]=\"i18n.messages().colorPicker.eyedropper\"\n (click)=\"pickFromScreen()\">\n <ea-icon-droplet aria-hidden=\"true\" />\n <span>{{ i18n.messages().colorPicker.eyedropper }}</span>\n </button>\n </div>\n }\n\n @if (presets().length > 0) {\n <div class=\"ea-color-picker__presets\">\n <span class=\"ea-color-picker__presets-label\">\n {{ i18n.messages().colorPicker.presets }}\n </span>\n <div\n class=\"ea-color-picker__presets-grid\"\n role=\"listbox\">\n @for (preset of presets(); track preset) {\n <button\n type=\"button\"\n class=\"ea-color-picker__preset\"\n role=\"option\"\n [attr.aria-label]=\"preset\"\n [attr.aria-selected]=\"value() === preset\"\n [style.background-color]=\"preset\"\n (click)=\"selectPreset(preset)\">\n </button>\n }\n </div>\n </div>\n }\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-color-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-color-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-color-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-color-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-color-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-color-picker-field__message--hint{color:var(--color-text-secondary)}.ea-color-picker-field__message--error{color:var(--color-error-default)}.ea-color-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-color-picker,.ea-color-picker__trigger-wrapper{position:relative}.ea-color-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-color-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-color-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-color-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-color-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--error{border-color:var(--color-error-default)}.ea-color-picker__trigger--error.ea-color-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-color-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-color-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-family-mono);font-size:.85em}.ea-color-picker__trigger-value--placeholder{color:var(--color-text-tertiary);font-family:var(--font-family-sans);font-size:1em}.ea-color-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-color-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__swatch{position:relative;overflow:hidden;flex-shrink:0;width:1.125rem;height:1.125rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);background-image:linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__swatch--lg{width:2.5rem;height:2.5rem;border-radius:var(--radius-md)}.ea-color-picker__swatch-fill{position:absolute;inset:0;display:block}.ea-color-picker__popover{display:flex;flex-direction:column;gap:var(--space-3);width:17.5rem;padding:var(--space-3);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-color-picker__sv-area{position:relative;overflow:hidden;width:100%;height:10rem;border-radius:var(--radius-sm);cursor:crosshair;touch-action:none}.ea-color-picker__sv-area:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__sv-area-sat{position:absolute;inset:0;background:linear-gradient(to right,var(--color-picker-sv-white),transparent)}.ea-color-picker__sv-area-val{position:absolute;inset:0;background:linear-gradient(to top,var(--color-picker-sv-black),transparent)}.ea-color-picker__sv-pointer{position:absolute;z-index:1;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__slider-row{display:flex;align-items:center;gap:var(--space-2)}.ea-color-picker__strip-stack{display:flex;flex-direction:column;flex:1;gap:var(--space-2)}.ea-color-picker__strip{position:relative;width:100%;height:.75rem;border-radius:var(--radius-full);cursor:pointer;touch-action:none}.ea-color-picker__strip:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__strip--hue{background:linear-gradient(to right,var(--color-picker-hue-red) 0%,var(--color-picker-hue-yellow) 17%,var(--color-picker-hue-green) 33%,var(--color-picker-hue-cyan) 50%,var(--color-picker-hue-blue) 67%,var(--color-picker-hue-magenta) 83%,var(--color-picker-hue-red) 100%)}.ea-color-picker__strip--alpha{background-color:var(--color-bg-base);background-image:linear-gradient(to right,transparent 0%,var(--ea-color-picker-alpha-base, currentcolor) 100%),linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:100% 100%,8px 8px,8px 8px,8px 8px,8px 8px;background-position:0 0,0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__strip-thumb{position:absolute;top:50%;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__inputs{display:flex;align-items:end;gap:var(--space-1)}.ea-color-picker__input-group{display:flex;flex:1;flex-direction:column;gap:var(--space-1);min-width:0;text-align:center}.ea-color-picker__input-group--hex{flex:1}.ea-color-picker__format-toggle{flex-shrink:0;min-width:3.25rem;padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);letter-spacing:.04em;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__format-toggle:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__format-toggle:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__input{width:100%;min-width:0;padding:var(--space-1) var(--space-1-5);background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);font-family:var(--font-family-mono);font-size:var(--font-size-xs);text-align:center;color:var(--color-text-primary)}.ea-color-picker__input:focus-visible{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input--num{appearance:textfield}.ea-color-picker__input--num::-webkit-outer-spin-button,.ea-color-picker__input--num::-webkit-inner-spin-button{appearance:none;margin:0}.ea-color-picker__tools{display:flex;justify-content:flex-start}.ea-color-picker__tool-btn{display:inline-flex;align-items:center;gap:var(--space-1-5);padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-xs);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__tool-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__tool-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__tool-btn ea-icon-droplet{width:.875em;height:.875em}.ea-color-picker__presets{display:flex;flex-direction:column;gap:var(--space-1-5);padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-color-picker__presets-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__presets-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:var(--space-1)}.ea-color-picker__preset{width:100%;aspect-ratio:1;padding:0;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);cursor:pointer;transition:transform var(--duration-fast) var(--ease-out)}.ea-color-picker__preset:hover{transform:scale(1.1)}.ea-color-picker__preset:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__preset[aria-selected=true]{box-shadow:0 0 0 2px var(--color-brand-default)}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: DropletIconComponent, selector: "ea-icon-droplet" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PopoverComponent, selector: "ea-popover", inputs: ["anchor", "open", "placement", "role", "aria-label", "surfaceId", "offset", "flip", "clamp", "matchAnchorWidth", "closeOnOutsideClick", "closeOnEscape", "scrollBehavior"], outputs: ["closeRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3446
3892
  }
3447
3893
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ColorPickerComponent, decorators: [{
3448
3894
  type: Component,
3449
- args: [{ selector: 'ea-color-picker', imports: [AlertCircleIconComponent, DropletIconComponent, NgClass], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
3895
+ args: [{ selector: 'ea-color-picker', imports: [AlertCircleIconComponent, DropletIconComponent, NgClass, PopoverComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
3450
3896
  {
3451
3897
  provide: NG_VALUE_ACCESSOR,
3452
3898
  useExisting: forwardRef(() => ColorPickerComponent),
3453
3899
  multi: true,
3454
3900
  },
3455
- ], template: "<div\n #hostEl\n class=\"ea-color-picker-field\">\n @if (label()) {\n <label\n class=\"ea-color-picker-field__label\"\n [for]=\"id()\"\n [class.ea-color-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-color-picker\">\n <div class=\"ea-color-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-color-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <span\n class=\"ea-color-picker__swatch\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"value() ? displayColor() : null\">\n </span>\n </span>\n <span\n class=\"ea-color-picker__trigger-value\"\n [class.ea-color-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-color-picker__clear\"\n [attr.aria-label]=\"i18n.messages().colorPicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n @if (isOpen()) {\n <div\n #popoverEl\n class=\"ea-color-picker__popover\"\n role=\"dialog\"\n [attr.aria-label]=\"label() || i18n.messages().colorPicker.placeholder\"\n [style.top.px]=\"popoverPosition()?.top\"\n [style.left.px]=\"popoverPosition()?.left\"\n (keydown)=\"onPopoverKeydown($event)\">\n <div\n #svAreaEl\n class=\"ea-color-picker__sv-area\"\n role=\"application\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.saturationAndValue\"\n [style.background-color]=\"hueColor()\"\n (pointerdown)=\"onSvPointerDown($event)\"\n (pointermove)=\"onSvPointerMove($event)\"\n (pointerup)=\"onSvPointerUp($event)\"\n (pointercancel)=\"onSvPointerUp($event)\"\n (keydown)=\"onSvKeydown($event)\">\n <div class=\"ea-color-picker__sv-area-sat\"></div>\n <div class=\"ea-color-picker__sv-area-val\"></div>\n <div\n class=\"ea-color-picker__sv-pointer\"\n [style.background-color]=\"opaqueColor()\"\n [style.left]=\"svPointerLeft()\"\n [style.top]=\"svPointerTop()\">\n </div>\n </div>\n\n <div class=\"ea-color-picker__sliders\">\n <div class=\"ea-color-picker__slider-row\">\n <span\n class=\"ea-color-picker__swatch ea-color-picker__swatch--lg\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"displayColor()\">\n </span>\n </span>\n <div class=\"ea-color-picker__strip-stack\">\n <div\n #hueTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--hue\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.hue\"\n [attr.aria-valuemin]=\"0\"\n [attr.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 (keydown)=\"onHueKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"huePointerLeft()\">\n </div>\n </div>\n @if (showAlpha()) {\n <div\n #alphaTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--alpha\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.alpha\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuenow]=\"alphaPointerLeft()\"\n [style.--ea-color-picker-alpha-base]=\"opaqueColor()\"\n (pointerdown)=\"onAlphaPointerDown($event)\"\n (pointermove)=\"onAlphaPointerMove($event)\"\n (pointerup)=\"onAlphaPointerUp($event)\"\n (pointercancel)=\"onAlphaPointerUp($event)\"\n (keydown)=\"onAlphaKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"alphaPointerLeft()\">\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <div\n class=\"ea-color-picker__inputs\"\n [class.ea-color-picker__inputs--hex]=\"inputMode() === 'hex'\">\n @if (inputMode() === 'hex') {\n <label class=\"ea-color-picker__input-group ea-color-picker__input-group--hex\">\n <span class=\"ea-color-picker__input-label\">HEX</span>\n <input\n class=\"ea-color-picker__input\"\n type=\"text\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n maxlength=\"9\"\n [value]=\"hexInputValue()\"\n (input)=\"onHexInput($event)\"\n (blur)=\"onHexBlur()\" />\n </label>\n } @else {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">R</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().r\"\n (input)=\"onRgbInput('r', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">G</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().g\"\n (input)=\"onRgbInput('g', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">B</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().b\"\n (input)=\"onRgbInput('b', $event)\" />\n </label>\n @if (showAlpha()) {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">A</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"alphaPercentRounded()\"\n (input)=\"onAlphaInput($event)\" />\n </label>\n }\n }\n <button\n type=\"button\"\n class=\"ea-color-picker__format-toggle\"\n [attr.aria-label]=\"i18n.messages().colorPicker.toggleFormat\"\n (click)=\"cycleInputMode()\">\n {{ inputMode() === 'hex' ? 'HEX' : 'RGB' }}\n </button>\n </div>\n\n @if (hasEyeDropper()) {\n <div class=\"ea-color-picker__tools\">\n <button\n type=\"button\"\n class=\"ea-color-picker__tool-btn\"\n [attr.aria-label]=\"i18n.messages().colorPicker.eyedropper\"\n (click)=\"pickFromScreen()\">\n <ea-icon-droplet aria-hidden=\"true\" />\n <span>{{ i18n.messages().colorPicker.eyedropper }}</span>\n </button>\n </div>\n }\n\n @if (presets().length > 0) {\n <div class=\"ea-color-picker__presets\">\n <span class=\"ea-color-picker__presets-label\">\n {{ i18n.messages().colorPicker.presets }}\n </span>\n <div\n class=\"ea-color-picker__presets-grid\"\n role=\"listbox\">\n @for (preset of presets(); track preset) {\n <button\n type=\"button\"\n class=\"ea-color-picker__preset\"\n role=\"option\"\n [attr.aria-label]=\"preset\"\n [attr.aria-selected]=\"value() === preset\"\n [style.background-color]=\"preset\"\n (click)=\"selectPreset(preset)\">\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-color-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-color-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-color-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-color-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-color-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-color-picker-field__message--hint{color:var(--color-text-secondary)}.ea-color-picker-field__message--error{color:var(--color-error-default)}.ea-color-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-color-picker,.ea-color-picker__trigger-wrapper{position:relative}.ea-color-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-color-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-color-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-color-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-color-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--error{border-color:var(--color-error-default)}.ea-color-picker__trigger--error.ea-color-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-color-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-color-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-family-mono);font-size:.85em}.ea-color-picker__trigger-value--placeholder{color:var(--color-text-tertiary);font-family:var(--font-family-sans);font-size:1em}.ea-color-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-color-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__swatch{position:relative;overflow:hidden;flex-shrink:0;width:1.125rem;height:1.125rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);background-image:linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__swatch--lg{width:2.5rem;height:2.5rem;border-radius:var(--radius-md)}.ea-color-picker__swatch-fill{position:absolute;inset:0;display:block}.ea-color-picker__popover{position:fixed;z-index:var(--z-index-popover);display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-3);width:17.5rem;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg)}.ea-color-picker__sv-area{position:relative;overflow:hidden;width:100%;height:10rem;border-radius:var(--radius-sm);cursor:crosshair;touch-action:none}.ea-color-picker__sv-area:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__sv-area-sat{position:absolute;inset:0;background:linear-gradient(to right,var(--color-picker-sv-white),transparent)}.ea-color-picker__sv-area-val{position:absolute;inset:0;background:linear-gradient(to top,var(--color-picker-sv-black),transparent)}.ea-color-picker__sv-pointer{position:absolute;z-index:1;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__slider-row{display:flex;align-items:center;gap:var(--space-2)}.ea-color-picker__strip-stack{display:flex;flex-direction:column;flex:1;gap:var(--space-2)}.ea-color-picker__strip{position:relative;width:100%;height:.75rem;border-radius:var(--radius-full);cursor:pointer;touch-action:none}.ea-color-picker__strip:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__strip--hue{background:linear-gradient(to right,var(--color-picker-hue-red) 0%,var(--color-picker-hue-yellow) 17%,var(--color-picker-hue-green) 33%,var(--color-picker-hue-cyan) 50%,var(--color-picker-hue-blue) 67%,var(--color-picker-hue-magenta) 83%,var(--color-picker-hue-red) 100%)}.ea-color-picker__strip--alpha{background-color:var(--color-bg-base);background-image:linear-gradient(to right,transparent 0%,var(--ea-color-picker-alpha-base, currentcolor) 100%),linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:100% 100%,8px 8px,8px 8px,8px 8px,8px 8px;background-position:0 0,0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__strip-thumb{position:absolute;top:50%;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__inputs{display:flex;align-items:end;gap:var(--space-1)}.ea-color-picker__input-group{display:flex;flex:1;flex-direction:column;gap:var(--space-1);min-width:0;text-align:center}.ea-color-picker__input-group--hex{flex:1}.ea-color-picker__format-toggle{flex-shrink:0;min-width:3.25rem;padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);letter-spacing:.04em;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__format-toggle:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__format-toggle:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__input{width:100%;min-width:0;padding:var(--space-1) var(--space-1-5);background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);font-family:var(--font-family-mono);font-size:var(--font-size-xs);text-align:center;color:var(--color-text-primary)}.ea-color-picker__input:focus-visible{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input--num{appearance:textfield}.ea-color-picker__input--num::-webkit-outer-spin-button,.ea-color-picker__input--num::-webkit-inner-spin-button{appearance:none;margin:0}.ea-color-picker__tools{display:flex;justify-content:flex-start}.ea-color-picker__tool-btn{display:inline-flex;align-items:center;gap:var(--space-1-5);padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-xs);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__tool-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__tool-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__tool-btn ea-icon-droplet{width:.875em;height:.875em}.ea-color-picker__presets{display:flex;flex-direction:column;gap:var(--space-1-5);padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-color-picker__presets-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__presets-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:var(--space-1)}.ea-color-picker__preset{width:100%;aspect-ratio:1;padding:0;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);cursor:pointer;transition:transform var(--duration-fast) var(--ease-out)}.ea-color-picker__preset:hover{transform:scale(1.1)}.ea-color-picker__preset:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__preset[aria-selected=true]{box-shadow:0 0 0 2px var(--color-brand-default)}\n"] }]
3456
- }], ctorParameters: () => [], propDecorators: { hostEl: [{ type: i0.ViewChild, args: ['hostEl', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], popoverEl: [{ type: i0.ViewChild, args: ['popoverEl', { isSignal: true }] }], svAreaEl: [{ type: i0.ViewChild, args: ['svAreaEl', { isSignal: true }] }], hueTrackEl: [{ type: i0.ViewChild, args: ['hueTrackEl', { isSignal: true }] }], alphaTrackEl: [{ type: i0.ViewChild, args: ['alphaTrackEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }], onDocumentClick: [{
3457
- type: HostListener,
3458
- args: ['document:click', ['$event']]
3459
- }] } });
3901
+ ], template: "<div class=\"ea-color-picker-field\">\n @if (label()) {\n <label\n class=\"ea-color-picker-field__label\"\n [for]=\"id()\"\n [class.ea-color-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-color-picker\">\n <div class=\"ea-color-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-color-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"onTriggerKeydown($event)\">\n <span\n class=\"ea-color-picker__swatch\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"value() ? displayColor() : null\">\n </span>\n </span>\n <span\n class=\"ea-color-picker__trigger-value\"\n [class.ea-color-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-color-picker__clear\"\n [attr.aria-label]=\"i18n.messages().colorPicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"dialog\"\n [ariaLabel]=\"label() || i18n.messages().colorPicker.placeholder\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div\n class=\"ea-color-picker__popover\"\n (keydown)=\"onPopoverKeydown($event)\">\n <div\n #svAreaEl\n class=\"ea-color-picker__sv-area\"\n role=\"application\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.saturationAndValue\"\n [style.background-color]=\"hueColor()\"\n (pointerdown)=\"onSvPointerDown($event)\"\n (pointermove)=\"onSvPointerMove($event)\"\n (pointerup)=\"onSvPointerUp($event)\"\n (pointercancel)=\"onSvPointerUp($event)\"\n (keydown)=\"onSvKeydown($event)\">\n <div class=\"ea-color-picker__sv-area-sat\"></div>\n <div class=\"ea-color-picker__sv-area-val\"></div>\n <div\n class=\"ea-color-picker__sv-pointer\"\n [style.background-color]=\"opaqueColor()\"\n [style.left]=\"svPointerLeft()\"\n [style.top]=\"svPointerTop()\">\n </div>\n </div>\n\n <div class=\"ea-color-picker__sliders\">\n <div class=\"ea-color-picker__slider-row\">\n <span\n class=\"ea-color-picker__swatch ea-color-picker__swatch--lg\"\n aria-hidden=\"true\">\n <span\n class=\"ea-color-picker__swatch-fill\"\n [style.background-color]=\"displayColor()\">\n </span>\n </span>\n <div class=\"ea-color-picker__strip-stack\">\n <div\n #hueTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--hue\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.hue\"\n [attr.aria-valuemin]=\"0\"\n [attr.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 (keydown)=\"onHueKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"huePointerLeft()\">\n </div>\n </div>\n @if (showAlpha()) {\n <div\n #alphaTrackEl\n class=\"ea-color-picker__strip ea-color-picker__strip--alpha\"\n role=\"slider\"\n tabindex=\"0\"\n [attr.aria-label]=\"i18n.messages().colorPicker.alpha\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-valuenow]=\"alphaPointerLeft()\"\n [style.--ea-color-picker-alpha-base]=\"opaqueColor()\"\n (pointerdown)=\"onAlphaPointerDown($event)\"\n (pointermove)=\"onAlphaPointerMove($event)\"\n (pointerup)=\"onAlphaPointerUp($event)\"\n (pointercancel)=\"onAlphaPointerUp($event)\"\n (keydown)=\"onAlphaKeydown($event)\">\n <div\n class=\"ea-color-picker__strip-thumb\"\n [style.left]=\"alphaPointerLeft()\">\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n\n <div\n class=\"ea-color-picker__inputs\"\n [class.ea-color-picker__inputs--hex]=\"inputMode() === 'hex'\">\n @if (inputMode() === 'hex') {\n <label class=\"ea-color-picker__input-group ea-color-picker__input-group--hex\">\n <span class=\"ea-color-picker__input-label\">HEX</span>\n <input\n class=\"ea-color-picker__input\"\n type=\"text\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n maxlength=\"9\"\n [value]=\"hexInputValue()\"\n (input)=\"onHexInput($event)\"\n (blur)=\"onHexBlur()\" />\n </label>\n } @else {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">R</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().r\"\n (input)=\"onRgbInput('r', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">G</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().g\"\n (input)=\"onRgbInput('g', $event)\" />\n </label>\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">B</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"rgb().b\"\n (input)=\"onRgbInput('b', $event)\" />\n </label>\n @if (showAlpha()) {\n <label class=\"ea-color-picker__input-group\">\n <span class=\"ea-color-picker__input-label\">A</span>\n <input\n class=\"ea-color-picker__input ea-color-picker__input--num\"\n type=\"text\"\n inputmode=\"numeric\"\n pattern=\"\\d*\"\n maxlength=\"3\"\n [value]=\"alphaPercentRounded()\"\n (input)=\"onAlphaInput($event)\" />\n </label>\n }\n }\n <button\n type=\"button\"\n class=\"ea-color-picker__format-toggle\"\n [attr.aria-label]=\"i18n.messages().colorPicker.toggleFormat\"\n (click)=\"cycleInputMode()\">\n {{ inputMode() === 'hex' ? 'HEX' : 'RGB' }}\n </button>\n </div>\n\n @if (hasEyeDropper()) {\n <div class=\"ea-color-picker__tools\">\n <button\n type=\"button\"\n class=\"ea-color-picker__tool-btn\"\n [attr.aria-label]=\"i18n.messages().colorPicker.eyedropper\"\n (click)=\"pickFromScreen()\">\n <ea-icon-droplet aria-hidden=\"true\" />\n <span>{{ i18n.messages().colorPicker.eyedropper }}</span>\n </button>\n </div>\n }\n\n @if (presets().length > 0) {\n <div class=\"ea-color-picker__presets\">\n <span class=\"ea-color-picker__presets-label\">\n {{ i18n.messages().colorPicker.presets }}\n </span>\n <div\n class=\"ea-color-picker__presets-grid\"\n role=\"listbox\">\n @for (preset of presets(); track preset) {\n <button\n type=\"button\"\n class=\"ea-color-picker__preset\"\n role=\"option\"\n [attr.aria-label]=\"preset\"\n [attr.aria-selected]=\"value() === preset\"\n [style.background-color]=\"preset\"\n (click)=\"selectPreset(preset)\">\n </button>\n }\n </div>\n </div>\n }\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-color-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-color-picker-field__message ea-color-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-color-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-color-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-color-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-color-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-color-picker-field__message--hint{color:var(--color-text-secondary)}.ea-color-picker-field__message--error{color:var(--color-error-default)}.ea-color-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-color-picker,.ea-color-picker__trigger-wrapper{position:relative}.ea-color-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-color-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-color-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-color-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-color-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__trigger--error{border-color:var(--color-error-default)}.ea-color-picker__trigger--error.ea-color-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-color-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-color-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-family-mono);font-size:.85em}.ea-color-picker__trigger-value--placeholder{color:var(--color-text-tertiary);font-family:var(--font-family-sans);font-size:1em}.ea-color-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-color-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__swatch{position:relative;overflow:hidden;flex-shrink:0;width:1.125rem;height:1.125rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);background-image:linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__swatch--lg{width:2.5rem;height:2.5rem;border-radius:var(--radius-md)}.ea-color-picker__swatch-fill{position:absolute;inset:0;display:block}.ea-color-picker__popover{display:flex;flex-direction:column;gap:var(--space-3);width:17.5rem;padding:var(--space-3);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-color-picker__sv-area{position:relative;overflow:hidden;width:100%;height:10rem;border-radius:var(--radius-sm);cursor:crosshair;touch-action:none}.ea-color-picker__sv-area:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__sv-area-sat{position:absolute;inset:0;background:linear-gradient(to right,var(--color-picker-sv-white),transparent)}.ea-color-picker__sv-area-val{position:absolute;inset:0;background:linear-gradient(to top,var(--color-picker-sv-black),transparent)}.ea-color-picker__sv-pointer{position:absolute;z-index:1;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__slider-row{display:flex;align-items:center;gap:var(--space-2)}.ea-color-picker__strip-stack{display:flex;flex-direction:column;flex:1;gap:var(--space-2)}.ea-color-picker__strip{position:relative;width:100%;height:.75rem;border-radius:var(--radius-full);cursor:pointer;touch-action:none}.ea-color-picker__strip:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__strip--hue{background:linear-gradient(to right,var(--color-picker-hue-red) 0%,var(--color-picker-hue-yellow) 17%,var(--color-picker-hue-green) 33%,var(--color-picker-hue-cyan) 50%,var(--color-picker-hue-blue) 67%,var(--color-picker-hue-magenta) 83%,var(--color-picker-hue-red) 100%)}.ea-color-picker__strip--alpha{background-color:var(--color-bg-base);background-image:linear-gradient(to right,transparent 0%,var(--ea-color-picker-alpha-base, currentcolor) 100%),linear-gradient(45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(-45deg,var(--color-neutral-200) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,var(--color-neutral-200) 75%),linear-gradient(-45deg,transparent 75%,var(--color-neutral-200) 75%);background-size:100% 100%,8px 8px,8px 8px,8px 8px,8px 8px;background-position:0 0,0 0,0 4px,4px -4px,-4px 0}.ea-color-picker__strip-thumb{position:absolute;top:50%;width:.875rem;height:.875rem;border:2px solid var(--color-neutral-0);border-radius:var(--radius-full);box-shadow:0 0 0 1px var(--color-picker-thumb-halo);pointer-events:none;transform:translate(-50%,-50%)}.ea-color-picker__inputs{display:flex;align-items:end;gap:var(--space-1)}.ea-color-picker__input-group{display:flex;flex:1;flex-direction:column;gap:var(--space-1);min-width:0;text-align:center}.ea-color-picker__input-group--hex{flex:1}.ea-color-picker__format-toggle{flex-shrink:0;min-width:3.25rem;padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);letter-spacing:.04em;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__format-toggle:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__format-toggle:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__input{width:100%;min-width:0;padding:var(--space-1) var(--space-1-5);background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);font-family:var(--font-family-mono);font-size:var(--font-size-xs);text-align:center;color:var(--color-text-primary)}.ea-color-picker__input:focus-visible{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-color-picker__input--num{appearance:textfield}.ea-color-picker__input--num::-webkit-outer-spin-button,.ea-color-picker__input--num::-webkit-inner-spin-button{appearance:none;margin:0}.ea-color-picker__tools{display:flex;justify-content:flex-start}.ea-color-picker__tool-btn{display:inline-flex;align-items:center;gap:var(--space-1-5);padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-xs);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-color-picker__tool-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-color-picker__tool-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__tool-btn ea-icon-droplet{width:.875em;height:.875em}.ea-color-picker__presets{display:flex;flex-direction:column;gap:var(--space-1-5);padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-color-picker__presets-label{font-size:var(--font-size-2xs);font-weight:var(--font-weight-medium);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-tertiary)}.ea-color-picker__presets-grid{display:grid;grid-template-columns:repeat(10,1fr);gap:var(--space-1)}.ea-color-picker__preset{width:100%;aspect-ratio:1;padding:0;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);cursor:pointer;transition:transform var(--duration-fast) var(--ease-out)}.ea-color-picker__preset:hover{transform:scale(1.1)}.ea-color-picker__preset:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-color-picker__preset[aria-selected=true]{box-shadow:0 0 0 2px var(--color-brand-default)}\n"] }]
3902
+ }], propDecorators: { triggerEl: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], svAreaEl: [{ type: i0.ViewChild, args: ['svAreaEl', { isSignal: true }] }], hueTrackEl: [{ type: i0.ViewChild, args: ['hueTrackEl', { isSignal: true }] }], alphaTrackEl: [{ type: i0.ViewChild, args: ['alphaTrackEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
3460
3903
  // ─── Pure color helpers (module-private) ──────────────────────────────────
3461
3904
  function clamp01(n) {
3462
3905
  return Math.min(1, Math.max(0, n));
@@ -4268,7 +4711,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
4268
4711
  * Escape). Integrates with Angular forms via `ControlValueAccessor`.
4269
4712
  */
4270
4713
  class DatePickerComponent {
4271
- hostEl = viewChild('hostEl', ...(ngDevMode ? [{ debugName: "hostEl" }] : /* istanbul ignore next */ []));
4272
4714
  triggerEl = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
4273
4715
  injector = inject(Injector);
4274
4716
  i18n = inject(EagamiI18nService);
@@ -4426,8 +4868,12 @@ class DatePickerComponent {
4426
4868
  this.focusedDate.set(null);
4427
4869
  }
4428
4870
  focusFocusedDayCell() {
4429
- const host = this.hostEl()?.nativeElement;
4430
- const focusedCell = host?.querySelector('.ea-date-picker__day--focused');
4871
+ // The calendar lives inside the popover surface, which `<ea-popover>`
4872
+ // teleports to `document.body`. Query the document directly so the lookup
4873
+ // works regardless of where the surface is mounted.
4874
+ if (typeof document === 'undefined')
4875
+ return;
4876
+ const focusedCell = document.querySelector('.ea-date-picker__day--focused');
4431
4877
  focusedCell?.focus();
4432
4878
  }
4433
4879
  /** Moves keyboard focus to the trigger button. */
@@ -4572,14 +5018,10 @@ class DatePickerComponent {
4572
5018
  this.viewMonth.set(next.getMonth());
4573
5019
  }
4574
5020
  }
4575
- onDocumentClick(event) {
4576
- if (!this.isOpen())
4577
- return;
4578
- const host = this.hostEl()?.nativeElement;
4579
- if (host && !host.contains(event.target)) {
4580
- this.close();
4581
- this.onTouched();
4582
- }
5021
+ /** Called by `<ea-popover>` when the user clicks outside the picker. */
5022
+ onPopoverCloseRequested() {
5023
+ this.close();
5024
+ this.onTouched();
4583
5025
  }
4584
5026
  // Internal helpers
4585
5027
  formatOptions() {
@@ -4620,13 +5062,13 @@ class DatePickerComponent {
4620
5062
  return result;
4621
5063
  }
4622
5064
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DatePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4623
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: DatePickerComponent, isStandalone: true, selector: "ea-date-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, weekStartsOn: { classPropertyName: "weekStartsOn", publicName: "weekStartsOn", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
5065
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: DatePickerComponent, isStandalone: true, selector: "ea-date-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, weekStartsOn: { classPropertyName: "weekStartsOn", publicName: "weekStartsOn", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, providers: [
4624
5066
  {
4625
5067
  provide: NG_VALUE_ACCESSOR,
4626
5068
  useExisting: forwardRef(() => DatePickerComponent),
4627
5069
  multi: true,
4628
5070
  },
4629
- ], viewQueries: [{ propertyName: "hostEl", first: true, predicate: ["hostEl"], descendants: true, isSignal: true }, { propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #hostEl\n class=\"ea-date-picker-field\">\n @if (label()) {\n <label\n class=\"ea-date-picker-field__label\"\n [for]=\"id()\"\n [class.ea-date-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-date-picker\">\n <div class=\"ea-date-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-date-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <ea-icon-calendar\n class=\"ea-date-picker__trigger-icon\"\n aria-hidden=\"true\" />\n <span\n class=\"ea-date-picker__trigger-value\"\n [class.ea-date-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__clear\"\n [attr.aria-label]=\"i18n.messages().datePicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n @if (isOpen()) {\n <div\n class=\"ea-date-picker__popover\"\n role=\"dialog\"\n [attr.aria-labelledby]=\"id() + '-label'\"\n (keydown)=\"handleGridKeydown($event)\">\n <div class=\"ea-date-picker__header\">\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousYear\"\n (click)=\"goToPrevYear()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousMonth\"\n (click)=\"goToPrevMonth()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <span\n class=\"ea-date-picker__month-label\"\n [id]=\"id() + '-label'\"\n aria-live=\"polite\">\n {{ monthYearLabel() }}\n </span>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextMonth\"\n (click)=\"goToNextMonth()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextYear\"\n (click)=\"goToNextYear()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n </div>\n\n <div\n class=\"ea-date-picker__grid\"\n role=\"grid\">\n <div\n class=\"ea-date-picker__weekday-row\"\n role=\"row\">\n @for (label of weekdayLabels(); track label) {\n <div\n class=\"ea-date-picker__weekday\"\n role=\"columnheader\">\n {{ label }}\n </div>\n }\n </div>\n @for (week of weeks(); track $index) {\n <div\n class=\"ea-date-picker__week\"\n role=\"row\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__day\"\n role=\"gridcell\"\n [class.ea-date-picker__day--outside]=\"!day.isCurrentMonth\"\n [class.ea-date-picker__day--today]=\"day.isToday\"\n [class.ea-date-picker__day--selected]=\"day.isSelected\"\n [class.ea-date-picker__day--focused]=\"day.isFocused\"\n [class.ea-date-picker__day--disabled]=\"day.isDisabled\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDay(day)\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"ea-date-picker__footer\">\n <button\n type=\"button\"\n class=\"ea-date-picker__today-btn\"\n (click)=\"goToToday()\">\n {{ i18n.messages().datePicker.today }}\n </button>\n </div>\n </div>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-date-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-date-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-date-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-date-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-date-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-date-picker-field__message--hint{color:var(--color-text-secondary)}.ea-date-picker-field__message--error{color:var(--color-error-default)}.ea-date-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-date-picker,.ea-date-picker__trigger-wrapper{position:relative}.ea-date-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-date-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-date-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-date-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-date-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--error{border-color:var(--color-error-default)}.ea-date-picker__trigger--error.ea-date-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-date-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-date-picker__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary)}.ea-date-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-date-picker__trigger-value--placeholder{color:var(--color-text-tertiary)}.ea-date-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-date-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__popover{position:absolute;top:calc(100% + var(--space-1));left:0;z-index:var(--z-index-dropdown);display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-3);min-width:17.5rem;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg)}.ea-date-picker__header{display:flex;align-items:center;gap:var(--space-1)}.ea-date-picker__nav-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__nav-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__nav-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__nav-btn ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right{width:.875em;height:.875em}.ea-date-picker__nav-btn ea-icon-chevron-left+ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right+ea-icon-chevron-right{margin-left:-.375em}.ea-date-picker__month-label{flex:1;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);text-align:center;color:var(--color-text-primary)}.ea-date-picker__grid{display:flex;flex-direction:column;gap:var(--space-1)}.ea-date-picker__weekday-row,.ea-date-picker__week{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--space-1)}.ea-date-picker__weekday{display:flex;align-items:center;justify-content:center;height:1.5rem;font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);text-transform:uppercase;color:var(--color-text-tertiary)}.ea-date-picker__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__day:hover:not(:disabled){background-color:var(--color-bg-muted)}.ea-date-picker__day:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__day--outside{color:var(--color-text-tertiary)}.ea-date-picker__day--today{font-weight:var(--font-weight-semibold);color:var(--color-brand-default)}.ea-date-picker__day--focused:not(.ea-date-picker__day--selected){background-color:var(--color-bg-muted)}.ea-date-picker__day--selected{background-color:var(--color-brand-default);color:var(--color-text-inverse);font-weight:var(--font-weight-medium)}.ea-date-picker__day--selected:hover{background-color:var(--color-brand-hover)}.ea-date-picker__day--disabled{color:var(--color-text-disabled);cursor:not-allowed}.ea-date-picker__day--disabled:hover{background-color:transparent}.ea-date-picker__footer{display:flex;justify-content:flex-end;padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-date-picker__today-btn{padding:var(--space-1) var(--space-2);border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-brand-default);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__today-btn:hover{background-color:var(--color-brand-subtle)}.ea-date-picker__today-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: CalendarIconComponent, selector: "ea-icon-calendar" }, { kind: "component", type: ChevronLeftIconComponent, selector: "ea-icon-chevron-left" }, { kind: "component", type: ChevronRightIconComponent, selector: "ea-icon-chevron-right" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5071
+ ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-date-picker-field\">\n @if (label()) {\n <label\n class=\"ea-date-picker-field__label\"\n [for]=\"id()\"\n [class.ea-date-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-date-picker\">\n <div class=\"ea-date-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-date-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <ea-icon-calendar\n class=\"ea-date-picker__trigger-icon\"\n aria-hidden=\"true\" />\n <span\n class=\"ea-date-picker__trigger-value\"\n [class.ea-date-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__clear\"\n [attr.aria-label]=\"i18n.messages().datePicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"dialog\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div\n class=\"ea-date-picker__popover\"\n [attr.aria-labelledby]=\"id() + '-label'\"\n (keydown)=\"handleGridKeydown($event)\">\n <div class=\"ea-date-picker__header\">\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousYear\"\n (click)=\"goToPrevYear()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousMonth\"\n (click)=\"goToPrevMonth()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <span\n class=\"ea-date-picker__month-label\"\n [id]=\"id() + '-label'\"\n aria-live=\"polite\">\n {{ monthYearLabel() }}\n </span>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextMonth\"\n (click)=\"goToNextMonth()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextYear\"\n (click)=\"goToNextYear()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n </div>\n\n <div\n class=\"ea-date-picker__grid\"\n role=\"grid\">\n <div\n class=\"ea-date-picker__weekday-row\"\n role=\"row\">\n @for (label of weekdayLabels(); track label) {\n <div\n class=\"ea-date-picker__weekday\"\n role=\"columnheader\">\n {{ label }}\n </div>\n }\n </div>\n @for (week of weeks(); track $index) {\n <div\n class=\"ea-date-picker__week\"\n role=\"row\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__day\"\n role=\"gridcell\"\n [class.ea-date-picker__day--outside]=\"!day.isCurrentMonth\"\n [class.ea-date-picker__day--today]=\"day.isToday\"\n [class.ea-date-picker__day--selected]=\"day.isSelected\"\n [class.ea-date-picker__day--focused]=\"day.isFocused\"\n [class.ea-date-picker__day--disabled]=\"day.isDisabled\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDay(day)\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"ea-date-picker__footer\">\n <button\n type=\"button\"\n class=\"ea-date-picker__today-btn\"\n (click)=\"goToToday()\">\n {{ i18n.messages().datePicker.today }}\n </button>\n </div>\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-date-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-date-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-date-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-date-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-date-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-date-picker-field__message--hint{color:var(--color-text-secondary)}.ea-date-picker-field__message--error{color:var(--color-error-default)}.ea-date-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-date-picker,.ea-date-picker__trigger-wrapper{position:relative}.ea-date-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-date-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-date-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-date-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-date-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--error{border-color:var(--color-error-default)}.ea-date-picker__trigger--error.ea-date-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-date-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-date-picker__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary)}.ea-date-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-date-picker__trigger-value--placeholder{color:var(--color-text-tertiary)}.ea-date-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-date-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__popover{display:flex;flex-direction:column;gap:var(--space-2);min-width:17.5rem;padding:var(--space-3);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-date-picker__header{display:flex;align-items:center;gap:var(--space-1)}.ea-date-picker__nav-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__nav-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__nav-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__nav-btn ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right{width:.875em;height:.875em}.ea-date-picker__nav-btn ea-icon-chevron-left+ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right+ea-icon-chevron-right{margin-left:-.375em}.ea-date-picker__month-label{flex:1;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);text-align:center;color:var(--color-text-primary)}.ea-date-picker__grid{display:flex;flex-direction:column;gap:var(--space-1)}.ea-date-picker__weekday-row,.ea-date-picker__week{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--space-1)}.ea-date-picker__weekday{display:flex;align-items:center;justify-content:center;height:1.5rem;font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);text-transform:uppercase;color:var(--color-text-tertiary)}.ea-date-picker__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__day:hover:not(:disabled){background-color:var(--color-bg-muted)}.ea-date-picker__day:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__day--outside{color:var(--color-text-tertiary)}.ea-date-picker__day--today{font-weight:var(--font-weight-semibold);color:var(--color-brand-default)}.ea-date-picker__day--focused:not(.ea-date-picker__day--selected){background-color:var(--color-bg-muted)}.ea-date-picker__day--selected{background-color:var(--color-brand-default);color:var(--color-text-inverse);font-weight:var(--font-weight-medium)}.ea-date-picker__day--selected:hover{background-color:var(--color-brand-hover)}.ea-date-picker__day--disabled{color:var(--color-text-disabled);cursor:not-allowed}.ea-date-picker__day--disabled:hover{background-color:transparent}.ea-date-picker__footer{display:flex;justify-content:flex-end;padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-date-picker__today-btn{padding:var(--space-1) var(--space-2);border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-brand-default);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__today-btn:hover{background-color:var(--color-brand-subtle)}.ea-date-picker__today-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: CalendarIconComponent, selector: "ea-icon-calendar" }, { kind: "component", type: ChevronLeftIconComponent, selector: "ea-icon-chevron-left" }, { kind: "component", type: ChevronRightIconComponent, selector: "ea-icon-chevron-right" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PopoverComponent, selector: "ea-popover", inputs: ["anchor", "open", "placement", "role", "aria-label", "surfaceId", "offset", "flip", "clamp", "matchAnchorWidth", "closeOnOutsideClick", "closeOnEscape", "scrollBehavior"], outputs: ["closeRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4630
5072
  }
4631
5073
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DatePickerComponent, decorators: [{
4632
5074
  type: Component,
@@ -4636,17 +5078,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
4636
5078
  ChevronLeftIconComponent,
4637
5079
  ChevronRightIconComponent,
4638
5080
  NgClass,
5081
+ PopoverComponent,
4639
5082
  ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
4640
5083
  {
4641
5084
  provide: NG_VALUE_ACCESSOR,
4642
5085
  useExisting: forwardRef(() => DatePickerComponent),
4643
5086
  multi: true,
4644
5087
  },
4645
- ], template: "<div\n #hostEl\n class=\"ea-date-picker-field\">\n @if (label()) {\n <label\n class=\"ea-date-picker-field__label\"\n [for]=\"id()\"\n [class.ea-date-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-date-picker\">\n <div class=\"ea-date-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-date-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <ea-icon-calendar\n class=\"ea-date-picker__trigger-icon\"\n aria-hidden=\"true\" />\n <span\n class=\"ea-date-picker__trigger-value\"\n [class.ea-date-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__clear\"\n [attr.aria-label]=\"i18n.messages().datePicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n @if (isOpen()) {\n <div\n class=\"ea-date-picker__popover\"\n role=\"dialog\"\n [attr.aria-labelledby]=\"id() + '-label'\"\n (keydown)=\"handleGridKeydown($event)\">\n <div class=\"ea-date-picker__header\">\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousYear\"\n (click)=\"goToPrevYear()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousMonth\"\n (click)=\"goToPrevMonth()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <span\n class=\"ea-date-picker__month-label\"\n [id]=\"id() + '-label'\"\n aria-live=\"polite\">\n {{ monthYearLabel() }}\n </span>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextMonth\"\n (click)=\"goToNextMonth()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextYear\"\n (click)=\"goToNextYear()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n </div>\n\n <div\n class=\"ea-date-picker__grid\"\n role=\"grid\">\n <div\n class=\"ea-date-picker__weekday-row\"\n role=\"row\">\n @for (label of weekdayLabels(); track label) {\n <div\n class=\"ea-date-picker__weekday\"\n role=\"columnheader\">\n {{ label }}\n </div>\n }\n </div>\n @for (week of weeks(); track $index) {\n <div\n class=\"ea-date-picker__week\"\n role=\"row\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__day\"\n role=\"gridcell\"\n [class.ea-date-picker__day--outside]=\"!day.isCurrentMonth\"\n [class.ea-date-picker__day--today]=\"day.isToday\"\n [class.ea-date-picker__day--selected]=\"day.isSelected\"\n [class.ea-date-picker__day--focused]=\"day.isFocused\"\n [class.ea-date-picker__day--disabled]=\"day.isDisabled\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDay(day)\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"ea-date-picker__footer\">\n <button\n type=\"button\"\n class=\"ea-date-picker__today-btn\"\n (click)=\"goToToday()\">\n {{ i18n.messages().datePicker.today }}\n </button>\n </div>\n </div>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-date-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-date-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-date-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-date-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-date-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-date-picker-field__message--hint{color:var(--color-text-secondary)}.ea-date-picker-field__message--error{color:var(--color-error-default)}.ea-date-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-date-picker,.ea-date-picker__trigger-wrapper{position:relative}.ea-date-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-date-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-date-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-date-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-date-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--error{border-color:var(--color-error-default)}.ea-date-picker__trigger--error.ea-date-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-date-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-date-picker__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary)}.ea-date-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-date-picker__trigger-value--placeholder{color:var(--color-text-tertiary)}.ea-date-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-date-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__popover{position:absolute;top:calc(100% + var(--space-1));left:0;z-index:var(--z-index-dropdown);display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-3);min-width:17.5rem;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg)}.ea-date-picker__header{display:flex;align-items:center;gap:var(--space-1)}.ea-date-picker__nav-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__nav-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__nav-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__nav-btn ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right{width:.875em;height:.875em}.ea-date-picker__nav-btn ea-icon-chevron-left+ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right+ea-icon-chevron-right{margin-left:-.375em}.ea-date-picker__month-label{flex:1;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);text-align:center;color:var(--color-text-primary)}.ea-date-picker__grid{display:flex;flex-direction:column;gap:var(--space-1)}.ea-date-picker__weekday-row,.ea-date-picker__week{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--space-1)}.ea-date-picker__weekday{display:flex;align-items:center;justify-content:center;height:1.5rem;font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);text-transform:uppercase;color:var(--color-text-tertiary)}.ea-date-picker__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__day:hover:not(:disabled){background-color:var(--color-bg-muted)}.ea-date-picker__day:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__day--outside{color:var(--color-text-tertiary)}.ea-date-picker__day--today{font-weight:var(--font-weight-semibold);color:var(--color-brand-default)}.ea-date-picker__day--focused:not(.ea-date-picker__day--selected){background-color:var(--color-bg-muted)}.ea-date-picker__day--selected{background-color:var(--color-brand-default);color:var(--color-text-inverse);font-weight:var(--font-weight-medium)}.ea-date-picker__day--selected:hover{background-color:var(--color-brand-hover)}.ea-date-picker__day--disabled{color:var(--color-text-disabled);cursor:not-allowed}.ea-date-picker__day--disabled:hover{background-color:transparent}.ea-date-picker__footer{display:flex;justify-content:flex-end;padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-date-picker__today-btn{padding:var(--space-1) var(--space-2);border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-brand-default);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__today-btn:hover{background-color:var(--color-brand-subtle)}.ea-date-picker__today-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}\n"] }]
4646
- }], propDecorators: { hostEl: [{ type: i0.ViewChild, args: ['hostEl', { isSignal: true }] }], triggerEl: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], weekStartsOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStartsOn", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }], onDocumentClick: [{
4647
- type: HostListener,
4648
- args: ['document:click', ['$event']]
4649
- }] } });
5088
+ ], template: "<div class=\"ea-date-picker-field\">\n @if (label()) {\n <label\n class=\"ea-date-picker-field__label\"\n [for]=\"id()\"\n [class.ea-date-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-date-picker\">\n <div class=\"ea-date-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-date-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <ea-icon-calendar\n class=\"ea-date-picker__trigger-icon\"\n aria-hidden=\"true\" />\n <span\n class=\"ea-date-picker__trigger-value\"\n [class.ea-date-picker__trigger-value--placeholder]=\"!displayValue()\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (value() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__clear\"\n [attr.aria-label]=\"i18n.messages().datePicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"dialog\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div\n class=\"ea-date-picker__popover\"\n [attr.aria-labelledby]=\"id() + '-label'\"\n (keydown)=\"handleGridKeydown($event)\">\n <div class=\"ea-date-picker__header\">\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousYear\"\n (click)=\"goToPrevYear()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.previousMonth\"\n (click)=\"goToPrevMonth()\">\n <ea-icon-chevron-left aria-hidden=\"true\" />\n </button>\n <span\n class=\"ea-date-picker__month-label\"\n [id]=\"id() + '-label'\"\n aria-live=\"polite\">\n {{ monthYearLabel() }}\n </span>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextMonth\"\n (click)=\"goToNextMonth()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n class=\"ea-date-picker__nav-btn\"\n [attr.aria-label]=\"i18n.messages().datePicker.nextYear\"\n (click)=\"goToNextYear()\">\n <ea-icon-chevron-right aria-hidden=\"true\" />\n <ea-icon-chevron-right aria-hidden=\"true\" />\n </button>\n </div>\n\n <div\n class=\"ea-date-picker__grid\"\n role=\"grid\">\n <div\n class=\"ea-date-picker__weekday-row\"\n role=\"row\">\n @for (label of weekdayLabels(); track label) {\n <div\n class=\"ea-date-picker__weekday\"\n role=\"columnheader\">\n {{ label }}\n </div>\n }\n </div>\n @for (week of weeks(); track $index) {\n <div\n class=\"ea-date-picker__week\"\n role=\"row\">\n @for (day of week; track day.date.getTime()) {\n <button\n type=\"button\"\n class=\"ea-date-picker__day\"\n role=\"gridcell\"\n [class.ea-date-picker__day--outside]=\"!day.isCurrentMonth\"\n [class.ea-date-picker__day--today]=\"day.isToday\"\n [class.ea-date-picker__day--selected]=\"day.isSelected\"\n [class.ea-date-picker__day--focused]=\"day.isFocused\"\n [class.ea-date-picker__day--disabled]=\"day.isDisabled\"\n [disabled]=\"day.isDisabled\"\n [attr.aria-selected]=\"day.isSelected\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n [attr.tabindex]=\"day.isFocused ? 0 : -1\"\n (click)=\"selectDay(day)\">\n {{ day.day }}\n </button>\n }\n </div>\n }\n </div>\n\n <div class=\"ea-date-picker__footer\">\n <button\n type=\"button\"\n class=\"ea-date-picker__today-btn\"\n (click)=\"goToToday()\">\n {{ i18n.messages().datePicker.today }}\n </button>\n </div>\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-date-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-date-picker-field__message ea-date-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-date-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-date-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-date-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-date-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-date-picker-field__message--hint{color:var(--color-text-secondary)}.ea-date-picker-field__message--error{color:var(--color-error-default)}.ea-date-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-date-picker,.ea-date-picker__trigger-wrapper{position:relative}.ea-date-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-date-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-date-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-date-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-date-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-date-picker__trigger--error{border-color:var(--color-error-default)}.ea-date-picker__trigger--error.ea-date-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-date-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-date-picker__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary)}.ea-date-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-date-picker__trigger-value--placeholder{color:var(--color-text-tertiary)}.ea-date-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-date-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__popover{display:flex;flex-direction:column;gap:var(--space-2);min-width:17.5rem;padding:var(--space-3);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-date-picker__header{display:flex;align-items:center;gap:var(--space-1)}.ea-date-picker__nav-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:1.75rem;height:1.75rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__nav-btn:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-date-picker__nav-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__nav-btn ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right{width:.875em;height:.875em}.ea-date-picker__nav-btn ea-icon-chevron-left+ea-icon-chevron-left,.ea-date-picker__nav-btn ea-icon-chevron-right+ea-icon-chevron-right{margin-left:-.375em}.ea-date-picker__month-label{flex:1;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);text-align:center;color:var(--color-text-primary)}.ea-date-picker__grid{display:flex;flex-direction:column;gap:var(--space-1)}.ea-date-picker__weekday-row,.ea-date-picker__week{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--space-1)}.ea-date-picker__weekday{display:flex;align-items:center;justify-content:center;height:1.5rem;font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);text-transform:uppercase;color:var(--color-text-tertiary)}.ea-date-picker__day{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__day:hover:not(:disabled){background-color:var(--color-bg-muted)}.ea-date-picker__day:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-date-picker__day--outside{color:var(--color-text-tertiary)}.ea-date-picker__day--today{font-weight:var(--font-weight-semibold);color:var(--color-brand-default)}.ea-date-picker__day--focused:not(.ea-date-picker__day--selected){background-color:var(--color-bg-muted)}.ea-date-picker__day--selected{background-color:var(--color-brand-default);color:var(--color-text-inverse);font-weight:var(--font-weight-medium)}.ea-date-picker__day--selected:hover{background-color:var(--color-brand-hover)}.ea-date-picker__day--disabled{color:var(--color-text-disabled);cursor:not-allowed}.ea-date-picker__day--disabled:hover{background-color:transparent}.ea-date-picker__footer{display:flex;justify-content:flex-end;padding-top:var(--space-2);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-date-picker__today-btn{padding:var(--space-1) var(--space-2);border:none;border-radius:var(--radius-sm);background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-brand-default);cursor:pointer;transition:var(--transition-colors)}.ea-date-picker__today-btn:hover{background-color:var(--color-brand-subtle)}.ea-date-picker__today-btn:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}\n"] }]
5089
+ }], propDecorators: { triggerEl: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], weekStartsOn: [{ type: i0.Input, args: [{ isSignal: true, alias: "weekStartsOn", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
4650
5090
 
4651
5091
  /**
4652
5092
  * Modal dialog backed by the native `<dialog>` element. Uses `showModal()`
@@ -4806,12 +5246,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
4806
5246
  * Single-select dropdown with a custom popup list. Supports keyboard
4807
5247
  * navigation (arrow keys, Enter/Space to select, Escape to close), closes
4808
5248
  * on outside click or viewport scroll/resize, and integrates with Angular
4809
- * forms via `ControlValueAccessor`.
5249
+ * forms via `ControlValueAccessor`. Positioning, dismissal, and SSR-safe
5250
+ * scroll handling are provided by `<ea-popover>`.
4810
5251
  */
4811
5252
  class DropdownComponent {
4812
5253
  elRef = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "elRef" }] : /* istanbul ignore next */ []));
4813
- menuEl = viewChild('menuEl', ...(ngDevMode ? [{ debugName: "menuEl" }] : /* istanbul ignore next */ []));
4814
- destroyRef = inject(DestroyRef);
4815
5254
  i18n = inject(EagamiI18nService);
4816
5255
  // Inputs
4817
5256
  label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
@@ -4853,36 +5292,6 @@ class DropdownComponent {
4853
5292
  'ea-dropdown__trigger--open': this.isOpen(),
4854
5293
  'ea-dropdown__trigger--disabled': this.isDisabled(),
4855
5294
  }), ...(ngDevMode ? [{ debugName: "triggerClasses" }] : /* istanbul ignore next */ []));
4856
- constructor() {
4857
- effect(() => {
4858
- const menu = this.menuEl()?.nativeElement;
4859
- const trigger = this.elRef()?.nativeElement;
4860
- if (!menu || !trigger || !this.isOpen())
4861
- return;
4862
- const rect = trigger.getBoundingClientRect();
4863
- menu.style.top = `${rect.bottom + 4}px`;
4864
- menu.style.left = `${rect.left}px`;
4865
- menu.style.minWidth = `${rect.width}px`;
4866
- });
4867
- // Guard `window` for SSR: the website prerenders 42 routes, and the
4868
- // dropdown can appear inside any of them. Without this, prerendering
4869
- // throws `ReferenceError: window is not defined`.
4870
- if (typeof window !== 'undefined') {
4871
- const closeOnViewportChange = () => {
4872
- if (this.isOpen())
4873
- this.close();
4874
- };
4875
- window.addEventListener('scroll', closeOnViewportChange, {
4876
- capture: true,
4877
- passive: true,
4878
- });
4879
- window.addEventListener('resize', closeOnViewportChange);
4880
- this.destroyRef.onDestroy(() => {
4881
- window.removeEventListener('scroll', closeOnViewportChange, { capture: true });
4882
- window.removeEventListener('resize', closeOnViewportChange);
4883
- });
4884
- }
4885
- }
4886
5295
  // ControlValueAccessor
4887
5296
  writeValue(val) {
4888
5297
  this.value.set(val ?? '');
@@ -4926,6 +5335,11 @@ class DropdownComponent {
4926
5335
  focus() {
4927
5336
  this.elRef()?.nativeElement.focus();
4928
5337
  }
5338
+ /** Called by `<ea-popover>` when the user clicks outside the dropdown. */
5339
+ onPopoverCloseRequested() {
5340
+ this.close();
5341
+ this.onTouched();
5342
+ }
4929
5343
  handleKeydown(event) {
4930
5344
  if (this.isDisabled() || this.readonly())
4931
5345
  return;
@@ -4978,38 +5392,30 @@ class DropdownComponent {
4978
5392
  this.focusedIndex.set(idx);
4979
5393
  }
4980
5394
  }
4981
- onDocumentClick(event) {
4982
- if (!this.isOpen())
4983
- return;
4984
- const el = event.target;
4985
- const host = this.elRef()?.nativeElement.closest('ea-dropdown');
4986
- if (host && !host.contains(el)) {
4987
- this.close();
4988
- this.onTouched();
4989
- }
4990
- }
4991
5395
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4992
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: DropdownComponent, isStandalone: true, selector: "ea-dropdown", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, providers: [
5396
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: DropdownComponent, isStandalone: true, selector: "ea-dropdown", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, providers: [
4993
5397
  {
4994
5398
  provide: NG_VALUE_ACCESSOR,
4995
5399
  useExisting: forwardRef(() => DropdownComponent),
4996
5400
  multi: true,
4997
5401
  },
4998
- ], viewQueries: [{ propertyName: "elRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "menuEl", first: true, predicate: ["menuEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-dropdown-field\">\n @if (label()) {\n <label\n class=\"ea-dropdown-field__label\"\n [for]=\"id()\"\n [id]=\"id() + '-label'\"\n [class.ea-dropdown-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-dropdown\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-dropdown__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"isOpen() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"\n isOpen() && focusedIndex() >= 0 ? id() + '-option-' + focusedIndex() : null\n \"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\">\n <span\n class=\"ea-dropdown__value\"\n [class.ea-dropdown__value--placeholder]=\"!selectedLabel()\">\n {{ selectedLabel() || resolvedPlaceholder() }}\n </span>\n <ea-icon-chevron-down\n class=\"ea-dropdown__chevron\"\n [class.ea-dropdown__chevron--open]=\"isOpen()\" />\n </button>\n\n @if (isOpen()) {\n <ul\n #menuEl\n class=\"ea-dropdown__menu\"\n role=\"listbox\"\n [id]=\"id() + '-listbox'\">\n @for (option of options(); track option.value; let i = $index) {\n <li\n class=\"ea-dropdown__option\"\n [class.ea-dropdown__option--selected]=\"option.value === value()\"\n [class.ea-dropdown__option--focused]=\"i === focusedIndex()\"\n [class.ea-dropdown__option--disabled]=\"option.disabled\"\n [id]=\"id() + '-option-' + i\"\n role=\"option\"\n [attr.aria-selected]=\"option.value === value()\"\n [attr.aria-disabled]=\"option.disabled || null\"\n (click)=\"select(option)\"\n (mouseenter)=\"focusedIndex.set(i)\">\n {{ option.label }}\n </li>\n }\n </ul>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-dropdown-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-dropdown-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-dropdown-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-dropdown-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-dropdown-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-dropdown-field__message--hint{color:var(--color-text-secondary)}.ea-dropdown-field__message--error{color:var(--color-error-default)}.ea-dropdown-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-dropdown{position:relative}.ea-dropdown__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-dropdown__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-dropdown__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-dropdown__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-dropdown__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--error{border-color:var(--color-error-default)}.ea-dropdown__trigger--error.ea-dropdown__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-dropdown__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-dropdown__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-dropdown__value--placeholder{color:var(--color-text-tertiary)}.ea-dropdown__chevron{width:1em;height:1em;flex-shrink:0;color:var(--color-text-secondary);transition:var(--transition-transform)}.ea-dropdown__chevron--open{transform:rotate(180deg)}.ea-dropdown__menu{position:fixed;z-index:var(--z-index-dropdown);max-height:15rem;overflow-y:auto;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);padding:var(--space-1) 0;margin:0;list-style:none}.ea-dropdown__option{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);white-space:nowrap;font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-dropdown__option--focused{background-color:var(--color-bg-muted)}.ea-dropdown__option--selected{color:var(--color-brand-default);font-weight:var(--font-weight-medium)}.ea-dropdown__option--disabled{color:var(--color-text-disabled);cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: ChevronDownIconComponent, selector: "ea-icon-chevron-down" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
5402
+ ], viewQueries: [{ propertyName: "elRef", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-dropdown-field\">\n @if (label()) {\n <label\n class=\"ea-dropdown-field__label\"\n [for]=\"id()\"\n [id]=\"id() + '-label'\"\n [class.ea-dropdown-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-dropdown\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-dropdown__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"isOpen() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"\n isOpen() && focusedIndex() >= 0 ? id() + '-option-' + focusedIndex() : null\n \"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\">\n <span\n class=\"ea-dropdown__value\"\n [class.ea-dropdown__value--placeholder]=\"!selectedLabel()\">\n {{ selectedLabel() || resolvedPlaceholder() }}\n </span>\n <ea-icon-chevron-down\n class=\"ea-dropdown__chevron\"\n [class.ea-dropdown__chevron--open]=\"isOpen()\" />\n </button>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"listbox\"\n [surfaceId]=\"id() + '-listbox'\"\n [matchAnchorWidth]=\"true\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div class=\"ea-dropdown__menu\">\n @for (option of options(); track option.value; let i = $index) {\n <div\n class=\"ea-dropdown__option\"\n [class.ea-dropdown__option--selected]=\"option.value === value()\"\n [class.ea-dropdown__option--focused]=\"i === focusedIndex()\"\n [class.ea-dropdown__option--disabled]=\"option.disabled\"\n [id]=\"id() + '-option-' + i\"\n role=\"option\"\n [attr.aria-selected]=\"option.value === value()\"\n [attr.aria-disabled]=\"option.disabled || null\"\n (click)=\"select(option)\"\n (mouseenter)=\"focusedIndex.set(i)\">\n {{ option.label }}\n </div>\n }\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-dropdown-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-dropdown-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-dropdown-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-dropdown-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-dropdown-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-dropdown-field__message--hint{color:var(--color-text-secondary)}.ea-dropdown-field__message--error{color:var(--color-error-default)}.ea-dropdown-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-dropdown{position:relative}.ea-dropdown__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-dropdown__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-dropdown__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-dropdown__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-dropdown__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--error{border-color:var(--color-error-default)}.ea-dropdown__trigger--error.ea-dropdown__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-dropdown__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-dropdown__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-dropdown__value--placeholder{color:var(--color-text-tertiary)}.ea-dropdown__chevron{width:1em;height:1em;flex-shrink:0;color:var(--color-text-secondary);transition:var(--transition-transform)}.ea-dropdown__chevron--open{transform:rotate(180deg)}.ea-dropdown__menu{max-height:15rem;padding:var(--space-1) 0;overflow-y:auto;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-dropdown__option{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);white-space:nowrap;font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-dropdown__option--focused{background-color:var(--color-bg-muted)}.ea-dropdown__option--selected{color:var(--color-brand-default);font-weight:var(--font-weight-medium)}.ea-dropdown__option--disabled{color:var(--color-text-disabled);cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: ChevronDownIconComponent, selector: "ea-icon-chevron-down" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PopoverComponent, selector: "ea-popover", inputs: ["anchor", "open", "placement", "role", "aria-label", "surfaceId", "offset", "flip", "clamp", "matchAnchorWidth", "closeOnOutsideClick", "closeOnEscape", "scrollBehavior"], outputs: ["closeRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
4999
5403
  }
5000
5404
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DropdownComponent, decorators: [{
5001
5405
  type: Component,
5002
- args: [{ selector: 'ea-dropdown', imports: [AlertCircleIconComponent, ChevronDownIconComponent, NgClass], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
5406
+ args: [{ selector: 'ea-dropdown', imports: [
5407
+ AlertCircleIconComponent,
5408
+ ChevronDownIconComponent,
5409
+ NgClass,
5410
+ PopoverComponent,
5411
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
5003
5412
  {
5004
5413
  provide: NG_VALUE_ACCESSOR,
5005
5414
  useExisting: forwardRef(() => DropdownComponent),
5006
5415
  multi: true,
5007
5416
  },
5008
- ], template: "<div class=\"ea-dropdown-field\">\n @if (label()) {\n <label\n class=\"ea-dropdown-field__label\"\n [for]=\"id()\"\n [id]=\"id() + '-label'\"\n [class.ea-dropdown-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-dropdown\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-dropdown__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"isOpen() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"\n isOpen() && focusedIndex() >= 0 ? id() + '-option-' + focusedIndex() : null\n \"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\">\n <span\n class=\"ea-dropdown__value\"\n [class.ea-dropdown__value--placeholder]=\"!selectedLabel()\">\n {{ selectedLabel() || resolvedPlaceholder() }}\n </span>\n <ea-icon-chevron-down\n class=\"ea-dropdown__chevron\"\n [class.ea-dropdown__chevron--open]=\"isOpen()\" />\n </button>\n\n @if (isOpen()) {\n <ul\n #menuEl\n class=\"ea-dropdown__menu\"\n role=\"listbox\"\n [id]=\"id() + '-listbox'\">\n @for (option of options(); track option.value; let i = $index) {\n <li\n class=\"ea-dropdown__option\"\n [class.ea-dropdown__option--selected]=\"option.value === value()\"\n [class.ea-dropdown__option--focused]=\"i === focusedIndex()\"\n [class.ea-dropdown__option--disabled]=\"option.disabled\"\n [id]=\"id() + '-option-' + i\"\n role=\"option\"\n [attr.aria-selected]=\"option.value === value()\"\n [attr.aria-disabled]=\"option.disabled || null\"\n (click)=\"select(option)\"\n (mouseenter)=\"focusedIndex.set(i)\">\n {{ option.label }}\n </li>\n }\n </ul>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-dropdown-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-dropdown-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-dropdown-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-dropdown-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-dropdown-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-dropdown-field__message--hint{color:var(--color-text-secondary)}.ea-dropdown-field__message--error{color:var(--color-error-default)}.ea-dropdown-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-dropdown{position:relative}.ea-dropdown__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-dropdown__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-dropdown__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-dropdown__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-dropdown__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--error{border-color:var(--color-error-default)}.ea-dropdown__trigger--error.ea-dropdown__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-dropdown__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-dropdown__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-dropdown__value--placeholder{color:var(--color-text-tertiary)}.ea-dropdown__chevron{width:1em;height:1em;flex-shrink:0;color:var(--color-text-secondary);transition:var(--transition-transform)}.ea-dropdown__chevron--open{transform:rotate(180deg)}.ea-dropdown__menu{position:fixed;z-index:var(--z-index-dropdown);max-height:15rem;overflow-y:auto;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);padding:var(--space-1) 0;margin:0;list-style:none}.ea-dropdown__option{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);white-space:nowrap;font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-dropdown__option--focused{background-color:var(--color-bg-muted)}.ea-dropdown__option--selected{color:var(--color-brand-default);font-weight:var(--font-weight-medium)}.ea-dropdown__option--disabled{color:var(--color-text-disabled);cursor:not-allowed}\n"] }]
5009
- }], ctorParameters: () => [], propDecorators: { elRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], menuEl: [{ type: i0.ViewChild, args: ['menuEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }], onDocumentClick: [{
5010
- type: HostListener,
5011
- args: ['document:click', ['$event']]
5012
- }] } });
5417
+ ], template: "<div class=\"ea-dropdown-field\">\n @if (label()) {\n <label\n class=\"ea-dropdown-field__label\"\n [for]=\"id()\"\n [id]=\"id() + '-label'\"\n [class.ea-dropdown-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-dropdown\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-dropdown__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-controls]=\"isOpen() ? id() + '-listbox' : null\"\n [attr.aria-activedescendant]=\"\n isOpen() && focusedIndex() >= 0 ? id() + '-option-' + focusedIndex() : null\n \"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleKeydown($event)\">\n <span\n class=\"ea-dropdown__value\"\n [class.ea-dropdown__value--placeholder]=\"!selectedLabel()\">\n {{ selectedLabel() || resolvedPlaceholder() }}\n </span>\n <ea-icon-chevron-down\n class=\"ea-dropdown__chevron\"\n [class.ea-dropdown__chevron--open]=\"isOpen()\" />\n </button>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"listbox\"\n [surfaceId]=\"id() + '-listbox'\"\n [matchAnchorWidth]=\"true\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div class=\"ea-dropdown__menu\">\n @for (option of options(); track option.value; let i = $index) {\n <div\n class=\"ea-dropdown__option\"\n [class.ea-dropdown__option--selected]=\"option.value === value()\"\n [class.ea-dropdown__option--focused]=\"i === focusedIndex()\"\n [class.ea-dropdown__option--disabled]=\"option.disabled\"\n [id]=\"id() + '-option-' + i\"\n role=\"option\"\n [attr.aria-selected]=\"option.value === value()\"\n [attr.aria-disabled]=\"option.disabled || null\"\n (click)=\"select(option)\"\n (mouseenter)=\"focusedIndex.set(i)\">\n {{ option.label }}\n </div>\n }\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-dropdown-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-dropdown-field__message ea-dropdown-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-dropdown-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-dropdown-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-dropdown-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-dropdown-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-dropdown-field__message--hint{color:var(--color-text-secondary)}.ea-dropdown-field__message--error{color:var(--color-error-default)}.ea-dropdown-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-dropdown{position:relative}.ea-dropdown__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-dropdown__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-dropdown__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-dropdown__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-dropdown__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-dropdown__trigger--error{border-color:var(--color-error-default)}.ea-dropdown__trigger--error.ea-dropdown__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-dropdown__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-dropdown__value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-dropdown__value--placeholder{color:var(--color-text-tertiary)}.ea-dropdown__chevron{width:1em;height:1em;flex-shrink:0;color:var(--color-text-secondary);transition:var(--transition-transform)}.ea-dropdown__chevron--open{transform:rotate(180deg)}.ea-dropdown__menu{max-height:15rem;padding:var(--space-1) 0;overflow-y:auto;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-dropdown__option{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);white-space:nowrap;font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-dropdown__option--focused{background-color:var(--color-bg-muted)}.ea-dropdown__option--selected{color:var(--color-brand-default);font-weight:var(--font-weight-medium)}.ea-dropdown__option--disabled{color:var(--color-text-disabled);cursor:not-allowed}\n"] }]
5418
+ }], propDecorators: { elRef: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
5013
5419
 
5014
5420
  class EagamiIconComponent extends IconComponentBase {
5015
5421
  static slug = 'eagami';
@@ -15477,6 +15883,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
15477
15883
  }]
15478
15884
  }] });
15479
15885
 
15886
+ class LeftHalfStarIconComponent extends IconComponentBase {
15887
+ static slug = 'left-half-star';
15888
+ static category = 'eagami';
15889
+ static tags = [
15890
+ 'left-half-star',
15891
+ 'half-star',
15892
+ 'half',
15893
+ 'left',
15894
+ 'partial',
15895
+ 'rating',
15896
+ 'star',
15897
+ 'shape',
15898
+ 'demi-étoile',
15899
+ 'demi',
15900
+ 'gauche',
15901
+ 'media-estrella',
15902
+ 'media',
15903
+ 'izquierda',
15904
+ 'μισό-αστέρι',
15905
+ 'μισό',
15906
+ 'αριστερά',
15907
+ 'pół-gwiazdy',
15908
+ 'pół',
15909
+ 'lewa',
15910
+ ];
15911
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: LeftHalfStarIconComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
15912
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.13", type: LeftHalfStarIconComponent, isStandalone: true, selector: "ea-icon-left-half-star", usesInheritance: true, ngImport: i0, template: `
15913
+ <svg
15914
+ viewBox="0 0 24 24"
15915
+ fill="none"
15916
+ stroke="currentColor"
15917
+ stroke-width="2"
15918
+ stroke-linecap="round"
15919
+ stroke-linejoin="round"
15920
+ aria-hidden="true"
15921
+ width="100%"
15922
+ height="100%">
15923
+ <path d="M12 2 L8.91 8.26 L2 9.27 L7 14.14 L5.82 21.02 L12 17.77 Z" />
15924
+ </svg>
15925
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
15926
+ }
15927
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: LeftHalfStarIconComponent, decorators: [{
15928
+ type: Component,
15929
+ args: [{
15930
+ selector: 'ea-icon-left-half-star',
15931
+ changeDetection: ChangeDetectionStrategy.OnPush,
15932
+ template: `
15933
+ <svg
15934
+ viewBox="0 0 24 24"
15935
+ fill="none"
15936
+ stroke="currentColor"
15937
+ stroke-width="2"
15938
+ stroke-linecap="round"
15939
+ stroke-linejoin="round"
15940
+ aria-hidden="true"
15941
+ width="100%"
15942
+ height="100%">
15943
+ <path d="M12 2 L8.91 8.26 L2 9.27 L7 14.14 L5.82 21.02 L12 17.77 Z" />
15944
+ </svg>
15945
+ `,
15946
+ }]
15947
+ }] });
15948
+
15480
15949
  class LifeBuoyIconComponent extends IconComponentBase {
15481
15950
  static slug = 'life-buoy';
15482
15951
  static category = 'feather';
@@ -20402,6 +20871,69 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
20402
20871
  }]
20403
20872
  }] });
20404
20873
 
20874
+ class RightHalfStarIconComponent extends IconComponentBase {
20875
+ static slug = 'right-half-star';
20876
+ static category = 'eagami';
20877
+ static tags = [
20878
+ 'right-half-star',
20879
+ 'half-star',
20880
+ 'half',
20881
+ 'right',
20882
+ 'partial',
20883
+ 'rating',
20884
+ 'star',
20885
+ 'shape',
20886
+ 'demi-étoile',
20887
+ 'demi',
20888
+ 'droite',
20889
+ 'media-estrella',
20890
+ 'media',
20891
+ 'derecha',
20892
+ 'μισό-αστέρι',
20893
+ 'μισό',
20894
+ 'δεξιά',
20895
+ 'pół-gwiazdy',
20896
+ 'pół',
20897
+ 'prawa',
20898
+ ];
20899
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RightHalfStarIconComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
20900
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.13", type: RightHalfStarIconComponent, isStandalone: true, selector: "ea-icon-right-half-star", usesInheritance: true, ngImport: i0, template: `
20901
+ <svg
20902
+ viewBox="0 0 24 24"
20903
+ fill="none"
20904
+ stroke="currentColor"
20905
+ stroke-width="2"
20906
+ stroke-linecap="round"
20907
+ stroke-linejoin="round"
20908
+ aria-hidden="true"
20909
+ width="100%"
20910
+ height="100%">
20911
+ <path d="M12 2 L15.09 8.26 L22 9.27 L17 14.14 L18.18 21.02 L12 17.77 Z" />
20912
+ </svg>
20913
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
20914
+ }
20915
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RightHalfStarIconComponent, decorators: [{
20916
+ type: Component,
20917
+ args: [{
20918
+ selector: 'ea-icon-right-half-star',
20919
+ changeDetection: ChangeDetectionStrategy.OnPush,
20920
+ template: `
20921
+ <svg
20922
+ viewBox="0 0 24 24"
20923
+ fill="none"
20924
+ stroke="currentColor"
20925
+ stroke-width="2"
20926
+ stroke-linecap="round"
20927
+ stroke-linejoin="round"
20928
+ aria-hidden="true"
20929
+ width="100%"
20930
+ height="100%">
20931
+ <path d="M12 2 L15.09 8.26 L22 9.27 L17 14.14 L18.18 21.02 L12 17.77 Z" />
20932
+ </svg>
20933
+ `,
20934
+ }]
20935
+ }] });
20936
+
20405
20937
  class RotateCwIconComponent extends IconComponentBase {
20406
20938
  static slug = 'rotate-cw';
20407
20939
  static category = 'feather';
@@ -26781,9 +27313,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
26781
27313
  * the full set. For single-icon usage import the component directly (e.g.
26782
27314
  * `import { HomeIconComponent } from '@eagami/ui'`) and the bundler will
26783
27315
  * tree-shake `ICONS` away.
26784
- *
26785
- * Deprecated aliases (e.g. `PencilIconComponent`) are intentionally excluded
26786
- * so they don't surface in generated catalogues.
26787
27316
  */
26788
27317
  const ICONS = [
26789
27318
  ActivityIconComponent,
@@ -26942,6 +27471,7 @@ const ICONS = [
26942
27471
  LampIconComponent,
26943
27472
  LayersIconComponent,
26944
27473
  LayoutIconComponent,
27474
+ LeftHalfStarIconComponent,
26945
27475
  LifeBuoyIconComponent,
26946
27476
  Link2IconComponent,
26947
27477
  LinkIconComponent,
@@ -27016,6 +27546,7 @@ const ICONS = [
27016
27546
  RefreshCwIconComponent,
27017
27547
  RepeatIconComponent,
27018
27548
  RewindIconComponent,
27549
+ RightHalfStarIconComponent,
27019
27550
  RotateCcwIconComponent,
27020
27551
  RotateCwIconComponent,
27021
27552
  RssIconComponent,
@@ -27111,110 +27642,6 @@ const ICONS = [
27111
27642
  ZoomOutIconComponent,
27112
27643
  ].sort((a, b) => a.slug.localeCompare(b.slug));
27113
27644
 
27114
- /**
27115
- * @deprecated Will be removed in v2.0.0. The icon depicts Apple Inc.'s logo,
27116
- * which is more strictly protected than other brand marks. Source the asset
27117
- * directly from Apple per their brand guidelines for use cases like "Sign in
27118
- * with Apple".
27119
- */
27120
- class AppleIconComponent extends IconComponentBase {
27121
- brand = input(false, ...(ngDevMode ? [{ debugName: "brand" }] : /* istanbul ignore next */ []));
27122
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: AppleIconComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
27123
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: AppleIconComponent, isStandalone: true, selector: "ea-icon-apple", inputs: { brand: { classPropertyName: "brand", publicName: "brand", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.color": "brand() ? '#000000' : null" } }, usesInheritance: true, ngImport: i0, template: `
27124
- <svg
27125
- viewBox="0 0 24 24"
27126
- fill="currentColor"
27127
- aria-hidden="true"
27128
- width="100%"
27129
- height="100%">
27130
- <path
27131
- d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09ZM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.32 2.32-1.55 4.3-3.74 4.25Z" />
27132
- </svg>
27133
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
27134
- }
27135
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: AppleIconComponent, decorators: [{
27136
- type: Component,
27137
- args: [{
27138
- selector: 'ea-icon-apple',
27139
- changeDetection: ChangeDetectionStrategy.OnPush,
27140
- host: { '[style.color]': "brand() ? '#000000' : null" },
27141
- template: `
27142
- <svg
27143
- viewBox="0 0 24 24"
27144
- fill="currentColor"
27145
- aria-hidden="true"
27146
- width="100%"
27147
- height="100%">
27148
- <path
27149
- d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09ZM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.32 2.32-1.55 4.3-3.74 4.25Z" />
27150
- </svg>
27151
- `,
27152
- }]
27153
- }], propDecorators: { brand: [{ type: i0.Input, args: [{ isSignal: true, alias: "brand", required: false }] }] } });
27154
-
27155
- /**
27156
- * @deprecated Will be removed in v2.0.0. The `pencil` icon depicts the same
27157
- * mark as Feather's canonical `edit-2` (with a marginally different cap
27158
- * curvature) and is being retired as redundant. Switch to `<ea-icon-edit-2>`
27159
- * / `Edit2IconComponent`.
27160
- */
27161
- class PencilIconComponent extends IconComponentBase {
27162
- static slug = 'pencil';
27163
- static category = 'feather';
27164
- static tags = [
27165
- 'edit-2',
27166
- 'edit',
27167
- '2',
27168
- 'pencil',
27169
- 'modify',
27170
- 'write',
27171
- 'éditer',
27172
- 'crayon',
27173
- 'editar',
27174
- 'lápiz',
27175
- 'επεξεργασία',
27176
- 'μολύβι',
27177
- 'edytuj',
27178
- 'ołówek',
27179
- ];
27180
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PencilIconComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
27181
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.13", type: PencilIconComponent, isStandalone: true, selector: "ea-icon-pencil", usesInheritance: true, ngImport: i0, template: `
27182
- <svg
27183
- viewBox="0 0 24 24"
27184
- fill="none"
27185
- stroke="currentColor"
27186
- stroke-width="2"
27187
- stroke-linecap="round"
27188
- stroke-linejoin="round"
27189
- aria-hidden="true"
27190
- width="100%"
27191
- height="100%">
27192
- <path d="M17 3a2.83 2.83 0 0 1 4 4L7.5 20.5 2 22l1.5-5.5Z" />
27193
- </svg>
27194
- `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
27195
- }
27196
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PencilIconComponent, decorators: [{
27197
- type: Component,
27198
- args: [{
27199
- selector: 'ea-icon-pencil',
27200
- changeDetection: ChangeDetectionStrategy.OnPush,
27201
- template: `
27202
- <svg
27203
- viewBox="0 0 24 24"
27204
- fill="none"
27205
- stroke="currentColor"
27206
- stroke-width="2"
27207
- stroke-linecap="round"
27208
- stroke-linejoin="round"
27209
- aria-hidden="true"
27210
- width="100%"
27211
- height="100%">
27212
- <path d="M17 3a2.83 2.83 0 0 1 4 4L7.5 20.5 2 22l1.5-5.5Z" />
27213
- </svg>
27214
- `,
27215
- }]
27216
- }] });
27217
-
27218
27645
  /**
27219
27646
  * Single-line text field with label, hint, and error message support.
27220
27647
  * Includes a built-in show/hide toggle for `password` inputs and integrates
@@ -27335,7 +27762,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
27335
27762
  * Popup action menu attached to any focusable element via the
27336
27763
  * `[eaMenuTrigger]` directive. Supports keyboard navigation
27337
27764
  * (arrow keys, Home/End), closes on outside click or Escape, and restores
27338
- * focus to the trigger on close.
27765
+ * focus to the trigger on close. Positioning, dismissal, and SSR-safe scroll
27766
+ * handling are provided by `<ea-popover>`.
27339
27767
  */
27340
27768
  class MenuComponent {
27341
27769
  injector = inject(Injector);
@@ -27352,32 +27780,8 @@ class MenuComponent {
27352
27780
  opened = output();
27353
27781
  /** Fires when the menu closes. */
27354
27782
  closed = output();
27355
- triggerEl = null;
27356
- triggerRect = signal(null, ...(ngDevMode ? [{ debugName: "triggerRect" }] : /* istanbul ignore next */ []));
27357
- listClasses = computed(() => ({
27358
- [`ea-menu__list--${this.placement()}`]: true,
27359
- }), ...(ngDevMode ? [{ debugName: "listClasses" }] : /* istanbul ignore next */ []));
27360
- listStyle = computed(() => {
27361
- const rect = this.triggerRect();
27362
- if (!rect)
27363
- return {};
27364
- const placement = this.placement();
27365
- const gap = 4;
27366
- const style = {};
27367
- if (placement === 'bottom-start' || placement === 'bottom-end') {
27368
- style['top'] = `${rect.bottom + gap}px`;
27369
- }
27370
- else {
27371
- style['bottom'] = `${window.innerHeight - rect.top + gap}px`;
27372
- }
27373
- if (placement === 'bottom-start' || placement === 'top-start') {
27374
- style['left'] = `${rect.left}px`;
27375
- }
27376
- else {
27377
- style['right'] = `${window.innerWidth - rect.right}px`;
27378
- }
27379
- return style;
27380
- }, ...(ngDevMode ? [{ debugName: "listStyle" }] : /* istanbul ignore next */ []));
27783
+ /** Trigger element currently anchoring the menu. Signal-typed so `<ea-popover>` reacts when it changes. */
27784
+ triggerEl = signal(undefined, ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
27381
27785
  /** Toggles the menu open state, anchoring it to the given trigger element. */
27382
27786
  toggleAt(triggerEl) {
27383
27787
  if (this.disabled())
@@ -27393,8 +27797,7 @@ class MenuComponent {
27393
27797
  openAt(triggerEl) {
27394
27798
  if (this.disabled())
27395
27799
  return;
27396
- this.triggerEl = triggerEl;
27397
- this.triggerRect.set(triggerEl.getBoundingClientRect());
27800
+ this.triggerEl.set(triggerEl);
27398
27801
  this.open.set(true);
27399
27802
  this.opened.emit();
27400
27803
  afterNextRender(() => this.focusFirstItem(), { injector: this.injector });
@@ -27410,7 +27813,11 @@ class MenuComponent {
27410
27813
  this.open.set(false);
27411
27814
  this.closed.emit();
27412
27815
  if (restoreFocus)
27413
- this.triggerEl?.focus({ preventScroll: true });
27816
+ this.triggerEl()?.focus({ preventScroll: true });
27817
+ }
27818
+ /** Called by `<ea-popover>` when the user clicks outside the menu. */
27819
+ onPopoverCloseRequested() {
27820
+ this.close();
27414
27821
  }
27415
27822
  getEnabledItems() {
27416
27823
  const list = this.listEl()?.nativeElement;
@@ -27464,47 +27871,23 @@ class MenuComponent {
27464
27871
  if (next >= 0)
27465
27872
  items[next].focus({ preventScroll: true });
27466
27873
  }
27467
- onDocumentClick(event) {
27468
- if (!this.open())
27469
- return;
27470
- const target = event.target;
27471
- if (this.triggerEl?.contains(target))
27472
- return;
27473
- if (this.listEl()?.nativeElement.contains(target))
27474
- return;
27475
- this.close();
27476
- }
27477
27874
  onEscape() {
27478
27875
  if (!this.open())
27479
27876
  return;
27480
27877
  this.close(true);
27481
27878
  }
27482
- onViewportChange() {
27483
- if (!this.open() || !this.triggerEl)
27484
- return;
27485
- this.triggerRect.set(this.triggerEl.getBoundingClientRect());
27486
- }
27487
27879
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
27488
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: MenuComponent, isStandalone: true, selector: "ea-menu", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", opened: "opened", closed: "closed" }, host: { listeners: { "document:keydown": "onKeydown($event)", "document:click": "onDocumentClick($event)", "document:keydown.escape": "onEscape()", "window:resize": "onViewportChange()", "window:scroll": "onViewportChange()" } }, viewQueries: [{ propertyName: "listEl", first: true, predicate: ["listEl"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <div\n #listEl\n class=\"ea-menu__list\"\n role=\"menu\"\n [id]=\"id()\"\n [ngClass]=\"listClasses()\"\n [style]=\"listStyle()\"\n [attr.aria-label]=\"resolvedAriaLabel()\">\n <ng-content />\n </div>\n}\n", styles: [":host{display:contents}.ea-menu__list{position:fixed;z-index:var(--z-index-dropdown);min-width:10rem;max-height:20rem;padding:var(--space-1) 0;overflow-y:auto;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
27880
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.13", type: MenuComponent, isStandalone: true, selector: "ea-menu", inputs: { placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "aria-label", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", opened: "opened", closed: "closed" }, host: { listeners: { "document:keydown": "onKeydown($event)", "document:keydown.escape": "onEscape()" } }, viewQueries: [{ propertyName: "listEl", first: true, predicate: ["listEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<ea-popover\n [anchor]=\"triggerEl()\"\n [open]=\"open()\"\n [placement]=\"placement()\"\n role=\"menu\"\n [surfaceId]=\"id()\"\n [ariaLabel]=\"resolvedAriaLabel()\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"reposition\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div\n #listEl\n class=\"ea-menu__list\">\n <ng-content />\n </div>\n</ea-popover>\n", styles: [":host{display:contents}.ea-menu__list{min-width:10rem;max-height:20rem;padding:var(--space-1) 0;overflow-y:auto;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}\n"], dependencies: [{ kind: "component", type: PopoverComponent, selector: "ea-popover", inputs: ["anchor", "open", "placement", "role", "aria-label", "surfaceId", "offset", "flip", "clamp", "matchAnchorWidth", "closeOnOutsideClick", "closeOnEscape", "scrollBehavior"], outputs: ["closeRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
27489
27881
  }
27490
27882
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: MenuComponent, decorators: [{
27491
27883
  type: Component,
27492
- args: [{ selector: 'ea-menu', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open()) {\n <div\n #listEl\n class=\"ea-menu__list\"\n role=\"menu\"\n [id]=\"id()\"\n [ngClass]=\"listClasses()\"\n [style]=\"listStyle()\"\n [attr.aria-label]=\"resolvedAriaLabel()\">\n <ng-content />\n </div>\n}\n", styles: [":host{display:contents}.ea-menu__list{position:fixed;z-index:var(--z-index-dropdown);min-width:10rem;max-height:20rem;padding:var(--space-1) 0;overflow-y:auto;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}\n"] }]
27884
+ args: [{ selector: 'ea-menu', imports: [PopoverComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ea-popover\n [anchor]=\"triggerEl()\"\n [open]=\"open()\"\n [placement]=\"placement()\"\n role=\"menu\"\n [surfaceId]=\"id()\"\n [ariaLabel]=\"resolvedAriaLabel()\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"reposition\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div\n #listEl\n class=\"ea-menu__list\">\n <ng-content />\n </div>\n</ea-popover>\n", styles: [":host{display:contents}.ea-menu__list{min-width:10rem;max-height:20rem;padding:var(--space-1) 0;overflow-y:auto;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}\n"] }]
27493
27885
  }], propDecorators: { listEl: [{ type: i0.ViewChild, args: ['listEl', { isSignal: true }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], onKeydown: [{
27494
27886
  type: HostListener,
27495
27887
  args: ['document:keydown', ['$event']]
27496
- }], onDocumentClick: [{
27497
- type: HostListener,
27498
- args: ['document:click', ['$event']]
27499
27888
  }], onEscape: [{
27500
27889
  type: HostListener,
27501
27890
  args: ['document:keydown.escape']
27502
- }], onViewportChange: [{
27503
- type: HostListener,
27504
- args: ['window:resize']
27505
- }, {
27506
- type: HostListener,
27507
- args: ['window:scroll']
27508
27891
  }] } });
27509
27892
 
27510
27893
  /**
@@ -27583,97 +27966,440 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
27583
27966
  }], propDecorators: { menu: [{ type: i0.Input, args: [{ isSignal: true, alias: "eaMenuTrigger", required: true }] }] } });
27584
27967
 
27585
27968
  /**
27586
- * Page navigation control with previous/next buttons, numbered page jumps,
27587
- * an optional page-size selector, and a range label. Exposes `page` and
27588
- * `pageSize` as two-way `model()` bindings and emits a single `changed`
27589
- * event whenever either changes.
27969
+ * Inline label commonly used to represent filters, categories, or selected
27970
+ * items. When `removable`, renders a close button that emits `removed`; the
27971
+ * accessible name of that button is configurable via `removeLabel` and
27972
+ * otherwise falls back to the active locale's translation.
27590
27973
  */
27591
- class PaginatorComponent {
27974
+ class TagComponent {
27592
27975
  i18n = inject(EagamiI18nService);
27593
- totalItems = input.required(...(ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []));
27594
- pageSizeOptions = input([10, 25, 50, 100], ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
27595
- showPageSizeSelector = input(true, ...(ngDevMode ? [{ debugName: "showPageSizeSelector" }] : /* istanbul ignore next */ []));
27596
- showRangeLabel = input(true, ...(ngDevMode ? [{ debugName: "showRangeLabel" }] : /* istanbul ignore next */ []));
27597
- align = input('right', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
27976
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
27977
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
27978
+ removable = input(false, ...(ngDevMode ? [{ debugName: "removable" }] : /* istanbul ignore next */ []));
27598
27979
  disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
27599
- page = model(1, ...(ngDevMode ? [{ debugName: "page" }] : /* istanbul ignore next */ []));
27600
- pageSize = model(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
27601
- /** Fires when the user changes either the current page or the page size. */
27602
- changed = output();
27603
- totalPages = computed(() => Math.max(1, Math.ceil(this.totalItems() / this.pageSize())), ...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
27604
- rangeStart = computed(() => this.totalItems() === 0 ? 0 : (this.page() - 1) * this.pageSize() + 1, ...(ngDevMode ? [{ debugName: "rangeStart" }] : /* istanbul ignore next */ []));
27605
- rangeEnd = computed(() => Math.min(this.page() * this.pageSize(), this.totalItems()), ...(ngDevMode ? [{ debugName: "rangeEnd" }] : /* istanbul ignore next */ []));
27606
- canGoPrev = computed(() => this.page() > 1, ...(ngDevMode ? [{ debugName: "canGoPrev" }] : /* istanbul ignore next */ []));
27607
- canGoNext = computed(() => this.page() < this.totalPages(), ...(ngDevMode ? [{ debugName: "canGoNext" }] : /* istanbul ignore next */ []));
27608
- visiblePages = computed(() => {
27609
- const total = this.totalPages();
27610
- const current = this.page();
27611
- const pages = [];
27612
- if (total <= 7) {
27613
- for (let i = 1; i <= total; i++)
27614
- pages.push(i);
27615
- return pages;
27616
- }
27617
- pages.push(1);
27618
- if (current > 3) {
27619
- pages.push('ellipsis');
27620
- }
27621
- const start = Math.max(2, current - 1);
27622
- const end = Math.min(total - 1, current + 1);
27623
- for (let i = start; i <= end; i++) {
27624
- pages.push(i);
27625
- }
27626
- if (current < total - 2) {
27627
- pages.push('ellipsis');
27628
- }
27629
- pages.push(total);
27630
- return pages;
27631
- }, ...(ngDevMode ? [{ debugName: "visiblePages" }] : /* istanbul ignore next */ []));
27632
- /** Navigates to the given page, clamped into the valid range. */
27633
- goToPage(page) {
27634
- if (this.disabled())
27635
- return;
27636
- const clamped = Math.max(1, Math.min(page, this.totalPages()));
27637
- if (clamped === this.page())
27638
- return;
27639
- this.page.set(clamped);
27640
- this.changed.emit({ page: clamped, pageSize: this.pageSize() });
27641
- }
27642
- /** Navigates to the previous page if one exists. */
27643
- prevPage() {
27644
- if (this.canGoPrev())
27645
- this.goToPage(this.page() - 1);
27646
- }
27647
- /** Navigates to the next page if one exists. */
27648
- nextPage() {
27649
- if (this.canGoNext())
27650
- this.goToPage(this.page() + 1);
27651
- }
27652
- onPageSizeChange(event) {
27653
- if (this.disabled())
27654
- return;
27655
- const newSize = Number(event.target.value);
27656
- this.pageSize.set(newSize);
27657
- this.page.set(1);
27658
- this.changed.emit({ page: 1, pageSize: newSize });
27980
+ removeLabel = input(undefined, ...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
27981
+ /** Fires when the user activates the remove button on a `removable` tag. */
27982
+ removed = output();
27983
+ /** Accessible label for the remove button, falling back to the active locale. */
27984
+ resolvedRemoveLabel = computed(() => this.removeLabel() ?? this.i18n.messages().tag.remove, ...(ngDevMode ? [{ debugName: "resolvedRemoveLabel" }] : /* istanbul ignore next */ []));
27985
+ hostClasses = computed(() => ({
27986
+ [`ea-tag--${this.variant()}`]: true,
27987
+ [`ea-tag--${this.size()}`]: true,
27988
+ 'ea-tag--disabled': this.disabled(),
27989
+ }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
27990
+ onRemove(event) {
27991
+ event.stopPropagation();
27992
+ this.removed.emit();
27659
27993
  }
27660
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PaginatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
27661
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: PaginatorComponent, isStandalone: true, selector: "ea-paginator", inputs: { totalItems: { classPropertyName: "totalItems", publicName: "totalItems", isSignal: true, isRequired: true, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, showPageSizeSelector: { classPropertyName: "showPageSizeSelector", publicName: "showPageSizeSelector", isSignal: true, isRequired: false, transformFunction: null }, showRangeLabel: { classPropertyName: "showRangeLabel", publicName: "showRangeLabel", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange", pageSize: "pageSizeChange", changed: "changed" }, ngImport: i0, template: "<div\n class=\"ea-paginator\"\n [class.ea-paginator--left]=\"align() === 'left'\"\n [class.ea-paginator--center]=\"align() === 'center'\"\n [class.ea-paginator--disabled]=\"disabled()\"\n role=\"navigation\"\n [attr.aria-label]=\"i18n.messages().paginator.label\">\n @if (showPageSizeSelector()) {\n <div class=\"ea-paginator__page-size\">\n <label\n class=\"ea-paginator__label\"\n for=\"ea-paginator-size\">\n {{ i18n.messages().paginator.rowsPerPage }}\n </label>\n <select\n class=\"ea-paginator__select\"\n id=\"ea-paginator-size\"\n [disabled]=\"disabled()\"\n (change)=\"onPageSizeChange($event)\">\n @for (size of pageSizeOptions(); track size) {\n <option\n [value]=\"size\"\n [selected]=\"size === pageSize()\">\n {{ size }}\n </option>\n }\n </select>\n </div>\n }\n\n @if (showRangeLabel()) {\n <span class=\"ea-paginator__range\">\n {{ i18n.messages().paginator.range(rangeStart(), rangeEnd(), totalItems()) }}\n </span>\n }\n\n <div class=\"ea-paginator__controls\">\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoPrev()\"\n [aria-label]=\"i18n.messages().paginator.previousPage\"\n (clicked)=\"prevPage()\">\n <ea-icon-chevron-left />\n </ea-button>\n\n @for (p of visiblePages(); track $index) {\n @if (p === 'ellipsis') {\n <span class=\"ea-paginator__ellipsis\">\u2026</span>\n } @else {\n <ea-button\n class=\"ea-paginator__page-btn\"\n [class.ea-paginator__page-btn--active]=\"p === page()\"\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled()\"\n [aria-current]=\"p === page() ? 'page' : undefined\"\n (clicked)=\"goToPage(p)\">\n {{ p }}\n </ea-button>\n }\n }\n\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoNext()\"\n [aria-label]=\"i18n.messages().paginator.nextPage\"\n (clicked)=\"nextPage()\">\n <ea-icon-chevron-right />\n </ea-button>\n </div>\n</div>\n", styles: [".ea-paginator{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--space-4);padding:var(--space-3) var(--space-4);font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-secondary);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-paginator--left{justify-content:flex-start}.ea-paginator--center{justify-content:center}.ea-paginator__page-size{display:flex;align-items:center;gap:var(--space-2)}.ea-paginator__label{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__select{padding:var(--space-1) calc(var(--space-2) + 1rem) var(--space-1) var(--space-2);font-size:var(--font-size-sm);font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 6px center;color:var(--color-text-primary);cursor:pointer;appearance:none;transition:var(--transition-colors),var(--transition-shadow)}.ea-paginator__select:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-paginator__select:disabled{opacity:.5;cursor:not-allowed}.ea-paginator__range{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__controls{display:flex;align-items:center;gap:var(--space-1)}.ea-paginator__controls ea-icon-chevron-left,.ea-paginator__controls ea-icon-chevron-right{width:1rem;height:1rem}.ea-paginator__page-btn--active .ea-button{font-weight:var(--font-weight-medium);border-color:var(--color-brand-default);background-color:var(--color-brand-subtle);color:var(--color-brand-default)}.ea-paginator__page-btn--active .ea-button:hover:not(.ea-button--disabled){background-color:var(--color-brand-muted)}.ea-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;color:var(--color-text-tertiary);pointer-events:none;-webkit-user-select:none;user-select:none}.ea-paginator--disabled{pointer-events:none}.ea-paginator--disabled .ea-paginator__range,.ea-paginator--disabled .ea-paginator__label{opacity:.5}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "ea-button", inputs: ["variant", "size", "type", "disabled", "loading", "fullWidth", "aria-label", "aria-current"], outputs: ["clicked"] }, { kind: "component", type: ChevronLeftIconComponent, selector: "ea-icon-chevron-left" }, { kind: "component", type: ChevronRightIconComponent, selector: "ea-icon-chevron-right" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
27994
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
27995
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: TagComponent, isStandalone: true, selector: "ea-tag", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { removed: "removed" }, ngImport: i0, template: "<span\n class=\"ea-tag\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n @if (removable()) {\n <button\n type=\"button\"\n class=\"ea-tag__remove\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"resolvedRemoveLabel()\"\n (click)=\"onRemove($event)\">\n <ea-icon-x />\n </button>\n }\n</span>\n", styles: [".ea-tag{display:inline-flex;align-items:center;gap:var(--space-1);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-secondary)}.ea-tag--sm{padding:var(--space-0-5) var(--space-1-5);font-size:var(--font-size-xs)}.ea-tag--sm .ea-tag__remove ea-icon-x{width:.625rem;height:.625rem}.ea-tag--md{padding:var(--space-1) var(--space-2);font-size:var(--font-size-xs)}.ea-tag--md .ea-tag__remove ea-icon-x{width:.75rem;height:.75rem}.ea-tag--lg{padding:var(--space-1) var(--space-2-5);font-size:var(--font-size-sm)}.ea-tag--lg .ea-tag__remove ea-icon-x{width:.875rem;height:.875rem}.ea-tag--success{border-color:var(--color-success-muted);background-color:var(--color-success-subtle);color:var(--color-success-700)}.ea-tag--warning{border-color:var(--color-warning-muted);background-color:var(--color-warning-subtle);color:var(--color-warning-700)}.ea-tag--error{border-color:var(--color-error-muted);background-color:var(--color-error-subtle);color:var(--color-error-700)}.ea-tag--info{border-color:var(--color-info-muted);background-color:var(--color-info-subtle);color:var(--color-info-700)}.ea-tag--disabled{opacity:.6;cursor:not-allowed}.ea-tag__remove{opacity:.7;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;border-radius:var(--radius-xs);background:none;color:inherit;cursor:pointer;transition:var(--transition-colors)}.ea-tag__remove:hover{opacity:1}.ea-tag__remove:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-tag__remove:disabled{cursor:not-allowed}.ea-tag__remove ea-icon-x{pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: XIconComponent, selector: "ea-icon-x" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
27662
27996
  }
27663
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PaginatorComponent, decorators: [{
27997
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TagComponent, decorators: [{
27664
27998
  type: Component,
27665
- args: [{ selector: 'ea-paginator', imports: [ButtonComponent, ChevronLeftIconComponent, ChevronRightIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-paginator\"\n [class.ea-paginator--left]=\"align() === 'left'\"\n [class.ea-paginator--center]=\"align() === 'center'\"\n [class.ea-paginator--disabled]=\"disabled()\"\n role=\"navigation\"\n [attr.aria-label]=\"i18n.messages().paginator.label\">\n @if (showPageSizeSelector()) {\n <div class=\"ea-paginator__page-size\">\n <label\n class=\"ea-paginator__label\"\n for=\"ea-paginator-size\">\n {{ i18n.messages().paginator.rowsPerPage }}\n </label>\n <select\n class=\"ea-paginator__select\"\n id=\"ea-paginator-size\"\n [disabled]=\"disabled()\"\n (change)=\"onPageSizeChange($event)\">\n @for (size of pageSizeOptions(); track size) {\n <option\n [value]=\"size\"\n [selected]=\"size === pageSize()\">\n {{ size }}\n </option>\n }\n </select>\n </div>\n }\n\n @if (showRangeLabel()) {\n <span class=\"ea-paginator__range\">\n {{ i18n.messages().paginator.range(rangeStart(), rangeEnd(), totalItems()) }}\n </span>\n }\n\n <div class=\"ea-paginator__controls\">\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoPrev()\"\n [aria-label]=\"i18n.messages().paginator.previousPage\"\n (clicked)=\"prevPage()\">\n <ea-icon-chevron-left />\n </ea-button>\n\n @for (p of visiblePages(); track $index) {\n @if (p === 'ellipsis') {\n <span class=\"ea-paginator__ellipsis\">\u2026</span>\n } @else {\n <ea-button\n class=\"ea-paginator__page-btn\"\n [class.ea-paginator__page-btn--active]=\"p === page()\"\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled()\"\n [aria-current]=\"p === page() ? 'page' : undefined\"\n (clicked)=\"goToPage(p)\">\n {{ p }}\n </ea-button>\n }\n }\n\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoNext()\"\n [aria-label]=\"i18n.messages().paginator.nextPage\"\n (clicked)=\"nextPage()\">\n <ea-icon-chevron-right />\n </ea-button>\n </div>\n</div>\n", styles: [".ea-paginator{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--space-4);padding:var(--space-3) var(--space-4);font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-secondary);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-paginator--left{justify-content:flex-start}.ea-paginator--center{justify-content:center}.ea-paginator__page-size{display:flex;align-items:center;gap:var(--space-2)}.ea-paginator__label{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__select{padding:var(--space-1) calc(var(--space-2) + 1rem) var(--space-1) var(--space-2);font-size:var(--font-size-sm);font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 6px center;color:var(--color-text-primary);cursor:pointer;appearance:none;transition:var(--transition-colors),var(--transition-shadow)}.ea-paginator__select:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-paginator__select:disabled{opacity:.5;cursor:not-allowed}.ea-paginator__range{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__controls{display:flex;align-items:center;gap:var(--space-1)}.ea-paginator__controls ea-icon-chevron-left,.ea-paginator__controls ea-icon-chevron-right{width:1rem;height:1rem}.ea-paginator__page-btn--active .ea-button{font-weight:var(--font-weight-medium);border-color:var(--color-brand-default);background-color:var(--color-brand-subtle);color:var(--color-brand-default)}.ea-paginator__page-btn--active .ea-button:hover:not(.ea-button--disabled){background-color:var(--color-brand-muted)}.ea-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;color:var(--color-text-tertiary);pointer-events:none;-webkit-user-select:none;user-select:none}.ea-paginator--disabled{pointer-events:none}.ea-paginator--disabled .ea-paginator__range,.ea-paginator--disabled .ea-paginator__label{opacity:.5}\n"] }]
27666
- }], propDecorators: { totalItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalItems", required: true }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], showPageSizeSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPageSizeSelector", required: false }] }], showRangeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRangeLabel", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
27999
+ args: [{ selector: 'ea-tag', imports: [NgClass, XIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<span\n class=\"ea-tag\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n @if (removable()) {\n <button\n type=\"button\"\n class=\"ea-tag__remove\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"resolvedRemoveLabel()\"\n (click)=\"onRemove($event)\">\n <ea-icon-x />\n </button>\n }\n</span>\n", styles: [".ea-tag{display:inline-flex;align-items:center;gap:var(--space-1);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-secondary)}.ea-tag--sm{padding:var(--space-0-5) var(--space-1-5);font-size:var(--font-size-xs)}.ea-tag--sm .ea-tag__remove ea-icon-x{width:.625rem;height:.625rem}.ea-tag--md{padding:var(--space-1) var(--space-2);font-size:var(--font-size-xs)}.ea-tag--md .ea-tag__remove ea-icon-x{width:.75rem;height:.75rem}.ea-tag--lg{padding:var(--space-1) var(--space-2-5);font-size:var(--font-size-sm)}.ea-tag--lg .ea-tag__remove ea-icon-x{width:.875rem;height:.875rem}.ea-tag--success{border-color:var(--color-success-muted);background-color:var(--color-success-subtle);color:var(--color-success-700)}.ea-tag--warning{border-color:var(--color-warning-muted);background-color:var(--color-warning-subtle);color:var(--color-warning-700)}.ea-tag--error{border-color:var(--color-error-muted);background-color:var(--color-error-subtle);color:var(--color-error-700)}.ea-tag--info{border-color:var(--color-info-muted);background-color:var(--color-info-subtle);color:var(--color-info-700)}.ea-tag--disabled{opacity:.6;cursor:not-allowed}.ea-tag__remove{opacity:.7;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;border-radius:var(--radius-xs);background:none;color:inherit;cursor:pointer;transition:var(--transition-colors)}.ea-tag__remove:hover{opacity:1}.ea-tag__remove:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-tag__remove:disabled{cursor:not-allowed}.ea-tag__remove ea-icon-x{pointer-events:none}\n"] }]
28000
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], removed: [{ type: i0.Output, args: ["removed"] }] } });
27667
28001
 
27668
28002
  /**
27669
- * Linear progress indicator supporting both determinate (driven by `value`
27670
- * and `max`) and indeterminate modes. Optionally renders an inline label
27671
- * and/or the current percentage.
28003
+ * Multi-select dropdown. Renders selections as removable `<ea-tag>` chips
28004
+ * inside the trigger, opens a popover containing an optional search input,
28005
+ * a tri-state "Select all" toggle, and a list of `<ea-checkbox>` options.
28006
+ * The wire value is a `readonly string[]` of selected option values, ordered
28007
+ * to match the input `options` array. Closes on outside click / scroll, and
28008
+ * integrates with Angular forms via `ControlValueAccessor`.
27672
28009
  */
27673
- class ProgressBarComponent {
28010
+ class MultiSelectComponent {
28011
+ triggerEl = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
28012
+ searchEl = viewChild('searchEl', ...(ngDevMode ? [{ debugName: "searchEl" }] : /* istanbul ignore next */ []));
27674
28013
  i18n = inject(EagamiI18nService);
27675
- value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
27676
- max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
28014
+ injector = inject(Injector);
28015
+ // ─── Inputs ───────────────────────────────────────────────────────────
28016
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
28017
+ placeholder = input(undefined, ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
28018
+ searchPlaceholder = input(undefined, ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
28019
+ options = input([], ...(ngDevMode ? [{ debugName: "options" }] : /* istanbul ignore next */ []));
28020
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
28021
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
28022
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
28023
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
28024
+ hint = input(undefined, ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
28025
+ errorMsg = input(undefined, ...(ngDevMode ? [{ debugName: "errorMsg" }] : /* istanbul ignore next */ []));
28026
+ /** Toggle the search input at the top of the popover. */
28027
+ searchable = input(true, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
28028
+ /** Toggle the "Select all" row at the top of the option list. */
28029
+ selectAll = input(true, ...(ngDevMode ? [{ debugName: "selectAll" }] : /* istanbul ignore next */ []));
28030
+ /** Max number of chips shown inside the trigger; the rest collapse into a "+N more" pill. `0` removes the cap. */
28031
+ maxVisibleChips = input(3, ...(ngDevMode ? [{ debugName: "maxVisibleChips" }] : /* istanbul ignore next */ []));
28032
+ id = input(`ea-multi-select-${Math.random().toString(36).slice(2, 9)}`, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
28033
+ /** Selected option values, in the original options order. */
28034
+ value = model([], ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
28035
+ /** Fires with the new value whenever the selection changes. */
28036
+ changed = output();
28037
+ // ─── State ────────────────────────────────────────────────────────────
28038
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
28039
+ searchTerm = signal('', ...(ngDevMode ? [{ debugName: "searchTerm" }] : /* istanbul ignore next */ []));
28040
+ /** Index into `filteredOptions()` for keyboard navigation. `-1` when none focused. */
28041
+ focusedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "focusedIndex" }] : /* istanbul ignore next */ []));
28042
+ _formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_formDisabled" }] : /* istanbul ignore next */ []));
28043
+ onChange = () => { };
28044
+ onTouched = () => { };
28045
+ // ─── Computed ─────────────────────────────────────────────────────────
28046
+ isDisabled = computed(() => this.disabled() || this._formDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
28047
+ hasError = computed(() => !!this.errorMsg(), ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
28048
+ showError = this.hasError;
28049
+ showHint = computed(() => !!this.hint() && !this.hasError(), ...(ngDevMode ? [{ debugName: "showHint" }] : /* istanbul ignore next */ []));
28050
+ /** Set-backed lookup for `selectedSet().has(value)`. */
28051
+ selectedSet = computed(() => new Set(this.value()), ...(ngDevMode ? [{ debugName: "selectedSet" }] : /* istanbul ignore next */ []));
28052
+ /** Options matching the current search term (case-insensitive substring on label). */
28053
+ filteredOptions = computed(() => {
28054
+ const term = this.searchTerm().trim().toLowerCase();
28055
+ const opts = this.options();
28056
+ if (!term)
28057
+ return opts;
28058
+ return opts.filter(o => o.label.toLowerCase().includes(term));
28059
+ }, ...(ngDevMode ? [{ debugName: "filteredOptions" }] : /* istanbul ignore next */ []));
28060
+ /** Currently selected options, ordered to match the input `options`. */
28061
+ selectedOptions = computed(() => {
28062
+ const set = this.selectedSet();
28063
+ return this.options().filter(o => set.has(o.value));
28064
+ }, ...(ngDevMode ? [{ debugName: "selectedOptions" }] : /* istanbul ignore next */ []));
28065
+ hasValue = computed(() => this.value().length > 0, ...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
28066
+ /** Chips visible inside the trigger, capped by `maxVisibleChips`. */
28067
+ visibleChips = computed(() => {
28068
+ const sel = this.selectedOptions();
28069
+ const cap = this.maxVisibleChips();
28070
+ return cap <= 0 || sel.length <= cap ? sel : sel.slice(0, cap);
28071
+ }, ...(ngDevMode ? [{ debugName: "visibleChips" }] : /* istanbul ignore next */ []));
28072
+ /** Count behind the "+N more" pill, or `0` when all chips fit. */
28073
+ hiddenChipCount = computed(() => {
28074
+ const sel = this.selectedOptions();
28075
+ const cap = this.maxVisibleChips();
28076
+ return cap <= 0 || sel.length <= cap ? 0 : sel.length - cap;
28077
+ }, ...(ngDevMode ? [{ debugName: "hiddenChipCount" }] : /* istanbul ignore next */ []));
28078
+ /** Tri-state of the Select-all checkbox over the **currently filtered** list. */
28079
+ selectAllState = computed(() => {
28080
+ const filtered = this.filteredOptions().filter(o => !o.disabled);
28081
+ if (filtered.length === 0)
28082
+ return 'none';
28083
+ const set = this.selectedSet();
28084
+ let count = 0;
28085
+ for (const o of filtered)
28086
+ if (set.has(o.value))
28087
+ count++;
28088
+ if (count === 0)
28089
+ return 'none';
28090
+ if (count === filtered.length)
28091
+ return 'all';
28092
+ return 'some';
28093
+ }, ...(ngDevMode ? [{ debugName: "selectAllState" }] : /* istanbul ignore next */ []));
28094
+ resolvedPlaceholder = computed(() => this.placeholder() ?? this.i18n.messages().multiSelect.placeholder, ...(ngDevMode ? [{ debugName: "resolvedPlaceholder" }] : /* istanbul ignore next */ []));
28095
+ resolvedSearchPlaceholder = computed(() => this.searchPlaceholder() ?? this.i18n.messages().multiSelect.searchPlaceholder, ...(ngDevMode ? [{ debugName: "resolvedSearchPlaceholder" }] : /* istanbul ignore next */ []));
28096
+ triggerClasses = computed(() => ({
28097
+ [`ea-multi-select__trigger--${this.size()}`]: true,
28098
+ 'ea-multi-select__trigger--error': this.hasError(),
28099
+ 'ea-multi-select__trigger--open': this.isOpen(),
28100
+ 'ea-multi-select__trigger--disabled': this.isDisabled(),
28101
+ 'ea-multi-select__trigger--placeholder': !this.hasValue(),
28102
+ }), ...(ngDevMode ? [{ debugName: "triggerClasses" }] : /* istanbul ignore next */ []));
28103
+ // ─── ControlValueAccessor ─────────────────────────────────────────────
28104
+ writeValue(val) {
28105
+ this.value.set(val ?? []);
28106
+ }
28107
+ registerOnChange(fn) {
28108
+ this.onChange = fn;
28109
+ }
28110
+ registerOnTouched(fn) {
28111
+ this.onTouched = fn;
28112
+ }
28113
+ setDisabledState(isDisabled) {
28114
+ this._formDisabled.set(isDisabled);
28115
+ }
28116
+ // ─── Handlers ─────────────────────────────────────────────────────────
28117
+ toggle() {
28118
+ if (this.isDisabled() || this.readonly())
28119
+ return;
28120
+ const opening = !this.isOpen();
28121
+ this.isOpen.set(opening);
28122
+ if (opening)
28123
+ this.focusSearchWhenReady();
28124
+ else
28125
+ this.resetEditState();
28126
+ }
28127
+ close() {
28128
+ this.isOpen.set(false);
28129
+ this.resetEditState();
28130
+ }
28131
+ /** Called by `<ea-popover>` when the user clicks outside or scrolls. */
28132
+ onPopoverCloseRequested() {
28133
+ this.close();
28134
+ this.onTouched();
28135
+ }
28136
+ /** Toggle one option's membership in the selection. */
28137
+ toggleOption(opt) {
28138
+ if (this.isDisabled() || this.readonly() || opt.disabled)
28139
+ return;
28140
+ const set = new Set(this.value());
28141
+ if (set.has(opt.value))
28142
+ set.delete(opt.value);
28143
+ else
28144
+ set.add(opt.value);
28145
+ this.commit(this.orderedValues(set));
28146
+ }
28147
+ /**
28148
+ * Remove a single chip from the trigger. `<ea-tag>` already stops the
28149
+ * click from bubbling to the trigger's `(click)`, so no event handling
28150
+ * is needed here.
28151
+ */
28152
+ removeChip(opt) {
28153
+ if (this.isDisabled() || this.readonly())
28154
+ return;
28155
+ this.commit(this.value().filter(v => v !== opt.value));
28156
+ }
28157
+ /** Clear every selection via the trigger × button. */
28158
+ clear(event) {
28159
+ event.stopPropagation();
28160
+ if (this.isDisabled() || this.readonly())
28161
+ return;
28162
+ this.commit([]);
28163
+ }
28164
+ /**
28165
+ * Toggle the Select-all checkbox. If any filtered option is unselected, the
28166
+ * action selects all filtered. Otherwise, the action removes every filtered
28167
+ * value from the selection. Disabled options are skipped either way.
28168
+ */
28169
+ toggleSelectAll() {
28170
+ if (this.isDisabled() || this.readonly())
28171
+ return;
28172
+ const filteredValues = this.filteredOptions()
28173
+ .filter(o => !o.disabled)
28174
+ .map(o => o.value);
28175
+ const set = new Set(this.value());
28176
+ if (this.selectAllState() === 'all') {
28177
+ for (const v of filteredValues)
28178
+ set.delete(v);
28179
+ }
28180
+ else {
28181
+ for (const v of filteredValues)
28182
+ set.add(v);
28183
+ }
28184
+ this.commit(this.orderedValues(set));
28185
+ }
28186
+ onSearchInput(event) {
28187
+ const target = event.target;
28188
+ this.searchTerm.set(target.value);
28189
+ this.focusedIndex.set(-1);
28190
+ }
28191
+ handleTriggerKeydown(event) {
28192
+ if (this.isDisabled() || this.readonly())
28193
+ return;
28194
+ if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {
28195
+ event.preventDefault();
28196
+ if (!this.isOpen()) {
28197
+ this.isOpen.set(true);
28198
+ this.focusSearchWhenReady();
28199
+ }
28200
+ }
28201
+ else if (event.key === 'Escape' && this.isOpen()) {
28202
+ event.preventDefault();
28203
+ this.close();
28204
+ this.triggerEl()?.nativeElement.focus();
28205
+ }
28206
+ else if (event.key === 'Backspace' && this.hasValue() && !this.isOpen()) {
28207
+ // Quick-remove the last chip when the trigger is focused and no popover.
28208
+ event.preventDefault();
28209
+ this.commit(this.value().slice(0, -1));
28210
+ }
28211
+ }
28212
+ /**
28213
+ * Keyboard navigation inside the popover. Bound to both the search input
28214
+ * and each option row; Space passes through to the search input naturally
28215
+ * so users can type spaces in their query.
28216
+ */
28217
+ handlePopoverKeydown(event) {
28218
+ if (this.isDisabled() || this.readonly())
28219
+ return;
28220
+ const opts = this.filteredOptions();
28221
+ const onSearchInput = event.target === this.searchEl()?.nativeElement;
28222
+ if (event.key === 'ArrowDown') {
28223
+ event.preventDefault();
28224
+ const next = Math.min(opts.length - 1, this.focusedIndex() + 1);
28225
+ this.focusedIndex.set(next);
28226
+ }
28227
+ else if (event.key === 'ArrowUp') {
28228
+ event.preventDefault();
28229
+ const next = Math.max(0, this.focusedIndex() - 1);
28230
+ this.focusedIndex.set(next);
28231
+ }
28232
+ else if (event.key === 'Home') {
28233
+ event.preventDefault();
28234
+ this.focusedIndex.set(0);
28235
+ }
28236
+ else if (event.key === 'End') {
28237
+ event.preventDefault();
28238
+ this.focusedIndex.set(opts.length - 1);
28239
+ }
28240
+ else if (event.key === 'Enter') {
28241
+ event.preventDefault();
28242
+ const idx = this.focusedIndex();
28243
+ if (idx >= 0 && idx < opts.length)
28244
+ this.toggleOption(opts[idx]);
28245
+ }
28246
+ else if (event.key === ' ' && !onSearchInput) {
28247
+ // Toggle on Space only when an option row has focus; the search input
28248
+ // needs Space for typing.
28249
+ event.preventDefault();
28250
+ const idx = this.focusedIndex();
28251
+ if (idx >= 0 && idx < opts.length)
28252
+ this.toggleOption(opts[idx]);
28253
+ }
28254
+ else if (event.key === 'Escape') {
28255
+ event.preventDefault();
28256
+ this.close();
28257
+ this.triggerEl()?.nativeElement.focus();
28258
+ }
28259
+ }
28260
+ // ─── Internals ────────────────────────────────────────────────────────
28261
+ focusSearchWhenReady() {
28262
+ afterNextRender(() => this.searchEl()?.nativeElement.focus(), {
28263
+ injector: this.injector,
28264
+ });
28265
+ }
28266
+ /** Reorder a value-set against the input `options` array. */
28267
+ orderedValues(set) {
28268
+ return this.options()
28269
+ .filter(o => set.has(o.value))
28270
+ .map(o => o.value);
28271
+ }
28272
+ resetEditState() {
28273
+ this.searchTerm.set('');
28274
+ this.focusedIndex.set(-1);
28275
+ }
28276
+ commit(next) {
28277
+ this.value.set(next);
28278
+ this.onChange(next);
28279
+ this.onTouched();
28280
+ this.changed.emit(next);
28281
+ }
28282
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: MultiSelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28283
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: MultiSelectComponent, isStandalone: true, selector: "ea-multi-select", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, selectAll: { classPropertyName: "selectAll", publicName: "selectAll", isSignal: true, isRequired: false, transformFunction: null }, maxVisibleChips: { classPropertyName: "maxVisibleChips", publicName: "maxVisibleChips", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, providers: [
28284
+ {
28285
+ provide: NG_VALUE_ACCESSOR,
28286
+ useExisting: forwardRef(() => MultiSelectComponent),
28287
+ multi: true,
28288
+ },
28289
+ ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "searchEl", first: true, predicate: ["searchEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-multi-select-field\">\n @if (label()) {\n <label\n class=\"ea-multi-select-field__label\"\n [for]=\"id()\"\n [class.ea-multi-select-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-multi-select\">\n <div class=\"ea-multi-select__trigger-wrapper\">\n <div\n #triggerEl\n class=\"ea-multi-select__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n role=\"combobox\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <span class=\"ea-multi-select__trigger-content\">\n @if (!hasValue()) {\n <span class=\"ea-multi-select__trigger-placeholder\">\n {{ resolvedPlaceholder() }}\n </span>\n } @else {\n @for (opt of visibleChips(); track opt.value) {\n <ea-tag\n size=\"sm\"\n variant=\"default\"\n [removable]=\"!isDisabled() && !readonly()\"\n [removeLabel]=\"i18n.messages().multiSelect.removeOption(opt.label)\"\n (removed)=\"removeChip(opt)\">\n {{ opt.label }}\n </ea-tag>\n }\n @if (hiddenChipCount() > 0) {\n <span class=\"ea-multi-select__more\">+{{ hiddenChipCount() }}</span>\n }\n }\n </span>\n <ea-icon-chevron-down\n class=\"ea-multi-select__trigger-icon\"\n aria-hidden=\"true\" />\n </div>\n @if (hasValue() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-multi-select__clear\"\n [attr.aria-label]=\"i18n.messages().multiSelect.clearAll\"\n (click)=\"clear($event)\">\n <ea-icon-x\n class=\"ea-multi-select__clear-icon\"\n aria-hidden=\"true\" />\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"listbox\"\n [matchAnchorWidth]=\"true\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"reposition\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div class=\"ea-multi-select__popover\">\n @if (searchable()) {\n <div class=\"ea-multi-select__search\">\n <ea-icon-search\n class=\"ea-multi-select__search-icon\"\n aria-hidden=\"true\" />\n <input\n #searchEl\n type=\"text\"\n class=\"ea-multi-select__search-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedSearchPlaceholder()\"\n [value]=\"searchTerm()\"\n (input)=\"onSearchInput($event)\"\n (keydown)=\"handlePopoverKeydown($event)\" />\n </div>\n }\n\n @if (selectAll() && filteredOptions().length > 0) {\n <div\n class=\"ea-multi-select__option ea-multi-select__option--select-all\"\n (click)=\"toggleSelectAll()\">\n <ea-checkbox\n size=\"sm\"\n [checked]=\"selectAllState() === 'all'\"\n [indeterminate]=\"selectAllState() === 'some'\"\n [ariaLabel]=\"i18n.messages().multiSelect.selectAll\" />\n <span class=\"ea-multi-select__option-label\">\n {{ i18n.messages().multiSelect.selectAll }}\n </span>\n </div>\n }\n\n <ul\n class=\"ea-multi-select__list\"\n role=\"presentation\">\n @for (opt of filteredOptions(); track opt.value; let i = $index) {\n <li\n class=\"ea-multi-select__option\"\n [class.ea-multi-select__option--focused]=\"focusedIndex() === i\"\n [class.ea-multi-select__option--disabled]=\"opt.disabled\"\n role=\"option\"\n tabindex=\"-1\"\n [attr.aria-selected]=\"selectedSet().has(opt.value)\"\n [attr.aria-disabled]=\"opt.disabled || null\"\n (click)=\"toggleOption(opt)\"\n (keydown)=\"handlePopoverKeydown($event)\">\n <ea-checkbox\n size=\"sm\"\n [checked]=\"selectedSet().has(opt.value)\"\n [disabled]=\"!!opt.disabled\"\n [ariaLabel]=\"opt.label\" />\n <span class=\"ea-multi-select__option-label\">\n {{ opt.label }}\n </span>\n </li>\n } @empty {\n <li class=\"ea-multi-select__empty\">\n {{ i18n.messages().multiSelect.searchEmpty }}\n </li>\n }\n </ul>\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-multi-select-field__message ea-multi-select-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-multi-select-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-multi-select-field__message ea-multi-select-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-multi-select-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-multi-select-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-multi-select-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-multi-select-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-multi-select-field__message--hint{color:var(--color-text-secondary)}.ea-multi-select-field__message--error{color:var(--color-error-default)}.ea-multi-select-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-multi-select,.ea-multi-select__trigger-wrapper{position:relative}.ea-multi-select__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-multi-select__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-multi-select__trigger--sm{padding:var(--space-1) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-multi-select__trigger--md{padding:var(--space-1-5) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-multi-select__trigger--lg{padding:var(--space-2) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-multi-select__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-multi-select__trigger--error{border-color:var(--color-error-default)}.ea-multi-select__trigger--error.ea-multi-select__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-multi-select__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-multi-select__trigger-content{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-1);flex:1;min-width:0}.ea-multi-select__trigger-placeholder{color:var(--color-text-tertiary)}.ea-multi-select__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary);transition:var(--transition-transform)}.ea-multi-select__trigger--open .ea-multi-select__trigger-icon{transform:rotate(180deg)}.ea-multi-select__more{display:inline-flex;align-items:center;padding:0 var(--space-1-5);border-radius:var(--radius-lg);background-color:var(--color-bg-muted);font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);color:var(--color-text-secondary)}.ea-multi-select__clear{position:absolute;top:50%;right:var(--space-7);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-multi-select__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-multi-select__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-multi-select__clear-icon{width:.875em;height:.875em}.ea-multi-select__popover{display:flex;flex-direction:column;overflow:hidden;max-height:20rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-multi-select__search{display:flex;align-items:center;gap:var(--space-2);flex-shrink:0;padding:var(--space-2) var(--space-3);border-bottom:var(--border-width-thin) solid var(--color-border-default)}.ea-multi-select__search-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-tertiary)}.ea-multi-select__search-input{flex:1;min-width:0;padding:0;border:none;background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-primary)}.ea-multi-select__search-input::placeholder{color:var(--color-text-tertiary);opacity:1}.ea-multi-select__search-input:focus{outline:none}.ea-multi-select__list{overflow-y:auto;flex:1;margin:0;padding:var(--space-1) 0;list-style:none}.ea-multi-select__option{display:flex;align-items:center;gap:var(--space-2);padding:var(--space-1-5) var(--space-3);font-size:var(--font-size-sm);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-multi-select__option--focused{background-color:var(--color-bg-muted)}.ea-multi-select__option--disabled{color:var(--color-text-disabled);cursor:not-allowed}.ea-multi-select__option--select-all{border-bottom:var(--border-width-thin) solid var(--color-border-default);font-weight:var(--font-weight-medium)}.ea-multi-select__option:hover:not(.ea-multi-select__option--disabled){background-color:var(--color-bg-muted)}.ea-multi-select__option ea-checkbox{pointer-events:none;display:inline-flex;align-items:center;line-height:1}.ea-multi-select__option-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-multi-select__empty{padding:var(--space-3);font-size:var(--font-size-sm);text-align:center;color:var(--color-text-tertiary);list-style:none}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: CheckboxComponent, selector: "ea-checkbox", inputs: ["label", "count", "hint", "errorMsg", "size", "disabled", "required", "indeterminate", "aria-label", "id", "checked"], outputs: ["checkedChange", "changed"] }, { kind: "component", type: ChevronDownIconComponent, selector: "ea-icon-chevron-down" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PopoverComponent, selector: "ea-popover", inputs: ["anchor", "open", "placement", "role", "aria-label", "surfaceId", "offset", "flip", "clamp", "matchAnchorWidth", "closeOnOutsideClick", "closeOnEscape", "scrollBehavior"], outputs: ["closeRequested"] }, { kind: "component", type: SearchIconComponent, selector: "ea-icon-search" }, { kind: "component", type: TagComponent, selector: "ea-tag", inputs: ["variant", "size", "removable", "disabled", "removeLabel"], outputs: ["removed"] }, { kind: "component", type: XIconComponent, selector: "ea-icon-x" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
28290
+ }
28291
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: MultiSelectComponent, decorators: [{
28292
+ type: Component,
28293
+ args: [{ selector: 'ea-multi-select', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
28294
+ AlertCircleIconComponent,
28295
+ CheckboxComponent,
28296
+ ChevronDownIconComponent,
28297
+ NgClass,
28298
+ PopoverComponent,
28299
+ SearchIconComponent,
28300
+ TagComponent,
28301
+ XIconComponent,
28302
+ ], providers: [
28303
+ {
28304
+ provide: NG_VALUE_ACCESSOR,
28305
+ useExisting: forwardRef(() => MultiSelectComponent),
28306
+ multi: true,
28307
+ },
28308
+ ], template: "<div class=\"ea-multi-select-field\">\n @if (label()) {\n <label\n class=\"ea-multi-select-field__label\"\n [for]=\"id()\"\n [class.ea-multi-select-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-multi-select\">\n <div class=\"ea-multi-select__trigger-wrapper\">\n <div\n #triggerEl\n class=\"ea-multi-select__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n role=\"combobox\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <span class=\"ea-multi-select__trigger-content\">\n @if (!hasValue()) {\n <span class=\"ea-multi-select__trigger-placeholder\">\n {{ resolvedPlaceholder() }}\n </span>\n } @else {\n @for (opt of visibleChips(); track opt.value) {\n <ea-tag\n size=\"sm\"\n variant=\"default\"\n [removable]=\"!isDisabled() && !readonly()\"\n [removeLabel]=\"i18n.messages().multiSelect.removeOption(opt.label)\"\n (removed)=\"removeChip(opt)\">\n {{ opt.label }}\n </ea-tag>\n }\n @if (hiddenChipCount() > 0) {\n <span class=\"ea-multi-select__more\">+{{ hiddenChipCount() }}</span>\n }\n }\n </span>\n <ea-icon-chevron-down\n class=\"ea-multi-select__trigger-icon\"\n aria-hidden=\"true\" />\n </div>\n @if (hasValue() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-multi-select__clear\"\n [attr.aria-label]=\"i18n.messages().multiSelect.clearAll\"\n (click)=\"clear($event)\">\n <ea-icon-x\n class=\"ea-multi-select__clear-icon\"\n aria-hidden=\"true\" />\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"listbox\"\n [matchAnchorWidth]=\"true\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"reposition\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div class=\"ea-multi-select__popover\">\n @if (searchable()) {\n <div class=\"ea-multi-select__search\">\n <ea-icon-search\n class=\"ea-multi-select__search-icon\"\n aria-hidden=\"true\" />\n <input\n #searchEl\n type=\"text\"\n class=\"ea-multi-select__search-input\"\n autocomplete=\"off\"\n [placeholder]=\"resolvedSearchPlaceholder()\"\n [value]=\"searchTerm()\"\n (input)=\"onSearchInput($event)\"\n (keydown)=\"handlePopoverKeydown($event)\" />\n </div>\n }\n\n @if (selectAll() && filteredOptions().length > 0) {\n <div\n class=\"ea-multi-select__option ea-multi-select__option--select-all\"\n (click)=\"toggleSelectAll()\">\n <ea-checkbox\n size=\"sm\"\n [checked]=\"selectAllState() === 'all'\"\n [indeterminate]=\"selectAllState() === 'some'\"\n [ariaLabel]=\"i18n.messages().multiSelect.selectAll\" />\n <span class=\"ea-multi-select__option-label\">\n {{ i18n.messages().multiSelect.selectAll }}\n </span>\n </div>\n }\n\n <ul\n class=\"ea-multi-select__list\"\n role=\"presentation\">\n @for (opt of filteredOptions(); track opt.value; let i = $index) {\n <li\n class=\"ea-multi-select__option\"\n [class.ea-multi-select__option--focused]=\"focusedIndex() === i\"\n [class.ea-multi-select__option--disabled]=\"opt.disabled\"\n role=\"option\"\n tabindex=\"-1\"\n [attr.aria-selected]=\"selectedSet().has(opt.value)\"\n [attr.aria-disabled]=\"opt.disabled || null\"\n (click)=\"toggleOption(opt)\"\n (keydown)=\"handlePopoverKeydown($event)\">\n <ea-checkbox\n size=\"sm\"\n [checked]=\"selectedSet().has(opt.value)\"\n [disabled]=\"!!opt.disabled\"\n [ariaLabel]=\"opt.label\" />\n <span class=\"ea-multi-select__option-label\">\n {{ opt.label }}\n </span>\n </li>\n } @empty {\n <li class=\"ea-multi-select__empty\">\n {{ i18n.messages().multiSelect.searchEmpty }}\n </li>\n }\n </ul>\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-multi-select-field__message ea-multi-select-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-multi-select-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-multi-select-field__message ea-multi-select-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-multi-select-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-multi-select-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-multi-select-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-multi-select-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-multi-select-field__message--hint{color:var(--color-text-secondary)}.ea-multi-select-field__message--error{color:var(--color-error-default)}.ea-multi-select-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-multi-select,.ea-multi-select__trigger-wrapper{position:relative}.ea-multi-select__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-multi-select__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-multi-select__trigger--sm{padding:var(--space-1) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-multi-select__trigger--md{padding:var(--space-1-5) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-multi-select__trigger--lg{padding:var(--space-2) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-multi-select__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-multi-select__trigger--error{border-color:var(--color-error-default)}.ea-multi-select__trigger--error.ea-multi-select__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-multi-select__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-multi-select__trigger-content{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-1);flex:1;min-width:0}.ea-multi-select__trigger-placeholder{color:var(--color-text-tertiary)}.ea-multi-select__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary);transition:var(--transition-transform)}.ea-multi-select__trigger--open .ea-multi-select__trigger-icon{transform:rotate(180deg)}.ea-multi-select__more{display:inline-flex;align-items:center;padding:0 var(--space-1-5);border-radius:var(--radius-lg);background-color:var(--color-bg-muted);font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);color:var(--color-text-secondary)}.ea-multi-select__clear{position:absolute;top:50%;right:var(--space-7);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-multi-select__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-multi-select__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-multi-select__clear-icon{width:.875em;height:.875em}.ea-multi-select__popover{display:flex;flex-direction:column;overflow:hidden;max-height:20rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-multi-select__search{display:flex;align-items:center;gap:var(--space-2);flex-shrink:0;padding:var(--space-2) var(--space-3);border-bottom:var(--border-width-thin) solid var(--color-border-default)}.ea-multi-select__search-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-tertiary)}.ea-multi-select__search-input{flex:1;min-width:0;padding:0;border:none;background:none;font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-primary)}.ea-multi-select__search-input::placeholder{color:var(--color-text-tertiary);opacity:1}.ea-multi-select__search-input:focus{outline:none}.ea-multi-select__list{overflow-y:auto;flex:1;margin:0;padding:var(--space-1) 0;list-style:none}.ea-multi-select__option{display:flex;align-items:center;gap:var(--space-2);padding:var(--space-1-5) var(--space-3);font-size:var(--font-size-sm);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors)}.ea-multi-select__option--focused{background-color:var(--color-bg-muted)}.ea-multi-select__option--disabled{color:var(--color-text-disabled);cursor:not-allowed}.ea-multi-select__option--select-all{border-bottom:var(--border-width-thin) solid var(--color-border-default);font-weight:var(--font-weight-medium)}.ea-multi-select__option:hover:not(.ea-multi-select__option--disabled){background-color:var(--color-bg-muted)}.ea-multi-select__option ea-checkbox{pointer-events:none;display:inline-flex;align-items:center;line-height:1}.ea-multi-select__option-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ea-multi-select__empty{padding:var(--space-3);font-size:var(--font-size-sm);text-align:center;color:var(--color-text-tertiary);list-style:none}\n"] }]
28309
+ }], propDecorators: { triggerEl: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], searchEl: [{ type: i0.ViewChild, args: ['searchEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], selectAll: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectAll", required: false }] }], maxVisibleChips: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxVisibleChips", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
28310
+
28311
+ /**
28312
+ * Page navigation control with previous/next buttons, numbered page jumps,
28313
+ * an optional page-size selector, and a range label. Exposes `page` and
28314
+ * `pageSize` as two-way `model()` bindings and emits a single `changed`
28315
+ * event whenever either changes.
28316
+ */
28317
+ class PaginatorComponent {
28318
+ i18n = inject(EagamiI18nService);
28319
+ totalItems = input.required(...(ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []));
28320
+ pageSizeOptions = input([10, 25, 50, 100], ...(ngDevMode ? [{ debugName: "pageSizeOptions" }] : /* istanbul ignore next */ []));
28321
+ showPageSizeSelector = input(true, ...(ngDevMode ? [{ debugName: "showPageSizeSelector" }] : /* istanbul ignore next */ []));
28322
+ showRangeLabel = input(true, ...(ngDevMode ? [{ debugName: "showRangeLabel" }] : /* istanbul ignore next */ []));
28323
+ align = input('right', ...(ngDevMode ? [{ debugName: "align" }] : /* istanbul ignore next */ []));
28324
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
28325
+ page = model(1, ...(ngDevMode ? [{ debugName: "page" }] : /* istanbul ignore next */ []));
28326
+ pageSize = model(10, ...(ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []));
28327
+ /** Fires when the user changes either the current page or the page size. */
28328
+ changed = output();
28329
+ totalPages = computed(() => Math.max(1, Math.ceil(this.totalItems() / this.pageSize())), ...(ngDevMode ? [{ debugName: "totalPages" }] : /* istanbul ignore next */ []));
28330
+ rangeStart = computed(() => this.totalItems() === 0 ? 0 : (this.page() - 1) * this.pageSize() + 1, ...(ngDevMode ? [{ debugName: "rangeStart" }] : /* istanbul ignore next */ []));
28331
+ rangeEnd = computed(() => Math.min(this.page() * this.pageSize(), this.totalItems()), ...(ngDevMode ? [{ debugName: "rangeEnd" }] : /* istanbul ignore next */ []));
28332
+ canGoPrev = computed(() => this.page() > 1, ...(ngDevMode ? [{ debugName: "canGoPrev" }] : /* istanbul ignore next */ []));
28333
+ canGoNext = computed(() => this.page() < this.totalPages(), ...(ngDevMode ? [{ debugName: "canGoNext" }] : /* istanbul ignore next */ []));
28334
+ visiblePages = computed(() => {
28335
+ const total = this.totalPages();
28336
+ const current = this.page();
28337
+ const pages = [];
28338
+ if (total <= 7) {
28339
+ for (let i = 1; i <= total; i++)
28340
+ pages.push(i);
28341
+ return pages;
28342
+ }
28343
+ pages.push(1);
28344
+ if (current > 3) {
28345
+ pages.push('ellipsis');
28346
+ }
28347
+ const start = Math.max(2, current - 1);
28348
+ const end = Math.min(total - 1, current + 1);
28349
+ for (let i = start; i <= end; i++) {
28350
+ pages.push(i);
28351
+ }
28352
+ if (current < total - 2) {
28353
+ pages.push('ellipsis');
28354
+ }
28355
+ pages.push(total);
28356
+ return pages;
28357
+ }, ...(ngDevMode ? [{ debugName: "visiblePages" }] : /* istanbul ignore next */ []));
28358
+ /** Navigates to the given page, clamped into the valid range. */
28359
+ goToPage(page) {
28360
+ if (this.disabled())
28361
+ return;
28362
+ const clamped = Math.max(1, Math.min(page, this.totalPages()));
28363
+ if (clamped === this.page())
28364
+ return;
28365
+ this.page.set(clamped);
28366
+ this.changed.emit({ page: clamped, pageSize: this.pageSize() });
28367
+ }
28368
+ /** Navigates to the previous page if one exists. */
28369
+ prevPage() {
28370
+ if (this.canGoPrev())
28371
+ this.goToPage(this.page() - 1);
28372
+ }
28373
+ /** Navigates to the next page if one exists. */
28374
+ nextPage() {
28375
+ if (this.canGoNext())
28376
+ this.goToPage(this.page() + 1);
28377
+ }
28378
+ onPageSizeChange(event) {
28379
+ if (this.disabled())
28380
+ return;
28381
+ const newSize = Number(event.target.value);
28382
+ this.pageSize.set(newSize);
28383
+ this.page.set(1);
28384
+ this.changed.emit({ page: 1, pageSize: newSize });
28385
+ }
28386
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PaginatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28387
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: PaginatorComponent, isStandalone: true, selector: "ea-paginator", inputs: { totalItems: { classPropertyName: "totalItems", publicName: "totalItems", isSignal: true, isRequired: true, transformFunction: null }, pageSizeOptions: { classPropertyName: "pageSizeOptions", publicName: "pageSizeOptions", isSignal: true, isRequired: false, transformFunction: null }, showPageSizeSelector: { classPropertyName: "showPageSizeSelector", publicName: "showPageSizeSelector", isSignal: true, isRequired: false, transformFunction: null }, showRangeLabel: { classPropertyName: "showRangeLabel", publicName: "showRangeLabel", isSignal: true, isRequired: false, transformFunction: null }, align: { classPropertyName: "align", publicName: "align", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, page: { classPropertyName: "page", publicName: "page", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { page: "pageChange", pageSize: "pageSizeChange", changed: "changed" }, ngImport: i0, template: "<div\n class=\"ea-paginator\"\n [class.ea-paginator--left]=\"align() === 'left'\"\n [class.ea-paginator--center]=\"align() === 'center'\"\n [class.ea-paginator--disabled]=\"disabled()\"\n role=\"navigation\"\n [attr.aria-label]=\"i18n.messages().paginator.label\">\n @if (showPageSizeSelector()) {\n <div class=\"ea-paginator__page-size\">\n <label\n class=\"ea-paginator__label\"\n for=\"ea-paginator-size\">\n {{ i18n.messages().paginator.rowsPerPage }}\n </label>\n <select\n class=\"ea-paginator__select\"\n id=\"ea-paginator-size\"\n [disabled]=\"disabled()\"\n (change)=\"onPageSizeChange($event)\">\n @for (size of pageSizeOptions(); track size) {\n <option\n [value]=\"size\"\n [selected]=\"size === pageSize()\">\n {{ size }}\n </option>\n }\n </select>\n </div>\n }\n\n @if (showRangeLabel()) {\n <span class=\"ea-paginator__range\">\n {{ i18n.messages().paginator.range(rangeStart(), rangeEnd(), totalItems()) }}\n </span>\n }\n\n <div class=\"ea-paginator__controls\">\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoPrev()\"\n [aria-label]=\"i18n.messages().paginator.previousPage\"\n (clicked)=\"prevPage()\">\n <ea-icon-chevron-left />\n </ea-button>\n\n @for (p of visiblePages(); track $index) {\n @if (p === 'ellipsis') {\n <span class=\"ea-paginator__ellipsis\">\u2026</span>\n } @else {\n <ea-button\n class=\"ea-paginator__page-btn\"\n [class.ea-paginator__page-btn--active]=\"p === page()\"\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled()\"\n [aria-current]=\"p === page() ? 'page' : undefined\"\n (clicked)=\"goToPage(p)\">\n {{ p }}\n </ea-button>\n }\n }\n\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoNext()\"\n [aria-label]=\"i18n.messages().paginator.nextPage\"\n (clicked)=\"nextPage()\">\n <ea-icon-chevron-right />\n </ea-button>\n </div>\n</div>\n", styles: [".ea-paginator{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--space-4);padding:var(--space-3) var(--space-4);font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-secondary);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-paginator--left{justify-content:flex-start}.ea-paginator--center{justify-content:center}.ea-paginator__page-size{display:flex;align-items:center;gap:var(--space-2)}.ea-paginator__label{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__select{padding:var(--space-1) calc(var(--space-2) + 1rem) var(--space-1) var(--space-2);font-size:var(--font-size-sm);font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 6px center;color:var(--color-text-primary);cursor:pointer;appearance:none;transition:var(--transition-colors),var(--transition-shadow)}.ea-paginator__select:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-paginator__select:disabled{opacity:.5;cursor:not-allowed}.ea-paginator__range{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__controls{display:flex;align-items:center;gap:var(--space-1)}.ea-paginator__controls ea-icon-chevron-left,.ea-paginator__controls ea-icon-chevron-right{width:1rem;height:1rem}.ea-paginator__page-btn--active .ea-button{font-weight:var(--font-weight-medium);border-color:var(--color-brand-default);background-color:var(--color-brand-subtle);color:var(--color-brand-default)}.ea-paginator__page-btn--active .ea-button:hover:not(.ea-button--disabled){background-color:var(--color-brand-muted)}.ea-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;color:var(--color-text-tertiary);pointer-events:none;-webkit-user-select:none;user-select:none}.ea-paginator--disabled{pointer-events:none}.ea-paginator--disabled .ea-paginator__range,.ea-paginator--disabled .ea-paginator__label{opacity:.5}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "ea-button", inputs: ["variant", "size", "type", "disabled", "loading", "fullWidth", "aria-label", "aria-current"], outputs: ["clicked"] }, { kind: "component", type: ChevronLeftIconComponent, selector: "ea-icon-chevron-left" }, { kind: "component", type: ChevronRightIconComponent, selector: "ea-icon-chevron-right" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
28388
+ }
28389
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: PaginatorComponent, decorators: [{
28390
+ type: Component,
28391
+ args: [{ selector: 'ea-paginator', imports: [ButtonComponent, ChevronLeftIconComponent, ChevronRightIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-paginator\"\n [class.ea-paginator--left]=\"align() === 'left'\"\n [class.ea-paginator--center]=\"align() === 'center'\"\n [class.ea-paginator--disabled]=\"disabled()\"\n role=\"navigation\"\n [attr.aria-label]=\"i18n.messages().paginator.label\">\n @if (showPageSizeSelector()) {\n <div class=\"ea-paginator__page-size\">\n <label\n class=\"ea-paginator__label\"\n for=\"ea-paginator-size\">\n {{ i18n.messages().paginator.rowsPerPage }}\n </label>\n <select\n class=\"ea-paginator__select\"\n id=\"ea-paginator-size\"\n [disabled]=\"disabled()\"\n (change)=\"onPageSizeChange($event)\">\n @for (size of pageSizeOptions(); track size) {\n <option\n [value]=\"size\"\n [selected]=\"size === pageSize()\">\n {{ size }}\n </option>\n }\n </select>\n </div>\n }\n\n @if (showRangeLabel()) {\n <span class=\"ea-paginator__range\">\n {{ i18n.messages().paginator.range(rangeStart(), rangeEnd(), totalItems()) }}\n </span>\n }\n\n <div class=\"ea-paginator__controls\">\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoPrev()\"\n [aria-label]=\"i18n.messages().paginator.previousPage\"\n (clicked)=\"prevPage()\">\n <ea-icon-chevron-left />\n </ea-button>\n\n @for (p of visiblePages(); track $index) {\n @if (p === 'ellipsis') {\n <span class=\"ea-paginator__ellipsis\">\u2026</span>\n } @else {\n <ea-button\n class=\"ea-paginator__page-btn\"\n [class.ea-paginator__page-btn--active]=\"p === page()\"\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled()\"\n [aria-current]=\"p === page() ? 'page' : undefined\"\n (clicked)=\"goToPage(p)\">\n {{ p }}\n </ea-button>\n }\n }\n\n <ea-button\n variant=\"ghost\"\n size=\"sm\"\n [disabled]=\"disabled() || !canGoNext()\"\n [aria-label]=\"i18n.messages().paginator.nextPage\"\n (clicked)=\"nextPage()\">\n <ea-icon-chevron-right />\n </ea-button>\n </div>\n</div>\n", styles: [".ea-paginator{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--space-4);padding:var(--space-3) var(--space-4);font-family:var(--font-family-sans);font-size:var(--font-size-sm);color:var(--color-text-secondary);border-top:var(--border-width-thin) solid var(--color-border-default)}.ea-paginator--left{justify-content:flex-start}.ea-paginator--center{justify-content:center}.ea-paginator__page-size{display:flex;align-items:center;gap:var(--space-2)}.ea-paginator__label{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__select{padding:var(--space-1) calc(var(--space-2) + 1rem) var(--space-1) var(--space-2);font-size:var(--font-size-sm);font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);background-color:var(--color-bg-base);background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:right 6px center;color:var(--color-text-primary);cursor:pointer;appearance:none;transition:var(--transition-colors),var(--transition-shadow)}.ea-paginator__select:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-paginator__select:disabled{opacity:.5;cursor:not-allowed}.ea-paginator__range{white-space:nowrap;color:var(--color-text-secondary)}.ea-paginator__controls{display:flex;align-items:center;gap:var(--space-1)}.ea-paginator__controls ea-icon-chevron-left,.ea-paginator__controls ea-icon-chevron-right{width:1rem;height:1rem}.ea-paginator__page-btn--active .ea-button{font-weight:var(--font-weight-medium);border-color:var(--color-brand-default);background-color:var(--color-brand-subtle);color:var(--color-brand-default)}.ea-paginator__page-btn--active .ea-button:hover:not(.ea-button--disabled){background-color:var(--color-brand-muted)}.ea-paginator__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:2rem;height:2rem;color:var(--color-text-tertiary);pointer-events:none;-webkit-user-select:none;user-select:none}.ea-paginator--disabled{pointer-events:none}.ea-paginator--disabled .ea-paginator__range,.ea-paginator--disabled .ea-paginator__label{opacity:.5}\n"] }]
28392
+ }], propDecorators: { totalItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "totalItems", required: true }] }], pageSizeOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSizeOptions", required: false }] }], showPageSizeSelector: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPageSizeSelector", required: false }] }], showRangeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRangeLabel", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], page: [{ type: i0.Input, args: [{ isSignal: true, alias: "page", required: false }] }, { type: i0.Output, args: ["pageChange"] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
28393
+
28394
+ /**
28395
+ * Linear progress indicator supporting both determinate (driven by `value`
28396
+ * and `max`) and indeterminate modes. Optionally renders an inline label
28397
+ * and/or the current percentage.
28398
+ */
28399
+ class ProgressBarComponent {
28400
+ i18n = inject(EagamiI18nService);
28401
+ value = input(0, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
28402
+ max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
27677
28403
  variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
27678
28404
  size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
27679
28405
  label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
@@ -27808,6 +28534,213 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
27808
28534
  args: [{ selector: 'ea-radio', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgClass], template: "<label\n class=\"ea-radio\"\n [ngClass]=\"hostClasses()\"\n [for]=\"id()\">\n <input\n type=\"radio\"\n class=\"ea-radio__input\"\n [id]=\"id()\"\n [name]=\"name()\"\n [value]=\"value()\"\n [checked]=\"isChecked()\"\n [disabled]=\"isDisabled()\"\n (change)=\"handleChange()\" />\n\n <span\n class=\"ea-radio__circle\"\n aria-hidden=\"true\">\n </span>\n\n @if (label()) {\n <span class=\"ea-radio__label\">{{ label() }}</span>\n }\n</label>\n", styles: [".ea-radio{display:inline-flex;align-items:center;gap:var(--space-2);cursor:pointer;-webkit-user-select:none;user-select:none;font-family:var(--font-family-sans);color:var(--color-text-primary)}.ea-radio--sm .ea-radio__circle{width:1rem;height:1rem}.ea-radio--sm .ea-radio__label{font-size:var(--font-size-sm);line-height:1rem}.ea-radio--md .ea-radio__circle{width:1.25rem;height:1.25rem}.ea-radio--md .ea-radio__label{font-size:var(--font-size-sm);line-height:1.25rem}.ea-radio--lg .ea-radio__circle{width:1.5rem;height:1.5rem}.ea-radio--lg .ea-radio__label{font-size:var(--font-size-md);line-height:1.5rem}.ea-radio--disabled{opacity:.45;cursor:not-allowed}.ea-radio--checked .ea-radio__circle{border-color:var(--color-brand-default)}.ea-radio--checked .ea-radio__circle:after{transform:scale(1)}.ea-radio:hover:not(.ea-radio--disabled) .ea-radio__circle{border-color:var(--color-brand-default)}.ea-radio__input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.ea-radio__input:focus-visible+.ea-radio__circle{box-shadow:var(--shadow-focus-ring)}.ea-radio__circle{display:flex;align-items:center;justify-content:center;flex-shrink:0;border-radius:var(--radius-full);background-color:var(--color-bg-base);border:var(--border-width-medium) solid var(--color-border-strong);transition:var(--transition-colors),var(--transition-shadow)}.ea-radio__circle:after{content:\"\";display:block;width:45%;height:45%;border-radius:var(--radius-full);background-color:var(--color-brand-default);transform:scale(0);transition:var(--transition-transform)}.ea-radio__label{font-weight:var(--font-weight-regular)}\n"] }]
27809
28535
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
27810
28536
 
28537
+ /**
28538
+ * Two-thumb extension of `<ea-slider>`. Drives a `[low, high]` numeric range
28539
+ * with pointer drag (the closer thumb to the pointer responds) and full
28540
+ * keyboard navigation per thumb (arrows / PageUp / PageDown / Home / End).
28541
+ * Tab moves between thumbs. Configurable `min`, `max`, `step`, optional value
28542
+ * display, and integrates with Angular forms via `ControlValueAccessor`.
28543
+ *
28544
+ * Overlap rule: a thumb cannot cross past the other; once it reaches the
28545
+ * opposite thumb's position, it clamps to that boundary. Drag-induced
28546
+ * overlap (where the user yanks the low thumb past the high) is resolved by
28547
+ * keeping the moving thumb on its side and the other thumb pinned.
28548
+ */
28549
+ class RangeSliderComponent {
28550
+ trackEl = viewChild('trackEl', ...(ngDevMode ? [{ debugName: "trackEl" }] : /* istanbul ignore next */ []));
28551
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
28552
+ hint = input(undefined, ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
28553
+ errorMsg = input(undefined, ...(ngDevMode ? [{ debugName: "errorMsg" }] : /* istanbul ignore next */ []));
28554
+ min = input(0, ...(ngDevMode ? [{ debugName: "min" }] : /* istanbul ignore next */ []));
28555
+ max = input(100, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
28556
+ step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : /* istanbul ignore next */ []));
28557
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
28558
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
28559
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
28560
+ showValue = input(false, ...(ngDevMode ? [{ debugName: "showValue" }] : /* istanbul ignore next */ []));
28561
+ showMinMaxLabels = input(false, ...(ngDevMode ? [{ debugName: "showMinMaxLabels" }] : /* istanbul ignore next */ []));
28562
+ formatValue = input(value => `${value}`, ...(ngDevMode ? [{ debugName: "formatValue" }] : /* istanbul ignore next */ []));
28563
+ /** Accessible label for the low (start) thumb. Falls back to the field label when omitted. */
28564
+ ariaLabelLow = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabelLow" } : /* istanbul ignore next */ {}), alias: 'aria-label-low' });
28565
+ /** Accessible label for the high (end) thumb. Falls back to the field label when omitted. */
28566
+ ariaLabelHigh = input(undefined, { ...(ngDevMode ? { debugName: "ariaLabelHigh" } : /* istanbul ignore next */ {}), alias: 'aria-label-high' });
28567
+ id = input(`ea-range-slider-${Math.random().toString(36).slice(2, 9)}`, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
28568
+ value = model([0, 100], ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
28569
+ /** Fires with the new `[low, high]` tuple whenever either thumb moves. */
28570
+ changed = output();
28571
+ _formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_formDisabled" }] : /* istanbul ignore next */ []));
28572
+ dragging = signal(null, ...(ngDevMode ? [{ debugName: "dragging" }] : /* istanbul ignore next */ []));
28573
+ onChange = () => { };
28574
+ onTouched = () => { };
28575
+ isDisabled = computed(() => this.disabled() || this._formDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
28576
+ /** Clamped, ordered `[low, high]` tuple — `low <= high`, both within `[min, max]`. */
28577
+ clampedValue = computed(() => {
28578
+ const [a, b] = this.value();
28579
+ const min = this.min();
28580
+ const max = this.max();
28581
+ const lo = Math.min(max, Math.max(min, Math.min(a, b)));
28582
+ const hi = Math.min(max, Math.max(min, Math.max(a, b)));
28583
+ return [lo, hi];
28584
+ }, ...(ngDevMode ? [{ debugName: "clampedValue" }] : /* istanbul ignore next */ []));
28585
+ lowPercent = computed(() => this.toPercent(this.clampedValue()[0]), ...(ngDevMode ? [{ debugName: "lowPercent" }] : /* istanbul ignore next */ []));
28586
+ highPercent = computed(() => this.toPercent(this.clampedValue()[1]), ...(ngDevMode ? [{ debugName: "highPercent" }] : /* istanbul ignore next */ []));
28587
+ hasError = computed(() => !!this.errorMsg(), ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
28588
+ showError = this.hasError;
28589
+ showHint = computed(() => !!this.hint() && !this.hasError(), ...(ngDevMode ? [{ debugName: "showHint" }] : /* istanbul ignore next */ []));
28590
+ hostClasses = computed(() => ({
28591
+ [`ea-range-slider--${this.size()}`]: true,
28592
+ 'ea-range-slider--error': this.hasError(),
28593
+ 'ea-range-slider--disabled': this.isDisabled(),
28594
+ 'ea-range-slider--dragging': this.dragging() !== null,
28595
+ }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
28596
+ // ─── ControlValueAccessor ───────────────────────────────────────────────
28597
+ writeValue(val) {
28598
+ if (Array.isArray(val) && val.length === 2) {
28599
+ const [a, b] = val;
28600
+ const safeA = typeof a === 'number' && !isNaN(a) ? a : this.min();
28601
+ const safeB = typeof b === 'number' && !isNaN(b) ? b : this.max();
28602
+ this.value.set([safeA, safeB]);
28603
+ }
28604
+ else {
28605
+ this.value.set([this.min(), this.max()]);
28606
+ }
28607
+ }
28608
+ registerOnChange(fn) {
28609
+ this.onChange = fn;
28610
+ }
28611
+ registerOnTouched(fn) {
28612
+ this.onTouched = fn;
28613
+ }
28614
+ setDisabledState(isDisabled) {
28615
+ this._formDisabled.set(isDisabled);
28616
+ }
28617
+ // ─── Keyboard ───────────────────────────────────────────────────────────
28618
+ handleKeydown(event, thumb) {
28619
+ if (this.isDisabled())
28620
+ return;
28621
+ const [lo, hi] = this.clampedValue();
28622
+ const current = thumb === 'low' ? lo : hi;
28623
+ const step = this.step();
28624
+ const bigStep = Math.max(step * 10, (this.max() - this.min()) / 10);
28625
+ let next;
28626
+ switch (event.key) {
28627
+ case 'ArrowRight':
28628
+ case 'ArrowUp':
28629
+ next = current + step;
28630
+ break;
28631
+ case 'ArrowLeft':
28632
+ case 'ArrowDown':
28633
+ next = current - step;
28634
+ break;
28635
+ case 'PageUp':
28636
+ next = current + bigStep;
28637
+ break;
28638
+ case 'PageDown':
28639
+ next = current - bigStep;
28640
+ break;
28641
+ case 'Home':
28642
+ next = this.min();
28643
+ break;
28644
+ case 'End':
28645
+ next = this.max();
28646
+ break;
28647
+ default:
28648
+ return;
28649
+ }
28650
+ event.preventDefault();
28651
+ this.commitThumb(thumb, next);
28652
+ }
28653
+ handleBlur() {
28654
+ this.onTouched();
28655
+ }
28656
+ // ─── Pointer ────────────────────────────────────────────────────────────
28657
+ handleTrackPointerDown(event) {
28658
+ if (this.isDisabled())
28659
+ return;
28660
+ const track = this.trackEl()?.nativeElement;
28661
+ if (!track)
28662
+ return;
28663
+ // Pick whichever thumb is closer to the pointer's track-relative ratio,
28664
+ // breaking ties toward the low thumb. Then begin dragging that thumb.
28665
+ const raw = this.pointerToValue(event, track);
28666
+ const [lo, hi] = this.clampedValue();
28667
+ const target = Math.abs(raw - lo) <= Math.abs(raw - hi) ? 'low' : 'high';
28668
+ event.target.setPointerCapture?.(event.pointerId);
28669
+ this.dragging.set(target);
28670
+ this.commitThumb(target, raw);
28671
+ }
28672
+ handleTrackPointerMove(event) {
28673
+ const active = this.dragging();
28674
+ if (!active || this.isDisabled())
28675
+ return;
28676
+ const track = this.trackEl()?.nativeElement;
28677
+ if (!track)
28678
+ return;
28679
+ this.commitThumb(active, this.pointerToValue(event, track));
28680
+ }
28681
+ handleTrackPointerUp(event) {
28682
+ if (!this.dragging())
28683
+ return;
28684
+ event.target.releasePointerCapture?.(event.pointerId);
28685
+ this.dragging.set(null);
28686
+ this.onTouched();
28687
+ }
28688
+ // ─── Internals ──────────────────────────────────────────────────────────
28689
+ toPercent(value) {
28690
+ const range = this.max() - this.min();
28691
+ if (range <= 0)
28692
+ return 0;
28693
+ return ((value - this.min()) / range) * 100;
28694
+ }
28695
+ pointerToValue(event, track) {
28696
+ const rect = track.getBoundingClientRect();
28697
+ const ratio = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width));
28698
+ return this.min() + ratio * (this.max() - this.min());
28699
+ }
28700
+ /** Snap to step, clamp to `[min, max]`, then constrain by the opposite thumb. */
28701
+ commitThumb(thumb, raw) {
28702
+ const step = this.step();
28703
+ const min = this.min();
28704
+ const max = this.max();
28705
+ const snapped = Math.round((raw - min) / step) * step + min;
28706
+ const clamped = Math.min(max, Math.max(min, snapped));
28707
+ const rounded = Number(clamped.toFixed(10));
28708
+ const [lo, hi] = this.clampedValue();
28709
+ let nextLo = lo;
28710
+ let nextHi = hi;
28711
+ if (thumb === 'low') {
28712
+ nextLo = Math.min(rounded, hi);
28713
+ }
28714
+ else {
28715
+ nextHi = Math.max(rounded, lo);
28716
+ }
28717
+ if (nextLo === lo && nextHi === hi)
28718
+ return;
28719
+ const next = [nextLo, nextHi];
28720
+ this.value.set(next);
28721
+ this.onChange(next);
28722
+ this.changed.emit(next);
28723
+ }
28724
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RangeSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28725
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: RangeSliderComponent, isStandalone: true, selector: "ea-range-slider", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, showMinMaxLabels: { classPropertyName: "showMinMaxLabels", publicName: "showMinMaxLabels", isSignal: true, isRequired: false, transformFunction: null }, formatValue: { classPropertyName: "formatValue", publicName: "formatValue", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelLow: { classPropertyName: "ariaLabelLow", publicName: "aria-label-low", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelHigh: { classPropertyName: "ariaLabelHigh", publicName: "aria-label-high", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, providers: [
28726
+ {
28727
+ provide: NG_VALUE_ACCESSOR,
28728
+ useExisting: forwardRef(() => RangeSliderComponent),
28729
+ multi: true,
28730
+ },
28731
+ ], viewQueries: [{ propertyName: "trackEl", first: true, predicate: ["trackEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ea-range-slider-field\"\n [ngClass]=\"hostClasses()\">\n @if (label()) {\n <span\n class=\"ea-range-slider-field__label\"\n [id]=\"id() + '-label'\"\n [class.ea-range-slider-field__label--required]=\"required()\">\n {{ label() }}\n @if (showValue()) {\n <span class=\"ea-range-slider-field__value\">\n {{ formatValue()(clampedValue()[0]) }} \u2013 {{ formatValue()(clampedValue()[1]) }}\n </span>\n }\n </span>\n }\n\n <div class=\"ea-range-slider\">\n <div\n #trackEl\n class=\"ea-range-slider__track\"\n (pointerdown)=\"handleTrackPointerDown($event)\"\n (pointermove)=\"handleTrackPointerMove($event)\"\n (pointerup)=\"handleTrackPointerUp($event)\"\n (pointercancel)=\"handleTrackPointerUp($event)\">\n <div\n class=\"ea-range-slider__fill\"\n [style.left.%]=\"lowPercent()\"\n [style.right.%]=\"100 - highPercent()\">\n </div>\n <div\n class=\"ea-range-slider__thumb ea-range-slider__thumb--low\"\n role=\"slider\"\n tabindex=\"0\"\n [id]=\"id() + '-low'\"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-label]=\"!label() ? (ariaLabelLow() ?? null) : null\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"clampedValue()[1]\"\n [attr.aria-valuenow]=\"clampedValue()[0]\"\n [attr.aria-valuetext]=\"formatValue()(clampedValue()[0])\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n [style.left.%]=\"lowPercent()\"\n (keydown)=\"handleKeydown($event, 'low')\"\n (blur)=\"handleBlur()\">\n </div>\n <div\n class=\"ea-range-slider__thumb ea-range-slider__thumb--high\"\n role=\"slider\"\n tabindex=\"0\"\n [id]=\"id() + '-high'\"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-label]=\"!label() ? (ariaLabelHigh() ?? null) : null\"\n [attr.aria-valuemin]=\"clampedValue()[0]\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"clampedValue()[1]\"\n [attr.aria-valuetext]=\"formatValue()(clampedValue()[1])\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n [style.left.%]=\"highPercent()\"\n (keydown)=\"handleKeydown($event, 'high')\"\n (blur)=\"handleBlur()\">\n </div>\n </div>\n\n @if (showMinMaxLabels()) {\n <div class=\"ea-range-slider__minmax\">\n <span class=\"ea-range-slider__minmax-label\">\n {{ formatValue()(min()) }}\n </span>\n <span class=\"ea-range-slider__minmax-label\">\n {{ formatValue()(max()) }}\n </span>\n </div>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-range-slider-field__message ea-range-slider-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-range-slider-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-range-slider-field__message ea-range-slider-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-range-slider-field{display:flex;flex-direction:column;gap:var(--space-2);font-family:var(--font-family-sans);color:var(--color-text-secondary)}.ea-range-slider-field__label{display:flex;justify-content:space-between;align-items:baseline;gap:var(--space-2);font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-range-slider-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-range-slider-field__value{font-variant-numeric:tabular-nums;font-weight:var(--font-weight-medium);color:var(--color-text-secondary)}.ea-range-slider-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-range-slider-field__message--hint{color:inherit}.ea-range-slider-field__message--error{color:var(--color-error-default)}.ea-range-slider-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-range-slider{display:flex;flex-direction:column;gap:var(--space-1);width:100%}.ea-range-slider--sm .ea-range-slider .ea-range-slider__track{height:.25rem}.ea-range-slider--sm .ea-range-slider .ea-range-slider__thumb{width:.875rem;height:.875rem}.ea-range-slider--md .ea-range-slider .ea-range-slider__track{height:.375rem}.ea-range-slider--md .ea-range-slider .ea-range-slider__thumb{width:1.125rem;height:1.125rem}.ea-range-slider--lg .ea-range-slider .ea-range-slider__track{height:.5rem}.ea-range-slider--lg .ea-range-slider .ea-range-slider__thumb{width:1.375rem;height:1.375rem}.ea-range-slider__track{position:relative;width:100%;background-color:var(--color-bg-muted);border-radius:var(--radius-full);cursor:pointer;touch-action:none}.ea-range-slider__fill{position:absolute;top:0;height:100%;background-color:var(--color-brand-default);border-radius:inherit;transition:var(--transition-colors)}.ea-range-slider__thumb{position:absolute;top:50%;background-color:var(--color-neutral-0);border:var(--border-width-medium) solid var(--color-brand-default);border-radius:var(--radius-full);box-shadow:var(--shadow-sm);cursor:grab;transform:translate(-50%,-50%);transition:box-shadow var(--duration-fast) var(--ease-out),transform var(--duration-fast) var(--ease-out)}.ea-range-slider__thumb:focus-visible{z-index:1;box-shadow:var(--shadow-focus-ring);outline:none}.ea-range-slider__minmax{display:flex;justify-content:space-between;margin-top:var(--space-1)}.ea-range-slider__minmax-label{font-size:var(--font-size-xs);color:var(--color-text-tertiary);font-variant-numeric:tabular-nums}.ea-range-slider--dragging .ea-range-slider__thumb{cursor:grabbing;transform:translate(-50%,-50%) scale(1.1)}.ea-range-slider--disabled{opacity:.5;cursor:not-allowed}.ea-range-slider--disabled .ea-range-slider__track,.ea-range-slider--disabled .ea-range-slider__thumb{cursor:not-allowed}.ea-range-slider--error .ea-range-slider__fill{background-color:var(--color-error-default)}.ea-range-slider--error .ea-range-slider__thumb{border-color:var(--color-error-default)}.ea-range-slider--error .ea-range-slider__thumb:focus-visible{box-shadow:var(--shadow-focus-ring-error)}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
28732
+ }
28733
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: RangeSliderComponent, decorators: [{
28734
+ type: Component,
28735
+ args: [{ selector: 'ea-range-slider', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AlertCircleIconComponent, NgClass], providers: [
28736
+ {
28737
+ provide: NG_VALUE_ACCESSOR,
28738
+ useExisting: forwardRef(() => RangeSliderComponent),
28739
+ multi: true,
28740
+ },
28741
+ ], template: "<div\n class=\"ea-range-slider-field\"\n [ngClass]=\"hostClasses()\">\n @if (label()) {\n <span\n class=\"ea-range-slider-field__label\"\n [id]=\"id() + '-label'\"\n [class.ea-range-slider-field__label--required]=\"required()\">\n {{ label() }}\n @if (showValue()) {\n <span class=\"ea-range-slider-field__value\">\n {{ formatValue()(clampedValue()[0]) }} \u2013 {{ formatValue()(clampedValue()[1]) }}\n </span>\n }\n </span>\n }\n\n <div class=\"ea-range-slider\">\n <div\n #trackEl\n class=\"ea-range-slider__track\"\n (pointerdown)=\"handleTrackPointerDown($event)\"\n (pointermove)=\"handleTrackPointerMove($event)\"\n (pointerup)=\"handleTrackPointerUp($event)\"\n (pointercancel)=\"handleTrackPointerUp($event)\">\n <div\n class=\"ea-range-slider__fill\"\n [style.left.%]=\"lowPercent()\"\n [style.right.%]=\"100 - highPercent()\">\n </div>\n <div\n class=\"ea-range-slider__thumb ea-range-slider__thumb--low\"\n role=\"slider\"\n tabindex=\"0\"\n [id]=\"id() + '-low'\"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-label]=\"!label() ? (ariaLabelLow() ?? null) : null\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"clampedValue()[1]\"\n [attr.aria-valuenow]=\"clampedValue()[0]\"\n [attr.aria-valuetext]=\"formatValue()(clampedValue()[0])\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n [style.left.%]=\"lowPercent()\"\n (keydown)=\"handleKeydown($event, 'low')\"\n (blur)=\"handleBlur()\">\n </div>\n <div\n class=\"ea-range-slider__thumb ea-range-slider__thumb--high\"\n role=\"slider\"\n tabindex=\"0\"\n [id]=\"id() + '-high'\"\n [attr.aria-labelledby]=\"label() ? id() + '-label' : null\"\n [attr.aria-label]=\"!label() ? (ariaLabelHigh() ?? null) : null\"\n [attr.aria-valuemin]=\"clampedValue()[0]\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"clampedValue()[1]\"\n [attr.aria-valuetext]=\"formatValue()(clampedValue()[1])\"\n [attr.aria-disabled]=\"isDisabled() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n [style.left.%]=\"highPercent()\"\n (keydown)=\"handleKeydown($event, 'high')\"\n (blur)=\"handleBlur()\">\n </div>\n </div>\n\n @if (showMinMaxLabels()) {\n <div class=\"ea-range-slider__minmax\">\n <span class=\"ea-range-slider__minmax-label\">\n {{ formatValue()(min()) }}\n </span>\n <span class=\"ea-range-slider__minmax-label\">\n {{ formatValue()(max()) }}\n </span>\n </div>\n }\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-range-slider-field__message ea-range-slider-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-range-slider-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-range-slider-field__message ea-range-slider-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-range-slider-field{display:flex;flex-direction:column;gap:var(--space-2);font-family:var(--font-family-sans);color:var(--color-text-secondary)}.ea-range-slider-field__label{display:flex;justify-content:space-between;align-items:baseline;gap:var(--space-2);font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-range-slider-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-range-slider-field__value{font-variant-numeric:tabular-nums;font-weight:var(--font-weight-medium);color:var(--color-text-secondary)}.ea-range-slider-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-range-slider-field__message--hint{color:inherit}.ea-range-slider-field__message--error{color:var(--color-error-default)}.ea-range-slider-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-range-slider{display:flex;flex-direction:column;gap:var(--space-1);width:100%}.ea-range-slider--sm .ea-range-slider .ea-range-slider__track{height:.25rem}.ea-range-slider--sm .ea-range-slider .ea-range-slider__thumb{width:.875rem;height:.875rem}.ea-range-slider--md .ea-range-slider .ea-range-slider__track{height:.375rem}.ea-range-slider--md .ea-range-slider .ea-range-slider__thumb{width:1.125rem;height:1.125rem}.ea-range-slider--lg .ea-range-slider .ea-range-slider__track{height:.5rem}.ea-range-slider--lg .ea-range-slider .ea-range-slider__thumb{width:1.375rem;height:1.375rem}.ea-range-slider__track{position:relative;width:100%;background-color:var(--color-bg-muted);border-radius:var(--radius-full);cursor:pointer;touch-action:none}.ea-range-slider__fill{position:absolute;top:0;height:100%;background-color:var(--color-brand-default);border-radius:inherit;transition:var(--transition-colors)}.ea-range-slider__thumb{position:absolute;top:50%;background-color:var(--color-neutral-0);border:var(--border-width-medium) solid var(--color-brand-default);border-radius:var(--radius-full);box-shadow:var(--shadow-sm);cursor:grab;transform:translate(-50%,-50%);transition:box-shadow var(--duration-fast) var(--ease-out),transform var(--duration-fast) var(--ease-out)}.ea-range-slider__thumb:focus-visible{z-index:1;box-shadow:var(--shadow-focus-ring);outline:none}.ea-range-slider__minmax{display:flex;justify-content:space-between;margin-top:var(--space-1)}.ea-range-slider__minmax-label{font-size:var(--font-size-xs);color:var(--color-text-tertiary);font-variant-numeric:tabular-nums}.ea-range-slider--dragging .ea-range-slider__thumb{cursor:grabbing;transform:translate(-50%,-50%) scale(1.1)}.ea-range-slider--disabled{opacity:.5;cursor:not-allowed}.ea-range-slider--disabled .ea-range-slider__track,.ea-range-slider--disabled .ea-range-slider__thumb{cursor:not-allowed}.ea-range-slider--error .ea-range-slider__fill{background-color:var(--color-error-default)}.ea-range-slider--error .ea-range-slider__thumb{border-color:var(--color-error-default)}.ea-range-slider--error .ea-range-slider__thumb:focus-visible{box-shadow:var(--shadow-focus-ring-error)}\n"] }]
28742
+ }], propDecorators: { trackEl: [{ type: i0.ViewChild, args: ['trackEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], showMinMaxLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMinMaxLabels", required: false }] }], formatValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatValue", required: false }] }], ariaLabelLow: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label-low", required: false }] }], ariaLabelHigh: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label-high", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
28743
+
27811
28744
  /**
27812
28745
  * Compact toggle button group for picking one of a small set of options
27813
28746
  * (e.g. List/Grid/Kanban or Light/Dark). Implements `radiogroup` semantics
@@ -28106,26 +29039,219 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
28106
29039
  }], propDecorators: { trackEl: [{ type: i0.ViewChild, args: ['trackEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], showMinMaxLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showMinMaxLabels", required: false }] }], formatValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatValue", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "aria-label", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
28107
29040
 
28108
29041
  /**
28109
- * SVG loading indicator with an accessible `role="status"`. The `label` input
28110
- * overrides the accessible name announced to assistive technology; when unset
28111
- * it falls back to the active locale's translation.
29042
+ * SVG loading indicator with an accessible `role="status"`. The `label` input
29043
+ * overrides the accessible name announced to assistive technology; when unset
29044
+ * it falls back to the active locale's translation.
29045
+ */
29046
+ class SpinnerComponent {
29047
+ i18n = inject(EagamiI18nService);
29048
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
29049
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
29050
+ /** Accessible label, falling back to the active locale's translation. */
29051
+ resolvedLabel = computed(() => this.label() ?? this.i18n.messages().spinner.label, ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
29052
+ hostClasses = computed(() => ({
29053
+ [`ea-spinner--${this.size()}`]: true,
29054
+ }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
29055
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29056
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: SpinnerComponent, isStandalone: true, selector: "ea-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"ea-spinner\"\n [ngClass]=\"hostClasses()\"\n role=\"status\">\n <svg\n class=\"ea-spinner__circle\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n opacity=\"0.25\" />\n <path\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\" />\n </svg>\n <span class=\"ea-spinner__label\">{{ resolvedLabel() }}</span>\n</div>\n", styles: [".ea-spinner{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--color-brand-default)}.ea-spinner--sm .ea-spinner__circle{width:1rem;height:1rem}.ea-spinner--sm .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--md .ea-spinner__circle{width:1.5rem;height:1.5rem}.ea-spinner--md .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--lg .ea-spinner__circle{width:2rem;height:2rem}.ea-spinner--lg .ea-spinner__label{font-size:var(--font-size-md)}.ea-spinner__circle{animation:ea-spin .75s linear infinite}@media(prefers-reduced-motion:reduce){.ea-spinner__circle{animation-duration:2.5s}}.ea-spinner__label{font-family:var(--font-family-sans);color:var(--color-text-secondary);line-height:var(--line-height-normal)}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
29057
+ }
29058
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SpinnerComponent, decorators: [{
29059
+ type: Component,
29060
+ args: [{ selector: 'ea-spinner', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-spinner\"\n [ngClass]=\"hostClasses()\"\n role=\"status\">\n <svg\n class=\"ea-spinner__circle\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n opacity=\"0.25\" />\n <path\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\" />\n </svg>\n <span class=\"ea-spinner__label\">{{ resolvedLabel() }}</span>\n</div>\n", styles: [".ea-spinner{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--color-brand-default)}.ea-spinner--sm .ea-spinner__circle{width:1rem;height:1rem}.ea-spinner--sm .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--md .ea-spinner__circle{width:1.5rem;height:1.5rem}.ea-spinner--md .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--lg .ea-spinner__circle{width:2rem;height:2rem}.ea-spinner--lg .ea-spinner__label{font-size:var(--font-size-md)}.ea-spinner__circle{animation:ea-spin .75s linear infinite}@media(prefers-reduced-motion:reduce){.ea-spinner__circle{animation-duration:2.5s}}.ea-spinner__label{font-family:var(--font-family-sans);color:var(--color-text-secondary);line-height:var(--line-height-normal)}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
29061
+ }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
29062
+
29063
+ /**
29064
+ * Multi-step navigation paired with content panels. Child `<ea-step>`
29065
+ * components register themselves automatically and the active panel is
29066
+ * shown based on the `activeStep` (zero-based index) two-way binding.
29067
+ *
29068
+ * In `linear` mode, steps cannot be navigated to until all earlier
29069
+ * non-optional steps are marked `completed`. Otherwise any step can be
29070
+ * clicked. ArrowLeft / ArrowRight walk through reachable steps; Home/End
29071
+ * jump to the extremes.
29072
+ */
29073
+ class StepperComponent {
29074
+ i18n = inject(EagamiI18nService);
29075
+ registeredSteps = signal([], ...(ngDevMode ? [{ debugName: "registeredSteps" }] : /* istanbul ignore next */ []));
29076
+ // ─── Inputs ───────────────────────────────────────────────────────────
29077
+ activeStep = model(0, ...(ngDevMode ? [{ debugName: "activeStep" }] : /* istanbul ignore next */ []));
29078
+ linear = input(false, ...(ngDevMode ? [{ debugName: "linear" }] : /* istanbul ignore next */ []));
29079
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
29080
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
29081
+ id = input(`ea-stepper-${Math.random().toString(36).slice(2, 9)}`, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
29082
+ // ─── Outputs ──────────────────────────────────────────────────────────
29083
+ /** Fires with the new active step index when the user navigates. */
29084
+ changed = output();
29085
+ // ─── Computed ─────────────────────────────────────────────────────────
29086
+ hostClasses = computed(() => ({
29087
+ [`ea-stepper--${this.size()}`]: true,
29088
+ 'ea-stepper--disabled': this.disabled(),
29089
+ }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
29090
+ // ─── Registration ─────────────────────────────────────────────────────
29091
+ registerStep(step) {
29092
+ this.registeredSteps.update(steps => [...steps, step]);
29093
+ }
29094
+ unregisterStep(step) {
29095
+ this.registeredSteps.update(steps => steps.filter(s => s !== step));
29096
+ }
29097
+ /** Returns the index of a given step, or `-1` if it isn't registered. */
29098
+ indexOf(step) {
29099
+ return this.registeredSteps().indexOf(step);
29100
+ }
29101
+ // ─── Navigation ───────────────────────────────────────────────────────
29102
+ /**
29103
+ * True when the user can navigate directly to the step at `index`. In
29104
+ * non-linear mode this is true for any non-disabled step; in linear mode,
29105
+ * every non-optional earlier step must also be marked `completed`.
29106
+ */
29107
+ canNavigateTo(index) {
29108
+ if (this.disabled())
29109
+ return false;
29110
+ const steps = this.registeredSteps();
29111
+ if (index < 0 || index >= steps.length)
29112
+ return false;
29113
+ if (steps[index].disabled())
29114
+ return false;
29115
+ if (!this.linear())
29116
+ return true;
29117
+ if (index <= this.activeStep())
29118
+ return true;
29119
+ for (let i = 0; i < index; i++) {
29120
+ const step = steps[i];
29121
+ if (!step.completed() && !step.optional())
29122
+ return false;
29123
+ }
29124
+ return true;
29125
+ }
29126
+ /** Activate the step at `index` if reachable. */
29127
+ selectStep(index) {
29128
+ if (!this.canNavigateTo(index))
29129
+ return;
29130
+ if (index === this.activeStep())
29131
+ return;
29132
+ this.activeStep.set(index);
29133
+ this.changed.emit(index);
29134
+ }
29135
+ handleKeydown(event) {
29136
+ if (this.disabled())
29137
+ return;
29138
+ const steps = this.registeredSteps();
29139
+ if (steps.length === 0)
29140
+ return;
29141
+ let nextIndex = -1;
29142
+ if (event.key === 'ArrowRight') {
29143
+ event.preventDefault();
29144
+ nextIndex = this.nextReachable(this.activeStep(), 1);
29145
+ }
29146
+ else if (event.key === 'ArrowLeft') {
29147
+ event.preventDefault();
29148
+ nextIndex = this.nextReachable(this.activeStep(), -1);
29149
+ }
29150
+ else if (event.key === 'Home') {
29151
+ event.preventDefault();
29152
+ nextIndex = this.firstReachable();
29153
+ }
29154
+ else if (event.key === 'End') {
29155
+ event.preventDefault();
29156
+ nextIndex = this.lastReachable();
29157
+ }
29158
+ if (nextIndex >= 0 && nextIndex !== this.activeStep()) {
29159
+ this.selectStep(nextIndex);
29160
+ const buttons = event.currentTarget.querySelectorAll('.ea-stepper__button:not([disabled])');
29161
+ // Match the focused button to the new index (visit order matches DOM order).
29162
+ const reachableIndices = this.registeredSteps()
29163
+ .map((_, i) => i)
29164
+ .filter(i => this.canNavigateTo(i));
29165
+ const buttonIdx = reachableIndices.indexOf(nextIndex);
29166
+ buttons[buttonIdx]?.focus();
29167
+ }
29168
+ }
29169
+ // ─── Internals ────────────────────────────────────────────────────────
29170
+ nextReachable(from, direction) {
29171
+ const steps = this.registeredSteps();
29172
+ for (let i = from + direction; i >= 0 && i < steps.length; i += direction) {
29173
+ if (this.canNavigateTo(i))
29174
+ return i;
29175
+ }
29176
+ return -1;
29177
+ }
29178
+ firstReachable() {
29179
+ const steps = this.registeredSteps();
29180
+ for (let i = 0; i < steps.length; i++) {
29181
+ if (this.canNavigateTo(i))
29182
+ return i;
29183
+ }
29184
+ return -1;
29185
+ }
29186
+ lastReachable() {
29187
+ const steps = this.registeredSteps();
29188
+ for (let i = steps.length - 1; i >= 0; i--) {
29189
+ if (this.canNavigateTo(i))
29190
+ return i;
29191
+ }
29192
+ return -1;
29193
+ }
29194
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: StepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29195
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: StepperComponent, isStandalone: true, selector: "ea-stepper", inputs: { activeStep: { classPropertyName: "activeStep", publicName: "activeStep", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeStep: "activeStepChange", changed: "changed" }, ngImport: i0, template: "<div\n class=\"ea-stepper\"\n [ngClass]=\"hostClasses()\">\n <ol\n class=\"ea-stepper__list\"\n role=\"tablist\"\n (keydown)=\"handleKeydown($event)\">\n @for (step of registeredSteps(); let i = $index; track step) {\n <li class=\"ea-stepper__item\">\n <button\n type=\"button\"\n role=\"tab\"\n class=\"ea-stepper__button\"\n [class.ea-stepper__button--active]=\"i === activeStep()\"\n [class.ea-stepper__button--completed]=\"step.completed()\"\n [id]=\"step.id() + '-tab'\"\n [attr.aria-controls]=\"step.id() + '-panel'\"\n [attr.aria-selected]=\"i === activeStep()\"\n [attr.aria-current]=\"i === activeStep() ? 'step' : null\"\n [disabled]=\"!canNavigateTo(i)\"\n [tabindex]=\"i === activeStep() ? 0 : -1\"\n (click)=\"selectStep(i)\">\n <span\n class=\"ea-stepper__circle\"\n aria-hidden=\"true\">\n @if (step.completed()) {\n <ea-icon-check />\n } @else {\n {{ i + 1 }}\n }\n </span>\n <span class=\"ea-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <span class=\"ea-stepper__optional\">\n ({{ i18n.messages().stepper.optional }})\n </span>\n }\n </span>\n </button>\n @if (i < registeredSteps().length - 1) {\n <span\n class=\"ea-stepper__connector\"\n [class.ea-stepper__connector--completed]=\"step.completed()\"\n aria-hidden=\"true\">\n </span>\n }\n </li>\n }\n </ol>\n <ng-content />\n</div>\n", styles: [".ea-stepper{display:flex;flex-direction:column;gap:var(--space-4)}.ea-stepper__list{display:flex;align-items:stretch;gap:var(--space-2);margin:0;padding:0;list-style:none}.ea-stepper__item{display:flex;align-items:center;flex:1;min-width:0}.ea-stepper__button{display:flex;align-items:center;gap:var(--space-2);flex-shrink:0;padding:0;border:none;background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-stepper__button:focus-visible{outline:none}.ea-stepper__button:focus-visible .ea-stepper__circle{box-shadow:var(--shadow-focus-ring)}.ea-stepper__button:hover:not(:disabled){color:var(--color-text-primary)}.ea-stepper__button:disabled{cursor:not-allowed;color:var(--color-text-disabled)}.ea-stepper__circle{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2rem;height:2rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-full);background-color:var(--color-bg-base);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);transition:var(--transition-colors)}.ea-stepper__circle ea-icon-check{width:.875em;height:.875em}.ea-stepper__button--active .ea-stepper__circle,.ea-stepper__button--completed .ea-stepper__circle{border-color:var(--color-brand-default);background-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-stepper__button:disabled .ea-stepper__circle{border-color:var(--color-border-default);background-color:var(--color-bg-muted);color:var(--color-text-disabled)}.ea-stepper__label{display:flex;flex-direction:column;align-items:flex-start;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);text-align:left;line-height:var(--line-height-tight)}.ea-stepper__button--active .ea-stepper__label{color:var(--color-text-primary)}.ea-stepper__optional{font-size:var(--font-size-xs);font-weight:var(--font-weight-regular);color:var(--color-text-tertiary)}.ea-stepper__connector{display:block;flex:1;align-self:center;min-width:var(--space-4);height:var(--border-width-thin);margin:0 var(--space-2);background-color:var(--color-border-default);transition:var(--transition-colors)}.ea-stepper__connector--completed{background-color:var(--color-brand-default)}.ea-stepper--sm .ea-stepper__circle{width:1.5rem;height:1.5rem;font-size:var(--font-size-xs)}.ea-stepper--sm .ea-stepper__label{font-size:var(--font-size-xs)}.ea-stepper--lg .ea-stepper__circle{width:2.5rem;height:2.5rem;font-size:var(--font-size-md)}.ea-stepper--lg .ea-stepper__label{font-size:var(--font-size-md)}.ea-stepper--disabled{opacity:.6;pointer-events:none}.ea-step__panel:focus-visible{outline:none}\n"], dependencies: [{ kind: "component", type: CheckIconComponent, selector: "ea-icon-check" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29196
+ }
29197
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: StepperComponent, decorators: [{
29198
+ type: Component,
29199
+ args: [{ selector: 'ea-stepper', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CheckIconComponent, NgClass], template: "<div\n class=\"ea-stepper\"\n [ngClass]=\"hostClasses()\">\n <ol\n class=\"ea-stepper__list\"\n role=\"tablist\"\n (keydown)=\"handleKeydown($event)\">\n @for (step of registeredSteps(); let i = $index; track step) {\n <li class=\"ea-stepper__item\">\n <button\n type=\"button\"\n role=\"tab\"\n class=\"ea-stepper__button\"\n [class.ea-stepper__button--active]=\"i === activeStep()\"\n [class.ea-stepper__button--completed]=\"step.completed()\"\n [id]=\"step.id() + '-tab'\"\n [attr.aria-controls]=\"step.id() + '-panel'\"\n [attr.aria-selected]=\"i === activeStep()\"\n [attr.aria-current]=\"i === activeStep() ? 'step' : null\"\n [disabled]=\"!canNavigateTo(i)\"\n [tabindex]=\"i === activeStep() ? 0 : -1\"\n (click)=\"selectStep(i)\">\n <span\n class=\"ea-stepper__circle\"\n aria-hidden=\"true\">\n @if (step.completed()) {\n <ea-icon-check />\n } @else {\n {{ i + 1 }}\n }\n </span>\n <span class=\"ea-stepper__label\">\n {{ step.label() }}\n @if (step.optional()) {\n <span class=\"ea-stepper__optional\">\n ({{ i18n.messages().stepper.optional }})\n </span>\n }\n </span>\n </button>\n @if (i < registeredSteps().length - 1) {\n <span\n class=\"ea-stepper__connector\"\n [class.ea-stepper__connector--completed]=\"step.completed()\"\n aria-hidden=\"true\">\n </span>\n }\n </li>\n }\n </ol>\n <ng-content />\n</div>\n", styles: [".ea-stepper{display:flex;flex-direction:column;gap:var(--space-4)}.ea-stepper__list{display:flex;align-items:stretch;gap:var(--space-2);margin:0;padding:0;list-style:none}.ea-stepper__item{display:flex;align-items:center;flex:1;min-width:0}.ea-stepper__button{display:flex;align-items:center;gap:var(--space-2);flex-shrink:0;padding:0;border:none;background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-stepper__button:focus-visible{outline:none}.ea-stepper__button:focus-visible .ea-stepper__circle{box-shadow:var(--shadow-focus-ring)}.ea-stepper__button:hover:not(:disabled){color:var(--color-text-primary)}.ea-stepper__button:disabled{cursor:not-allowed;color:var(--color-text-disabled)}.ea-stepper__circle{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2rem;height:2rem;border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-full);background-color:var(--color-bg-base);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);transition:var(--transition-colors)}.ea-stepper__circle ea-icon-check{width:.875em;height:.875em}.ea-stepper__button--active .ea-stepper__circle,.ea-stepper__button--completed .ea-stepper__circle{border-color:var(--color-brand-default);background-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-stepper__button:disabled .ea-stepper__circle{border-color:var(--color-border-default);background-color:var(--color-bg-muted);color:var(--color-text-disabled)}.ea-stepper__label{display:flex;flex-direction:column;align-items:flex-start;font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);text-align:left;line-height:var(--line-height-tight)}.ea-stepper__button--active .ea-stepper__label{color:var(--color-text-primary)}.ea-stepper__optional{font-size:var(--font-size-xs);font-weight:var(--font-weight-regular);color:var(--color-text-tertiary)}.ea-stepper__connector{display:block;flex:1;align-self:center;min-width:var(--space-4);height:var(--border-width-thin);margin:0 var(--space-2);background-color:var(--color-border-default);transition:var(--transition-colors)}.ea-stepper__connector--completed{background-color:var(--color-brand-default)}.ea-stepper--sm .ea-stepper__circle{width:1.5rem;height:1.5rem;font-size:var(--font-size-xs)}.ea-stepper--sm .ea-stepper__label{font-size:var(--font-size-xs)}.ea-stepper--lg .ea-stepper__circle{width:2.5rem;height:2.5rem;font-size:var(--font-size-md)}.ea-stepper--lg .ea-stepper__label{font-size:var(--font-size-md)}.ea-stepper--disabled{opacity:.6;pointer-events:none}.ea-step__panel:focus-visible{outline:none}\n"] }]
29200
+ }], propDecorators: { activeStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeStep", required: false }] }, { type: i0.Output, args: ["activeStepChange"] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
29201
+
29202
+ /**
29203
+ * Single step within an `<ea-stepper>`. Registers itself with the parent on
29204
+ * init, exposes its `label` / `completed` / `optional` flags, and shows its
29205
+ * projected content when active.
28112
29206
  */
28113
- class SpinnerComponent {
28114
- i18n = inject(EagamiI18nService);
28115
- size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
28116
- label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
28117
- /** Accessible label, falling back to the active locale's translation. */
28118
- resolvedLabel = computed(() => this.label() ?? this.i18n.messages().spinner.label, ...(ngDevMode ? [{ debugName: "resolvedLabel" }] : /* istanbul ignore next */ []));
28119
- hostClasses = computed(() => ({
28120
- [`ea-spinner--${this.size()}`]: true,
28121
- }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
28122
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28123
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: SpinnerComponent, isStandalone: true, selector: "ea-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n class=\"ea-spinner\"\n [ngClass]=\"hostClasses()\"\n role=\"status\">\n <svg\n class=\"ea-spinner__circle\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n opacity=\"0.25\" />\n <path\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\" />\n </svg>\n <span class=\"ea-spinner__label\">{{ resolvedLabel() }}</span>\n</div>\n", styles: [".ea-spinner{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--color-brand-default)}.ea-spinner--sm .ea-spinner__circle{width:1rem;height:1rem}.ea-spinner--sm .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--md .ea-spinner__circle{width:1.5rem;height:1.5rem}.ea-spinner--md .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--lg .ea-spinner__circle{width:2rem;height:2rem}.ea-spinner--lg .ea-spinner__label{font-size:var(--font-size-md)}.ea-spinner__circle{animation:ea-spin .75s linear infinite}@media(prefers-reduced-motion:reduce){.ea-spinner__circle{animation-duration:2.5s}}.ea-spinner__label{font-family:var(--font-family-sans);color:var(--color-text-secondary);line-height:var(--line-height-normal)}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
29207
+ class StepComponent {
29208
+ stepper = inject(StepperComponent);
29209
+ label = input.required(...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
29210
+ completed = input(false, ...(ngDevMode ? [{ debugName: "completed" }] : /* istanbul ignore next */ []));
29211
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
29212
+ optional = input(false, ...(ngDevMode ? [{ debugName: "optional" }] : /* istanbul ignore next */ []));
29213
+ id = input(`ea-step-${Math.random().toString(36).slice(2, 9)}`, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
29214
+ isActive = computed(() => this.stepper.indexOf(this) === this.stepper.activeStep(), ...(ngDevMode ? [{ debugName: "isActive" }] : /* istanbul ignore next */ []));
29215
+ ngOnInit() {
29216
+ this.stepper.registerStep(this);
29217
+ }
29218
+ ngOnDestroy() {
29219
+ this.stepper.unregisterStep(this);
29220
+ }
29221
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: StepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29222
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: StepComponent, isStandalone: true, selector: "ea-step", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, completed: { classPropertyName: "completed", publicName: "completed", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.display": "isActive() ? null : \"none\"" } }, ngImport: i0, template: `
29223
+ @if (isActive()) {
29224
+ <div
29225
+ class="ea-step__panel"
29226
+ role="tabpanel"
29227
+ [id]="id() + '-panel'"
29228
+ [attr.aria-labelledby]="id() + '-tab'"
29229
+ tabindex="0">
29230
+ <ng-content />
29231
+ </div>
29232
+ }
29233
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
28124
29234
  }
28125
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SpinnerComponent, decorators: [{
29235
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: StepComponent, decorators: [{
28126
29236
  type: Component,
28127
- args: [{ selector: 'ea-spinner', imports: [NgClass], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div\n class=\"ea-spinner\"\n [ngClass]=\"hostClasses()\"\n role=\"status\">\n <svg\n class=\"ea-spinner__circle\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n aria-hidden=\"true\">\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n opacity=\"0.25\" />\n <path\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\" />\n </svg>\n <span class=\"ea-spinner__label\">{{ resolvedLabel() }}</span>\n</div>\n", styles: [".ea-spinner{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--color-brand-default)}.ea-spinner--sm .ea-spinner__circle{width:1rem;height:1rem}.ea-spinner--sm .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--md .ea-spinner__circle{width:1.5rem;height:1.5rem}.ea-spinner--md .ea-spinner__label{font-size:var(--font-size-sm)}.ea-spinner--lg .ea-spinner__circle{width:2rem;height:2rem}.ea-spinner--lg .ea-spinner__label{font-size:var(--font-size-md)}.ea-spinner__circle{animation:ea-spin .75s linear infinite}@media(prefers-reduced-motion:reduce){.ea-spinner__circle{animation-duration:2.5s}}.ea-spinner__label{font-family:var(--font-family-sans);color:var(--color-text-secondary);line-height:var(--line-height-normal)}@keyframes ea-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
28128
- }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
29237
+ args: [{
29238
+ selector: 'ea-step',
29239
+ host: { '[style.display]': 'isActive() ? null : "none"' },
29240
+ template: `
29241
+ @if (isActive()) {
29242
+ <div
29243
+ class="ea-step__panel"
29244
+ role="tabpanel"
29245
+ [id]="id() + '-panel'"
29246
+ [attr.aria-labelledby]="id() + '-tab'"
29247
+ tabindex="0">
29248
+ <ng-content />
29249
+ </div>
29250
+ }
29251
+ `,
29252
+ changeDetection: ChangeDetectionStrategy.OnPush,
29253
+ }]
29254
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], completed: [{ type: i0.Input, args: [{ isSignal: true, alias: "completed", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
28129
29255
 
28130
29256
  /**
28131
29257
  * On/off toggle styled as a sliding switch. Backed by a visually hidden
@@ -28312,40 +29438,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
28312
29438
  }]
28313
29439
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
28314
29440
 
28315
- /**
28316
- * Inline label commonly used to represent filters, categories, or selected
28317
- * items. When `removable`, renders a close button that emits `removed`; the
28318
- * accessible name of that button is configurable via `removeLabel` and
28319
- * otherwise falls back to the active locale's translation.
28320
- */
28321
- class TagComponent {
28322
- i18n = inject(EagamiI18nService);
28323
- variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
28324
- size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
28325
- removable = input(false, ...(ngDevMode ? [{ debugName: "removable" }] : /* istanbul ignore next */ []));
28326
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
28327
- removeLabel = input(undefined, ...(ngDevMode ? [{ debugName: "removeLabel" }] : /* istanbul ignore next */ []));
28328
- /** Fires when the user activates the remove button on a `removable` tag. */
28329
- removed = output();
28330
- /** Accessible label for the remove button, falling back to the active locale. */
28331
- resolvedRemoveLabel = computed(() => this.removeLabel() ?? this.i18n.messages().tag.remove, ...(ngDevMode ? [{ debugName: "resolvedRemoveLabel" }] : /* istanbul ignore next */ []));
28332
- hostClasses = computed(() => ({
28333
- [`ea-tag--${this.variant()}`]: true,
28334
- [`ea-tag--${this.size()}`]: true,
28335
- 'ea-tag--disabled': this.disabled(),
28336
- }), ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
28337
- onRemove(event) {
28338
- event.stopPropagation();
28339
- this.removed.emit();
28340
- }
28341
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
28342
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: TagComponent, isStandalone: true, selector: "ea-tag", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, removable: { classPropertyName: "removable", publicName: "removable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, removeLabel: { classPropertyName: "removeLabel", publicName: "removeLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { removed: "removed" }, ngImport: i0, template: "<span\n class=\"ea-tag\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n @if (removable()) {\n <button\n type=\"button\"\n class=\"ea-tag__remove\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"resolvedRemoveLabel()\"\n (click)=\"onRemove($event)\">\n <ea-icon-x />\n </button>\n }\n</span>\n", styles: [".ea-tag{display:inline-flex;align-items:center;gap:var(--space-1);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-secondary)}.ea-tag--sm{padding:var(--space-0-5) var(--space-1-5);font-size:var(--font-size-xs)}.ea-tag--sm .ea-tag__remove ea-icon-x{width:.625rem;height:.625rem}.ea-tag--md{padding:var(--space-1) var(--space-2);font-size:var(--font-size-xs)}.ea-tag--md .ea-tag__remove ea-icon-x{width:.75rem;height:.75rem}.ea-tag--lg{padding:var(--space-1) var(--space-2-5);font-size:var(--font-size-sm)}.ea-tag--lg .ea-tag__remove ea-icon-x{width:.875rem;height:.875rem}.ea-tag--success{border-color:var(--color-success-muted);background-color:var(--color-success-subtle);color:var(--color-success-700)}.ea-tag--warning{border-color:var(--color-warning-muted);background-color:var(--color-warning-subtle);color:var(--color-warning-700)}.ea-tag--error{border-color:var(--color-error-muted);background-color:var(--color-error-subtle);color:var(--color-error-700)}.ea-tag--info{border-color:var(--color-info-muted);background-color:var(--color-info-subtle);color:var(--color-info-700)}.ea-tag--disabled{opacity:.6;cursor:not-allowed}.ea-tag__remove{opacity:.7;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;border-radius:var(--radius-xs);background:none;color:inherit;cursor:pointer;transition:var(--transition-colors)}.ea-tag__remove:hover{opacity:1}.ea-tag__remove:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-tag__remove:disabled{cursor:not-allowed}.ea-tag__remove ea-icon-x{pointer-events:none}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: XIconComponent, selector: "ea-icon-x" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
28343
- }
28344
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TagComponent, decorators: [{
28345
- type: Component,
28346
- args: [{ selector: 'ea-tag', imports: [NgClass, XIconComponent], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<span\n class=\"ea-tag\"\n [ngClass]=\"hostClasses()\">\n <ng-content />\n @if (removable()) {\n <button\n type=\"button\"\n class=\"ea-tag__remove\"\n [disabled]=\"disabled() || null\"\n [attr.aria-label]=\"resolvedRemoveLabel()\"\n (click)=\"onRemove($event)\">\n <ea-icon-x />\n </button>\n }\n</span>\n", styles: [".ea-tag{display:inline-flex;align-items:center;gap:var(--space-1);font-weight:var(--font-weight-medium);line-height:var(--line-height-none);white-space:nowrap;font-family:var(--font-family-sans);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-lg);background-color:var(--color-bg-subtle);color:var(--color-text-secondary)}.ea-tag--sm{padding:var(--space-0-5) var(--space-1-5);font-size:var(--font-size-xs)}.ea-tag--sm .ea-tag__remove ea-icon-x{width:.625rem;height:.625rem}.ea-tag--md{padding:var(--space-1) var(--space-2);font-size:var(--font-size-xs)}.ea-tag--md .ea-tag__remove ea-icon-x{width:.75rem;height:.75rem}.ea-tag--lg{padding:var(--space-1) var(--space-2-5);font-size:var(--font-size-sm)}.ea-tag--lg .ea-tag__remove ea-icon-x{width:.875rem;height:.875rem}.ea-tag--success{border-color:var(--color-success-muted);background-color:var(--color-success-subtle);color:var(--color-success-700)}.ea-tag--warning{border-color:var(--color-warning-muted);background-color:var(--color-warning-subtle);color:var(--color-warning-700)}.ea-tag--error{border-color:var(--color-error-muted);background-color:var(--color-error-subtle);color:var(--color-error-700)}.ea-tag--info{border-color:var(--color-info-muted);background-color:var(--color-info-subtle);color:var(--color-info-700)}.ea-tag--disabled{opacity:.6;cursor:not-allowed}.ea-tag__remove{opacity:.7;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;border:none;border-radius:var(--radius-xs);background:none;color:inherit;cursor:pointer;transition:var(--transition-colors)}.ea-tag__remove:hover{opacity:1}.ea-tag__remove:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-tag__remove:disabled{cursor:not-allowed}.ea-tag__remove ea-icon-x{pointer-events:none}\n"] }]
28347
- }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], removable: [{ type: i0.Input, args: [{ isSignal: true, alias: "removable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], removeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "removeLabel", required: false }] }], removed: [{ type: i0.Output, args: ["removed"] }] } });
28348
-
28349
29441
  /**
28350
29442
  * Multiline text field that mirrors the `ea-input` API. Supports configurable
28351
29443
  * `rows`, `resize` direction, and `maxlength`, and integrates with Angular
@@ -28422,7 +29514,7 @@ class TextareaComponent {
28422
29514
  useExisting: forwardRef(() => TextareaComponent),
28423
29515
  multi: true,
28424
29516
  },
28425
- ], viewQueries: [{ propertyName: "textareaEl", first: true, predicate: ["textareaEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-textarea-field\">\n @if (label()) {\n <label\n class=\"ea-textarea-field__label\"\n [for]=\"id()\"\n [class.ea-textarea-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div\n class=\"ea-textarea-wrapper\"\n [ngClass]=\"wrapperClasses()\">\n <textarea\n #textareaEl\n class=\"ea-textarea\"\n [id]=\"id()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"readonly()\"\n [required]=\"required()\"\n [rows]=\"rows()\"\n [value]=\"value()\"\n [style.resize]=\"resize()\"\n [attr.maxlength]=\"maxlength() ?? null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"></textarea>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-textarea-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-textarea-field{display:flex;flex-direction:column;gap:var(--space-1-5);color:var(--color-text-secondary)}.ea-textarea-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-textarea-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-textarea-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-textarea-field__message--hint{color:inherit}.ea-textarea-field__message--error{color:var(--color-error-default)}.ea-textarea-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-textarea-wrapper{display:flex;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);overflow:hidden}.ea-textarea-wrapper--sm .ea-textarea{padding:var(--space-2);font-size:var(--font-size-sm)}.ea-textarea-wrapper--md .ea-textarea{padding:var(--space-3);font-size:var(--font-size-md)}.ea-textarea-wrapper--lg .ea-textarea{padding:var(--space-4);font-size:var(--font-size-lg)}.ea-textarea-wrapper--focused{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-textarea-wrapper--error{border-color:var(--color-error-default)}.ea-textarea-wrapper--error.ea-textarea-wrapper--focused{box-shadow:var(--shadow-focus-ring-error)}.ea-textarea-wrapper--disabled{background-color:var(--color-bg-muted);border-color:var(--color-border-default);cursor:not-allowed;opacity:.6}.ea-textarea-wrapper--disabled .ea-textarea{cursor:not-allowed}.ea-textarea-wrapper--readonly{background-color:var(--color-bg-subtle)}.ea-textarea{flex:1;width:100%;min-width:0;min-height:0;background:transparent;border:none;outline:none;color:var(--color-text-primary);font-family:var(--font-family-sans);line-height:var(--line-height-normal)}.ea-textarea::placeholder{color:var(--color-text-tertiary)}.ea-textarea:disabled{cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29517
+ ], viewQueries: [{ propertyName: "textareaEl", first: true, predicate: ["textareaEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-textarea-field\">\n @if (label()) {\n <label\n class=\"ea-textarea-field__label\"\n [for]=\"id()\"\n [class.ea-textarea-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div\n class=\"ea-textarea-wrapper\"\n [ngClass]=\"wrapperClasses()\">\n <textarea\n #textareaEl\n class=\"ea-textarea\"\n [id]=\"id()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"readonly()\"\n [required]=\"required()\"\n [rows]=\"rows()\"\n [value]=\"value()\"\n [style.resize]=\"resize()\"\n [attr.maxlength]=\"maxlength() ?? null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"></textarea>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-textarea-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-textarea-field{display:flex;flex-direction:column;gap:var(--space-1-5);color:var(--color-text-secondary)}.ea-textarea-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-textarea-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-textarea-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-textarea-field__message--hint{color:inherit}.ea-textarea-field__message--error{color:var(--color-error-default)}.ea-textarea-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-textarea-wrapper{display:flex;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);overflow:hidden}.ea-textarea-wrapper--sm .ea-textarea{min-height:calc(1.5em + var(--space-2) * 2);padding:var(--space-2);font-size:var(--font-size-sm)}.ea-textarea-wrapper--md .ea-textarea{min-height:calc(1.5em + var(--space-3) * 2);padding:var(--space-3);font-size:var(--font-size-md)}.ea-textarea-wrapper--lg .ea-textarea{min-height:calc(1.5em + var(--space-4) * 2);padding:var(--space-4);font-size:var(--font-size-lg)}.ea-textarea-wrapper--focused{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-textarea-wrapper--error{border-color:var(--color-error-default)}.ea-textarea-wrapper--error.ea-textarea-wrapper--focused{box-shadow:var(--shadow-focus-ring-error)}.ea-textarea-wrapper--disabled{background-color:var(--color-bg-muted);border-color:var(--color-border-default);cursor:not-allowed;opacity:.6}.ea-textarea-wrapper--disabled .ea-textarea{cursor:not-allowed}.ea-textarea-wrapper--readonly{background-color:var(--color-bg-subtle)}.ea-textarea{flex:1;width:100%;min-width:0;min-height:0;background:transparent;border:none;outline:none;color:var(--color-text-primary);font-family:var(--font-family-sans);line-height:var(--line-height-normal)}.ea-textarea::placeholder{color:var(--color-text-tertiary)}.ea-textarea:disabled{cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
28426
29518
  }
28427
29519
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TextareaComponent, decorators: [{
28428
29520
  type: Component,
@@ -28432,9 +29524,503 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
28432
29524
  useExisting: forwardRef(() => TextareaComponent),
28433
29525
  multi: true,
28434
29526
  },
28435
- ], template: "<div class=\"ea-textarea-field\">\n @if (label()) {\n <label\n class=\"ea-textarea-field__label\"\n [for]=\"id()\"\n [class.ea-textarea-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div\n class=\"ea-textarea-wrapper\"\n [ngClass]=\"wrapperClasses()\">\n <textarea\n #textareaEl\n class=\"ea-textarea\"\n [id]=\"id()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"readonly()\"\n [required]=\"required()\"\n [rows]=\"rows()\"\n [value]=\"value()\"\n [style.resize]=\"resize()\"\n [attr.maxlength]=\"maxlength() ?? null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"></textarea>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-textarea-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-textarea-field{display:flex;flex-direction:column;gap:var(--space-1-5);color:var(--color-text-secondary)}.ea-textarea-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-textarea-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-textarea-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-textarea-field__message--hint{color:inherit}.ea-textarea-field__message--error{color:var(--color-error-default)}.ea-textarea-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-textarea-wrapper{display:flex;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);overflow:hidden}.ea-textarea-wrapper--sm .ea-textarea{padding:var(--space-2);font-size:var(--font-size-sm)}.ea-textarea-wrapper--md .ea-textarea{padding:var(--space-3);font-size:var(--font-size-md)}.ea-textarea-wrapper--lg .ea-textarea{padding:var(--space-4);font-size:var(--font-size-lg)}.ea-textarea-wrapper--focused{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-textarea-wrapper--error{border-color:var(--color-error-default)}.ea-textarea-wrapper--error.ea-textarea-wrapper--focused{box-shadow:var(--shadow-focus-ring-error)}.ea-textarea-wrapper--disabled{background-color:var(--color-bg-muted);border-color:var(--color-border-default);cursor:not-allowed;opacity:.6}.ea-textarea-wrapper--disabled .ea-textarea{cursor:not-allowed}.ea-textarea-wrapper--readonly{background-color:var(--color-bg-subtle)}.ea-textarea{flex:1;width:100%;min-width:0;min-height:0;background:transparent;border:none;outline:none;color:var(--color-text-primary);font-family:var(--font-family-sans);line-height:var(--line-height-normal)}.ea-textarea::placeholder{color:var(--color-text-tertiary)}.ea-textarea:disabled{cursor:not-allowed}\n"] }]
29527
+ ], template: "<div class=\"ea-textarea-field\">\n @if (label()) {\n <label\n class=\"ea-textarea-field__label\"\n [for]=\"id()\"\n [class.ea-textarea-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div\n class=\"ea-textarea-wrapper\"\n [ngClass]=\"wrapperClasses()\">\n <textarea\n #textareaEl\n class=\"ea-textarea\"\n [id]=\"id()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readOnly]=\"readonly()\"\n [required]=\"required()\"\n [rows]=\"rows()\"\n [value]=\"value()\"\n [style.resize]=\"resize()\"\n [attr.maxlength]=\"maxlength() ?? null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (input)=\"handleInput($event)\"\n (focus)=\"handleFocus($event)\"\n (blur)=\"handleBlur($event)\"></textarea>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-textarea-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-textarea-field__message ea-textarea-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-textarea-field{display:flex;flex-direction:column;gap:var(--space-1-5);color:var(--color-text-secondary)}.ea-textarea-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-textarea-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-textarea-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-textarea-field__message--hint{color:inherit}.ea-textarea-field__message--error{color:var(--color-error-default)}.ea-textarea-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-textarea-wrapper{display:flex;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);transition:var(--transition-colors),var(--transition-shadow);overflow:hidden}.ea-textarea-wrapper--sm .ea-textarea{min-height:calc(1.5em + var(--space-2) * 2);padding:var(--space-2);font-size:var(--font-size-sm)}.ea-textarea-wrapper--md .ea-textarea{min-height:calc(1.5em + var(--space-3) * 2);padding:var(--space-3);font-size:var(--font-size-md)}.ea-textarea-wrapper--lg .ea-textarea{min-height:calc(1.5em + var(--space-4) * 2);padding:var(--space-4);font-size:var(--font-size-lg)}.ea-textarea-wrapper--focused{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-textarea-wrapper--error{border-color:var(--color-error-default)}.ea-textarea-wrapper--error.ea-textarea-wrapper--focused{box-shadow:var(--shadow-focus-ring-error)}.ea-textarea-wrapper--disabled{background-color:var(--color-bg-muted);border-color:var(--color-border-default);cursor:not-allowed;opacity:.6}.ea-textarea-wrapper--disabled .ea-textarea{cursor:not-allowed}.ea-textarea-wrapper--readonly{background-color:var(--color-bg-subtle)}.ea-textarea{flex:1;width:100%;min-width:0;min-height:0;background:transparent;border:none;outline:none;color:var(--color-text-primary);font-family:var(--font-family-sans);line-height:var(--line-height-normal)}.ea-textarea::placeholder{color:var(--color-text-tertiary)}.ea-textarea:disabled{cursor:not-allowed}\n"] }]
28436
29528
  }], propDecorators: { textareaEl: [{ type: i0.ViewChild, args: ['textareaEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], resize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resize", required: false }] }], maxlength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxlength", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], focused: [{ type: i0.Output, args: ["focused"] }], blurred: [{ type: i0.Output, args: ["blurred"] }] } });
28437
29529
 
29530
+ /**
29531
+ * Pops a stepper UI for selecting an `HH:MM[:SS]` time. The wire value is
29532
+ * always a 24-hour string (`"14:30"` or `"14:30:00"`); the `format` input
29533
+ * toggles the trigger's display between 12-hour and 24-hour styles. Supports
29534
+ * configurable steps for minutes and seconds, optional seconds column, and
29535
+ * integrates with Angular forms via `ControlValueAccessor`.
29536
+ *
29537
+ * Keyboard: Tab moves between the hour, minute, (seconds), and AM/PM columns.
29538
+ * Each spinner accepts ArrowUp/ArrowDown to step by 1 (or by the configured
29539
+ * step), PageUp/PageDown for a coarser bump, and digit keys to type a value
29540
+ * directly. After typing two digits (or one digit that already maxes the
29541
+ * unit), focus auto-advances to the next column. Backspace clears the typed
29542
+ * buffer; Escape closes the popover.
29543
+ */
29544
+ class TimePickerComponent {
29545
+ triggerEl = viewChild('triggerEl', ...(ngDevMode ? [{ debugName: "triggerEl" }] : /* istanbul ignore next */ []));
29546
+ hoursEl = viewChild('hoursEl', ...(ngDevMode ? [{ debugName: "hoursEl" }] : /* istanbul ignore next */ []));
29547
+ minutesEl = viewChild('minutesEl', ...(ngDevMode ? [{ debugName: "minutesEl" }] : /* istanbul ignore next */ []));
29548
+ secondsEl = viewChild('secondsEl', ...(ngDevMode ? [{ debugName: "secondsEl" }] : /* istanbul ignore next */ []));
29549
+ i18n = inject(EagamiI18nService);
29550
+ destroyRef = inject(DestroyRef);
29551
+ injector = inject(Injector);
29552
+ // ─── Inputs ───────────────────────────────────────────────────────────
29553
+ label = input(undefined, ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
29554
+ placeholder = input(undefined, ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
29555
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
29556
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []));
29557
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : /* istanbul ignore next */ []));
29558
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
29559
+ hint = input(undefined, ...(ngDevMode ? [{ debugName: "hint" }] : /* istanbul ignore next */ []));
29560
+ errorMsg = input(undefined, ...(ngDevMode ? [{ debugName: "errorMsg" }] : /* istanbul ignore next */ []));
29561
+ /** Display format for the trigger label. Wire value is always 24h. */
29562
+ format = input('24h', ...(ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []));
29563
+ includeSeconds = input(false, ...(ngDevMode ? [{ debugName: "includeSeconds" }] : /* istanbul ignore next */ []));
29564
+ minuteStep = input(1, ...(ngDevMode ? [{ debugName: "minuteStep" }] : /* istanbul ignore next */ []));
29565
+ secondStep = input(1, ...(ngDevMode ? [{ debugName: "secondStep" }] : /* istanbul ignore next */ []));
29566
+ id = input(`ea-time-picker-${Math.random().toString(36).slice(2, 9)}`, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
29567
+ /** `"HH:MM"` or `"HH:MM:SS"` in 24-hour notation, or `null` when unset. */
29568
+ value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
29569
+ /** Fires with the new value whenever the user changes the time. */
29570
+ changed = output();
29571
+ // ─── State ────────────────────────────────────────────────────────────
29572
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : /* istanbul ignore next */ []));
29573
+ /** Typed-digit buffer for the currently focused column, or `null` when idle. */
29574
+ editBuffer = signal(null, ...(ngDevMode ? [{ debugName: "editBuffer" }] : /* istanbul ignore next */ []));
29575
+ _formDisabled = signal(false, ...(ngDevMode ? [{ debugName: "_formDisabled" }] : /* istanbul ignore next */ []));
29576
+ onChange = () => { };
29577
+ onTouched = () => { };
29578
+ /** Long-press timers for the chevron buttons. Cleared on release/destroy. */
29579
+ holdDelayTimer = null;
29580
+ holdIntervalTimer = null;
29581
+ holdStartedAt = 0;
29582
+ // ─── Computed ─────────────────────────────────────────────────────────
29583
+ isDisabled = computed(() => this.disabled() || this._formDisabled(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []));
29584
+ hasError = computed(() => !!this.errorMsg(), ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
29585
+ showError = this.hasError;
29586
+ showHint = computed(() => !!this.hint() && !this.hasError(), ...(ngDevMode ? [{ debugName: "showHint" }] : /* istanbul ignore next */ []));
29587
+ /** Parsed `[hh, mm, ss]` from the current value, defaulting to midnight. */
29588
+ parsed = computed(() => {
29589
+ const parsed = parseTime(this.value());
29590
+ return parsed ?? { hours: 0, minutes: 0, seconds: 0 };
29591
+ }, ...(ngDevMode ? [{ debugName: "parsed" }] : /* istanbul ignore next */ []));
29592
+ /** True when the picker has a non-null value. Drives the clear button + placeholder fallback. */
29593
+ hasValue = computed(() => this.value() !== null, ...(ngDevMode ? [{ debugName: "hasValue" }] : /* istanbul ignore next */ []));
29594
+ /** Hours digit displayed in the popover stepper. Honors the `format` input. */
29595
+ displayHours = computed(() => {
29596
+ const h = this.parsed().hours;
29597
+ if (this.format() === '24h')
29598
+ return h;
29599
+ // 12h: 0 → 12 (midnight as 12 AM), 13–23 → 1–11
29600
+ return h % 12 === 0 ? 12 : h % 12;
29601
+ }, ...(ngDevMode ? [{ debugName: "displayHours" }] : /* istanbul ignore next */ []));
29602
+ /**
29603
+ * Text shown in a column's value cell. Reflects the typed-digit buffer when
29604
+ * the user is mid-edit on that column; otherwise renders the committed
29605
+ * value. Hours pad to two digits in 24h mode only (so 9 AM still reads as
29606
+ * "9", but 09:00 in 24h reads as "09").
29607
+ */
29608
+ hoursText = computed(() => {
29609
+ const buf = this.editBuffer();
29610
+ if (buf && buf.unit === 'hours')
29611
+ return buf.digits;
29612
+ const h = this.displayHours();
29613
+ return this.format() === '24h' ? pad2(h) : String(h);
29614
+ }, ...(ngDevMode ? [{ debugName: "hoursText" }] : /* istanbul ignore next */ []));
29615
+ minutesText = computed(() => {
29616
+ const buf = this.editBuffer();
29617
+ if (buf && buf.unit === 'minutes')
29618
+ return buf.digits;
29619
+ return pad2(this.parsed().minutes);
29620
+ }, ...(ngDevMode ? [{ debugName: "minutesText" }] : /* istanbul ignore next */ []));
29621
+ secondsText = computed(() => {
29622
+ const buf = this.editBuffer();
29623
+ if (buf && buf.unit === 'seconds')
29624
+ return buf.digits;
29625
+ return pad2(this.parsed().seconds);
29626
+ }, ...(ngDevMode ? [{ debugName: "secondsText" }] : /* istanbul ignore next */ []));
29627
+ /** `'AM' | 'PM'` for 12h mode; `null` in 24h. */
29628
+ period = computed(() => {
29629
+ if (this.format() === '24h')
29630
+ return null;
29631
+ return this.parsed().hours < 12 ? 'AM' : 'PM';
29632
+ }, ...(ngDevMode ? [{ debugName: "period" }] : /* istanbul ignore next */ []));
29633
+ /** Localized text shown on the trigger. Falls back to placeholder when no value. */
29634
+ displayValue = computed(() => {
29635
+ if (!this.hasValue())
29636
+ return null;
29637
+ const { hours, minutes, seconds } = this.parsed();
29638
+ const m = pad2(minutes);
29639
+ const s = this.includeSeconds() ? `:${pad2(seconds)}` : '';
29640
+ if (this.format() === '24h') {
29641
+ return `${pad2(hours)}:${m}${s}`;
29642
+ }
29643
+ const display = hours % 12 === 0 ? 12 : hours % 12;
29644
+ const period = hours < 12
29645
+ ? this.i18n.messages().timePicker.amLabel
29646
+ : this.i18n.messages().timePicker.pmLabel;
29647
+ return `${display}:${m}${s} ${period}`;
29648
+ }, ...(ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []));
29649
+ resolvedPlaceholder = computed(() => this.placeholder() ?? this.i18n.messages().timePicker.placeholder, ...(ngDevMode ? [{ debugName: "resolvedPlaceholder" }] : /* istanbul ignore next */ []));
29650
+ triggerClasses = computed(() => ({
29651
+ [`ea-time-picker__trigger--${this.size()}`]: true,
29652
+ 'ea-time-picker__trigger--error': this.hasError(),
29653
+ 'ea-time-picker__trigger--open': this.isOpen(),
29654
+ 'ea-time-picker__trigger--disabled': this.isDisabled(),
29655
+ 'ea-time-picker__trigger--placeholder': !this.hasValue(),
29656
+ }), ...(ngDevMode ? [{ debugName: "triggerClasses" }] : /* istanbul ignore next */ []));
29657
+ // ─── ControlValueAccessor ─────────────────────────────────────────────
29658
+ writeValue(val) {
29659
+ this.value.set(val ?? null);
29660
+ }
29661
+ registerOnChange(fn) {
29662
+ this.onChange = fn;
29663
+ }
29664
+ registerOnTouched(fn) {
29665
+ this.onTouched = fn;
29666
+ }
29667
+ setDisabledState(isDisabled) {
29668
+ this._formDisabled.set(isDisabled);
29669
+ }
29670
+ constructor() {
29671
+ this.destroyRef.onDestroy(() => this.stopHold());
29672
+ }
29673
+ // ─── Handlers ─────────────────────────────────────────────────────────
29674
+ toggle() {
29675
+ if (this.isDisabled() || this.readonly())
29676
+ return;
29677
+ const opening = !this.isOpen();
29678
+ this.isOpen.set(opening);
29679
+ if (opening)
29680
+ this.focusHoursWhenReady();
29681
+ }
29682
+ /**
29683
+ * Push focus into the hours input once the popover surface has been
29684
+ * rendered. `afterNextRender` guarantees the DOM has been updated (and the
29685
+ * surface is no longer `display: none`) before we call `.focus()`.
29686
+ */
29687
+ focusHoursWhenReady() {
29688
+ afterNextRender(() => {
29689
+ const el = this.hoursEl()?.nativeElement;
29690
+ el?.focus();
29691
+ el?.select();
29692
+ }, { injector: this.injector });
29693
+ }
29694
+ close() {
29695
+ this.isOpen.set(false);
29696
+ }
29697
+ /** Called by `<ea-popover>` when the user clicks outside or scrolls. */
29698
+ onPopoverCloseRequested() {
29699
+ this.close();
29700
+ this.onTouched();
29701
+ }
29702
+ clear(event) {
29703
+ event.stopPropagation();
29704
+ if (this.isDisabled() || this.readonly())
29705
+ return;
29706
+ this.value.set(null);
29707
+ this.onChange(null);
29708
+ this.onTouched();
29709
+ this.changed.emit(null);
29710
+ }
29711
+ handleTriggerKeydown(event) {
29712
+ if (this.isDisabled() || this.readonly())
29713
+ return;
29714
+ if (event.key === 'Enter' || event.key === ' ' || event.key === 'ArrowDown') {
29715
+ event.preventDefault();
29716
+ if (!this.isOpen()) {
29717
+ this.isOpen.set(true);
29718
+ this.focusHoursWhenReady();
29719
+ }
29720
+ }
29721
+ else if (event.key === 'Escape' && this.isOpen()) {
29722
+ event.preventDefault();
29723
+ this.close();
29724
+ this.triggerEl()?.nativeElement.focus();
29725
+ }
29726
+ }
29727
+ /** Stepper button or keyboard arrow nudges one column up or down. */
29728
+ step(unit, direction) {
29729
+ if (this.isDisabled() || this.readonly())
29730
+ return;
29731
+ const { hours, minutes, seconds } = this.parsed();
29732
+ const next = nextTime({ hours, minutes, seconds }, unit, direction, this.minuteStep(), this.secondStep());
29733
+ this.commit(next);
29734
+ }
29735
+ /**
29736
+ * Begin a long-press repeat on a chevron button. Fires once immediately,
29737
+ * then after a `HOLD_INITIAL_DELAY` pause repeats at `HOLD_INTERVAL_MS`,
29738
+ * accelerating to `HOLD_FAST_INTERVAL_MS` after `HOLD_ACCELERATE_AFTER_MS`
29739
+ * of continuous holding. Pointer up / leave / cancel stops the repeat.
29740
+ */
29741
+ startHold(unit, direction, event) {
29742
+ if (this.isDisabled() || this.readonly())
29743
+ return;
29744
+ event.preventDefault();
29745
+ this.stopHold();
29746
+ this.step(unit, direction);
29747
+ this.holdStartedAt = performance.now();
29748
+ this.holdDelayTimer = setTimeout(() => {
29749
+ this.holdIntervalTimer = setInterval(() => {
29750
+ this.step(unit, direction);
29751
+ const elapsed = performance.now() - this.holdStartedAt;
29752
+ if (elapsed > HOLD_ACCELERATE_AFTER_MS && this.holdIntervalTimer !== null) {
29753
+ clearInterval(this.holdIntervalTimer);
29754
+ this.holdIntervalTimer = setInterval(() => this.step(unit, direction), HOLD_FAST_INTERVAL_MS);
29755
+ }
29756
+ }, HOLD_INTERVAL_MS);
29757
+ }, HOLD_INITIAL_DELAY);
29758
+ }
29759
+ /** End any in-flight long-press repeat. Idempotent. */
29760
+ stopHold() {
29761
+ if (this.holdDelayTimer !== null) {
29762
+ clearTimeout(this.holdDelayTimer);
29763
+ this.holdDelayTimer = null;
29764
+ }
29765
+ if (this.holdIntervalTimer !== null) {
29766
+ clearInterval(this.holdIntervalTimer);
29767
+ this.holdIntervalTimer = null;
29768
+ }
29769
+ }
29770
+ /** Switches the AM/PM period in 12h mode by toggling the 12-hour offset. */
29771
+ togglePeriod() {
29772
+ if (this.isDisabled() || this.readonly() || this.format() === '24h')
29773
+ return;
29774
+ const { hours, minutes, seconds } = this.parsed();
29775
+ const flipped = (hours + 12) % 24;
29776
+ this.commit({ hours: flipped, minutes, seconds });
29777
+ }
29778
+ handlePopoverKeydown(event, unit) {
29779
+ if (this.isDisabled() || this.readonly())
29780
+ return;
29781
+ // Digits, Backspace, and Delete pass through to the native `<input>`.
29782
+ // The `(input)` handler picks them up via `onSpinnerInput`.
29783
+ if (event.key === 'ArrowUp') {
29784
+ event.preventDefault();
29785
+ this.flushBuffer();
29786
+ this.step(unit, 1);
29787
+ }
29788
+ else if (event.key === 'ArrowDown') {
29789
+ event.preventDefault();
29790
+ this.flushBuffer();
29791
+ this.step(unit, -1);
29792
+ }
29793
+ else if (event.key === 'PageUp') {
29794
+ event.preventDefault();
29795
+ this.flushBuffer();
29796
+ // Coarse step: 5× the configured step (or 10 for hours).
29797
+ const coarse = unit === 'hours' ? 10 : 5;
29798
+ for (let i = 0; i < coarse; i++)
29799
+ this.step(unit, 1);
29800
+ }
29801
+ else if (event.key === 'PageDown') {
29802
+ event.preventDefault();
29803
+ this.flushBuffer();
29804
+ const coarse = unit === 'hours' ? 10 : 5;
29805
+ for (let i = 0; i < coarse; i++)
29806
+ this.step(unit, -1);
29807
+ }
29808
+ else if (event.key === 'Enter') {
29809
+ event.preventDefault();
29810
+ this.flushBuffer();
29811
+ this.close();
29812
+ this.triggerEl()?.nativeElement.focus();
29813
+ }
29814
+ else if (event.key === 'Escape') {
29815
+ event.preventDefault();
29816
+ this.editBuffer.set(null);
29817
+ this.close();
29818
+ this.triggerEl()?.nativeElement.focus();
29819
+ }
29820
+ // Tab is handled by the browser; (blur) on the leaving input flushes.
29821
+ }
29822
+ /** Select-all on focus so the first keystroke replaces the current value. */
29823
+ onSpinnerFocus(event) {
29824
+ const el = event.currentTarget;
29825
+ // afterNextRender-ish: wait one tick so iOS / Safari accept the select().
29826
+ queueMicrotask(() => el.select());
29827
+ }
29828
+ /**
29829
+ * Native `(input)` event: the typed value is already in `el.value`. Strip
29830
+ * non-digits, update the buffer (which drives the displayed text), and
29831
+ * commit + auto-advance once the column is full or a third digit would
29832
+ * overflow.
29833
+ */
29834
+ onSpinnerInput(unit, event) {
29835
+ if (this.isDisabled() || this.readonly())
29836
+ return;
29837
+ const el = event.currentTarget;
29838
+ const raw = el.value;
29839
+ const digits = raw.replace(/\D/g, '').slice(0, 2);
29840
+ if (digits !== raw)
29841
+ el.value = digits;
29842
+ this.editBuffer.set({ unit, digits });
29843
+ if (digits.length === 2) {
29844
+ // Two digits committed — advance.
29845
+ this.commitDigits(unit, digits);
29846
+ this.advanceFocus(unit);
29847
+ return;
29848
+ }
29849
+ if (digits.length === 1 && this.cannotExtend(unit, digits)) {
29850
+ // A single digit already saturates the unit (e.g. `9` in minutes once
29851
+ // a second `0`–`5` would be required to stay ≤ 59 — but 9 + 0 = 90 > 59).
29852
+ // Commit and advance.
29853
+ this.commitDigits(unit, digits);
29854
+ this.advanceFocus(unit);
29855
+ }
29856
+ }
29857
+ /** Commits the current buffer if any. Wired to each input's `(blur)`. */
29858
+ onSpinnerBlur() {
29859
+ this.flushBuffer();
29860
+ }
29861
+ // ─── Typing internals ─────────────────────────────────────────────────
29862
+ /** True when no digit `0`–`9` can validly extend the current buffer. */
29863
+ cannotExtend(unit, digits) {
29864
+ const candidate = parseInt(digits + '0', 10);
29865
+ return candidate > this.maxFor(unit);
29866
+ }
29867
+ /** Commits any pending buffer. Called on blur, on arrow keys, on Tab. */
29868
+ flushBuffer() {
29869
+ const buf = this.editBuffer();
29870
+ if (!buf || buf.digits.length === 0) {
29871
+ this.editBuffer.set(null);
29872
+ return;
29873
+ }
29874
+ this.commitDigits(buf.unit, buf.digits);
29875
+ }
29876
+ /** Writes the buffered digits into the value and clears the buffer. */
29877
+ commitDigits(unit, digits) {
29878
+ const raw = parseInt(digits, 10);
29879
+ if (isNaN(raw)) {
29880
+ this.editBuffer.set(null);
29881
+ return;
29882
+ }
29883
+ const max = this.maxFor(unit);
29884
+ const clamped = Math.min(max, Math.max(this.minFor(unit), raw));
29885
+ const { hours, minutes, seconds } = this.parsed();
29886
+ let next;
29887
+ if (unit === 'hours') {
29888
+ next = { hours: this.hoursFromTyped(clamped), minutes, seconds };
29889
+ }
29890
+ else if (unit === 'minutes') {
29891
+ next = { hours, minutes: clamped, seconds };
29892
+ }
29893
+ else {
29894
+ next = { hours, minutes, seconds: clamped };
29895
+ }
29896
+ this.editBuffer.set(null);
29897
+ this.commit(next);
29898
+ }
29899
+ /**
29900
+ * Map a typed hours value back to 24h. In 24h mode the typed value is the
29901
+ * hour. In 12h mode the typed value is interpreted in the current period
29902
+ * (AM → 12 maps to 0, others stay; PM → 12 stays, others add 12).
29903
+ */
29904
+ hoursFromTyped(typed) {
29905
+ if (this.format() === '24h')
29906
+ return typed;
29907
+ const isPm = this.period() === 'PM';
29908
+ if (typed === 12)
29909
+ return isPm ? 12 : 0;
29910
+ return isPm ? typed + 12 : typed;
29911
+ }
29912
+ minFor(unit) {
29913
+ if (unit !== 'hours')
29914
+ return 0;
29915
+ return this.format() === '24h' ? 0 : 1;
29916
+ }
29917
+ maxFor(unit) {
29918
+ if (unit === 'hours')
29919
+ return this.format() === '24h' ? 23 : 12;
29920
+ return 59;
29921
+ }
29922
+ /** Move focus to the next unit column, looping back to hours at the end. */
29923
+ advanceFocus(unit) {
29924
+ const next = this.nextUnit(unit);
29925
+ const el = next === 'hours'
29926
+ ? this.hoursEl()?.nativeElement
29927
+ : next === 'minutes'
29928
+ ? this.minutesEl()?.nativeElement
29929
+ : this.secondsEl()?.nativeElement;
29930
+ el?.focus();
29931
+ }
29932
+ nextUnit(unit) {
29933
+ if (unit === 'hours')
29934
+ return 'minutes';
29935
+ if (unit === 'minutes')
29936
+ return this.includeSeconds() ? 'seconds' : 'hours';
29937
+ return 'hours';
29938
+ }
29939
+ // ─── Internals ────────────────────────────────────────────────────────
29940
+ commit(time) {
29941
+ const str = formatTime(time, this.includeSeconds());
29942
+ if (str === this.value())
29943
+ return;
29944
+ this.value.set(str);
29945
+ this.onChange(str);
29946
+ this.changed.emit(str);
29947
+ }
29948
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TimePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
29949
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: TimePickerComponent, isStandalone: true, selector: "ea-time-picker", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, errorMsg: { classPropertyName: "errorMsg", publicName: "errorMsg", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, includeSeconds: { classPropertyName: "includeSeconds", publicName: "includeSeconds", isSignal: true, isRequired: false, transformFunction: null }, minuteStep: { classPropertyName: "minuteStep", publicName: "minuteStep", isSignal: true, isRequired: false, transformFunction: null }, secondStep: { classPropertyName: "secondStep", publicName: "secondStep", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", changed: "changed" }, providers: [
29950
+ {
29951
+ provide: NG_VALUE_ACCESSOR,
29952
+ useExisting: forwardRef(() => TimePickerComponent),
29953
+ multi: true,
29954
+ },
29955
+ ], viewQueries: [{ propertyName: "triggerEl", first: true, predicate: ["triggerEl"], descendants: true, isSignal: true }, { propertyName: "hoursEl", first: true, predicate: ["hoursEl"], descendants: true, isSignal: true }, { propertyName: "minutesEl", first: true, predicate: ["minutesEl"], descendants: true, isSignal: true }, { propertyName: "secondsEl", first: true, predicate: ["secondsEl"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ea-time-picker-field\">\n @if (label()) {\n <label\n class=\"ea-time-picker-field__label\"\n [for]=\"id()\"\n [class.ea-time-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-time-picker\">\n <div class=\"ea-time-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-time-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <ea-icon-clock\n class=\"ea-time-picker__trigger-icon\"\n aria-hidden=\"true\" />\n <span class=\"ea-time-picker__trigger-value\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (hasValue() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-time-picker__clear\"\n [attr.aria-label]=\"i18n.messages().timePicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"dialog\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div class=\"ea-time-picker__popover\">\n <!-- Hours column -->\n <div class=\"ea-time-picker__column\">\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.incrementHours\"\n (mousedown)=\"startHold('hours', 1, $event)\"\n (touchstart)=\"startHold('hours', 1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-up aria-hidden=\"true\" />\n </button>\n <input\n #hoursEl\n type=\"text\"\n class=\"ea-time-picker__value\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"2\"\n role=\"spinbutton\"\n [attr.aria-label]=\"i18n.messages().timePicker.hoursLabel\"\n [attr.aria-valuemin]=\"format() === '24h' ? 0 : 1\"\n [attr.aria-valuemax]=\"format() === '24h' ? 23 : 12\"\n [attr.aria-valuenow]=\"displayHours()\"\n [value]=\"hoursText()\"\n (focus)=\"onSpinnerFocus($event)\"\n (input)=\"onSpinnerInput('hours', $event)\"\n (keydown)=\"handlePopoverKeydown($event, 'hours')\"\n (blur)=\"onSpinnerBlur()\" />\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.decrementHours\"\n (mousedown)=\"startHold('hours', -1, $event)\"\n (touchstart)=\"startHold('hours', -1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-down aria-hidden=\"true\" />\n </button>\n </div>\n\n <span\n class=\"ea-time-picker__separator\"\n aria-hidden=\"true\">\n :\n </span>\n\n <!-- Minutes column -->\n <div class=\"ea-time-picker__column\">\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.incrementMinutes\"\n (mousedown)=\"startHold('minutes', 1, $event)\"\n (touchstart)=\"startHold('minutes', 1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-up aria-hidden=\"true\" />\n </button>\n <input\n #minutesEl\n type=\"text\"\n class=\"ea-time-picker__value\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"2\"\n role=\"spinbutton\"\n [attr.aria-label]=\"i18n.messages().timePicker.minutesLabel\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"59\"\n [attr.aria-valuenow]=\"parsed().minutes\"\n [value]=\"minutesText()\"\n (focus)=\"onSpinnerFocus($event)\"\n (input)=\"onSpinnerInput('minutes', $event)\"\n (keydown)=\"handlePopoverKeydown($event, 'minutes')\"\n (blur)=\"onSpinnerBlur()\" />\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.decrementMinutes\"\n (mousedown)=\"startHold('minutes', -1, $event)\"\n (touchstart)=\"startHold('minutes', -1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-down aria-hidden=\"true\" />\n </button>\n </div>\n\n <!-- Seconds column (optional) -->\n @if (includeSeconds()) {\n <span\n class=\"ea-time-picker__separator\"\n aria-hidden=\"true\">\n :\n </span>\n <div class=\"ea-time-picker__column\">\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.incrementSeconds\"\n (mousedown)=\"startHold('seconds', 1, $event)\"\n (touchstart)=\"startHold('seconds', 1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-up aria-hidden=\"true\" />\n </button>\n <input\n #secondsEl\n type=\"text\"\n class=\"ea-time-picker__value\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"2\"\n role=\"spinbutton\"\n [attr.aria-label]=\"i18n.messages().timePicker.secondsLabel\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"59\"\n [attr.aria-valuenow]=\"parsed().seconds\"\n [value]=\"secondsText()\"\n (focus)=\"onSpinnerFocus($event)\"\n (input)=\"onSpinnerInput('seconds', $event)\"\n (keydown)=\"handlePopoverKeydown($event, 'seconds')\"\n (blur)=\"onSpinnerBlur()\" />\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.decrementSeconds\"\n (mousedown)=\"startHold('seconds', -1, $event)\"\n (touchstart)=\"startHold('seconds', -1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-down aria-hidden=\"true\" />\n </button>\n </div>\n }\n\n <!-- AM/PM toggle (12h only) -->\n @if (format() === '12h') {\n <div class=\"ea-time-picker__period\">\n <button\n type=\"button\"\n class=\"ea-time-picker__period-option\"\n [class.ea-time-picker__period-option--active]=\"period() === 'AM'\"\n (click)=\"period() === 'PM' && togglePeriod()\">\n {{ i18n.messages().timePicker.amLabel }}\n </button>\n <button\n type=\"button\"\n class=\"ea-time-picker__period-option\"\n [class.ea-time-picker__period-option--active]=\"period() === 'PM'\"\n (click)=\"period() === 'AM' && togglePeriod()\">\n {{ i18n.messages().timePicker.pmLabel }}\n </button>\n </div>\n }\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-time-picker-field__message ea-time-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-time-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-time-picker-field__message ea-time-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-time-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-time-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-time-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-time-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-time-picker-field__message--hint{color:var(--color-text-secondary)}.ea-time-picker-field__message--error{color:var(--color-error-default)}.ea-time-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-time-picker,.ea-time-picker__trigger-wrapper{position:relative}.ea-time-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-time-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-time-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-time-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-time-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-time-picker__trigger--error{border-color:var(--color-error-default)}.ea-time-picker__trigger--error.ea-time-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-time-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-time-picker__trigger--placeholder .ea-time-picker__trigger-value{color:var(--color-text-tertiary)}.ea-time-picker__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary)}.ea-time-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums}.ea-time-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-time-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-time-picker__popover{display:flex;align-items:center;gap:var(--space-2);padding:var(--space-3);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-time-picker__column{display:flex;flex-direction:column;align-items:stretch;gap:var(--space-1)}.ea-time-picker__step{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2.25rem;height:1.75rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-time-picker__step:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-time-picker__step:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__step ea-icon-chevron-up,.ea-time-picker__step ea-icon-chevron-down{width:.875em;height:.875em}.ea-time-picker__value{width:2.25rem;height:2.25rem;padding:0;border:var(--border-width-thin) solid transparent;border-radius:var(--radius-sm);background-color:var(--color-bg-muted);font-family:var(--font-family-mono);font-size:var(--font-size-md);font-weight:var(--font-weight-medium);text-align:center;color:var(--color-text-primary);font-variant-numeric:tabular-nums;appearance:none;cursor:text}.ea-time-picker__value::selection{background-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-time-picker__value:hover{border-color:var(--color-border-default)}.ea-time-picker__value:focus{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring);background-color:var(--color-bg-base)}.ea-time-picker__separator{font-family:var(--font-family-mono);font-size:var(--font-size-md);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);-webkit-user-select:none;user-select:none}.ea-time-picker__period{display:flex;flex-direction:column;gap:var(--space-1);margin-left:var(--space-1)}.ea-time-picker__period-option{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2.5rem;padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-time-picker__period-option:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-time-picker__period-option:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__period-option--active{background-color:var(--color-brand-default);border-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-time-picker__period-option--active:hover{background-color:var(--color-brand-hover);border-color:var(--color-brand-hover);color:var(--color-text-inverse)}\n"], dependencies: [{ kind: "component", type: AlertCircleIconComponent, selector: "ea-icon-alert-circle" }, { kind: "component", type: ChevronDownIconComponent, selector: "ea-icon-chevron-down" }, { kind: "component", type: ChevronUpIconComponent, selector: "ea-icon-chevron-up" }, { kind: "component", type: ClockIconComponent, selector: "ea-icon-clock" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PopoverComponent, selector: "ea-popover", inputs: ["anchor", "open", "placement", "role", "aria-label", "surfaceId", "offset", "flip", "clamp", "matchAnchorWidth", "closeOnOutsideClick", "closeOnEscape", "scrollBehavior"], outputs: ["closeRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29956
+ }
29957
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: TimePickerComponent, decorators: [{
29958
+ type: Component,
29959
+ args: [{ selector: 'ea-time-picker', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
29960
+ AlertCircleIconComponent,
29961
+ ChevronDownIconComponent,
29962
+ ChevronUpIconComponent,
29963
+ ClockIconComponent,
29964
+ NgClass,
29965
+ PopoverComponent,
29966
+ ], providers: [
29967
+ {
29968
+ provide: NG_VALUE_ACCESSOR,
29969
+ useExisting: forwardRef(() => TimePickerComponent),
29970
+ multi: true,
29971
+ },
29972
+ ], template: "<div class=\"ea-time-picker-field\">\n @if (label()) {\n <label\n class=\"ea-time-picker-field__label\"\n [for]=\"id()\"\n [class.ea-time-picker-field__label--required]=\"required()\">\n {{ label() }}\n </label>\n }\n\n <div class=\"ea-time-picker\">\n <div class=\"ea-time-picker__trigger-wrapper\">\n <button\n #triggerEl\n type=\"button\"\n class=\"ea-time-picker__trigger\"\n [ngClass]=\"triggerClasses()\"\n [id]=\"id()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'dialog'\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"hasError() || null\"\n [attr.aria-describedby]=\"\n showError() ? id() + '-error' : showHint() ? id() + '-hint' : null\n \"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\">\n <ea-icon-clock\n class=\"ea-time-picker__trigger-icon\"\n aria-hidden=\"true\" />\n <span class=\"ea-time-picker__trigger-value\">\n {{ displayValue() || resolvedPlaceholder() }}\n </span>\n </button>\n @if (hasValue() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"ea-time-picker__clear\"\n [attr.aria-label]=\"i18n.messages().timePicker.clear\"\n (click)=\"clear($event)\">\n <span aria-hidden=\"true\">\u00D7</span>\n </button>\n }\n </div>\n\n <ea-popover\n [anchor]=\"triggerEl\"\n [open]=\"isOpen()\"\n placement=\"bottom-start\"\n role=\"dialog\"\n [closeOnEscape]=\"false\"\n scrollBehavior=\"close\"\n (closeRequested)=\"onPopoverCloseRequested()\">\n <div class=\"ea-time-picker__popover\">\n <!-- Hours column -->\n <div class=\"ea-time-picker__column\">\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.incrementHours\"\n (mousedown)=\"startHold('hours', 1, $event)\"\n (touchstart)=\"startHold('hours', 1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-up aria-hidden=\"true\" />\n </button>\n <input\n #hoursEl\n type=\"text\"\n class=\"ea-time-picker__value\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"2\"\n role=\"spinbutton\"\n [attr.aria-label]=\"i18n.messages().timePicker.hoursLabel\"\n [attr.aria-valuemin]=\"format() === '24h' ? 0 : 1\"\n [attr.aria-valuemax]=\"format() === '24h' ? 23 : 12\"\n [attr.aria-valuenow]=\"displayHours()\"\n [value]=\"hoursText()\"\n (focus)=\"onSpinnerFocus($event)\"\n (input)=\"onSpinnerInput('hours', $event)\"\n (keydown)=\"handlePopoverKeydown($event, 'hours')\"\n (blur)=\"onSpinnerBlur()\" />\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.decrementHours\"\n (mousedown)=\"startHold('hours', -1, $event)\"\n (touchstart)=\"startHold('hours', -1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-down aria-hidden=\"true\" />\n </button>\n </div>\n\n <span\n class=\"ea-time-picker__separator\"\n aria-hidden=\"true\">\n :\n </span>\n\n <!-- Minutes column -->\n <div class=\"ea-time-picker__column\">\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.incrementMinutes\"\n (mousedown)=\"startHold('minutes', 1, $event)\"\n (touchstart)=\"startHold('minutes', 1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-up aria-hidden=\"true\" />\n </button>\n <input\n #minutesEl\n type=\"text\"\n class=\"ea-time-picker__value\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"2\"\n role=\"spinbutton\"\n [attr.aria-label]=\"i18n.messages().timePicker.minutesLabel\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"59\"\n [attr.aria-valuenow]=\"parsed().minutes\"\n [value]=\"minutesText()\"\n (focus)=\"onSpinnerFocus($event)\"\n (input)=\"onSpinnerInput('minutes', $event)\"\n (keydown)=\"handlePopoverKeydown($event, 'minutes')\"\n (blur)=\"onSpinnerBlur()\" />\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.decrementMinutes\"\n (mousedown)=\"startHold('minutes', -1, $event)\"\n (touchstart)=\"startHold('minutes', -1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-down aria-hidden=\"true\" />\n </button>\n </div>\n\n <!-- Seconds column (optional) -->\n @if (includeSeconds()) {\n <span\n class=\"ea-time-picker__separator\"\n aria-hidden=\"true\">\n :\n </span>\n <div class=\"ea-time-picker__column\">\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.incrementSeconds\"\n (mousedown)=\"startHold('seconds', 1, $event)\"\n (touchstart)=\"startHold('seconds', 1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-up aria-hidden=\"true\" />\n </button>\n <input\n #secondsEl\n type=\"text\"\n class=\"ea-time-picker__value\"\n inputmode=\"numeric\"\n autocomplete=\"off\"\n maxlength=\"2\"\n role=\"spinbutton\"\n [attr.aria-label]=\"i18n.messages().timePicker.secondsLabel\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"59\"\n [attr.aria-valuenow]=\"parsed().seconds\"\n [value]=\"secondsText()\"\n (focus)=\"onSpinnerFocus($event)\"\n (input)=\"onSpinnerInput('seconds', $event)\"\n (keydown)=\"handlePopoverKeydown($event, 'seconds')\"\n (blur)=\"onSpinnerBlur()\" />\n <button\n type=\"button\"\n class=\"ea-time-picker__step\"\n [attr.aria-label]=\"i18n.messages().timePicker.decrementSeconds\"\n (mousedown)=\"startHold('seconds', -1, $event)\"\n (touchstart)=\"startHold('seconds', -1, $event)\"\n (mouseup)=\"stopHold()\"\n (mouseleave)=\"stopHold()\"\n (touchend)=\"stopHold()\"\n (touchcancel)=\"stopHold()\">\n <ea-icon-chevron-down aria-hidden=\"true\" />\n </button>\n </div>\n }\n\n <!-- AM/PM toggle (12h only) -->\n @if (format() === '12h') {\n <div class=\"ea-time-picker__period\">\n <button\n type=\"button\"\n class=\"ea-time-picker__period-option\"\n [class.ea-time-picker__period-option--active]=\"period() === 'AM'\"\n (click)=\"period() === 'PM' && togglePeriod()\">\n {{ i18n.messages().timePicker.amLabel }}\n </button>\n <button\n type=\"button\"\n class=\"ea-time-picker__period-option\"\n [class.ea-time-picker__period-option--active]=\"period() === 'PM'\"\n (click)=\"period() === 'AM' && togglePeriod()\">\n {{ i18n.messages().timePicker.pmLabel }}\n </button>\n </div>\n }\n </div>\n </ea-popover>\n </div>\n\n @if (showError()) {\n <p\n class=\"ea-time-picker-field__message ea-time-picker-field__message--error\"\n [id]=\"id() + '-error'\"\n role=\"alert\">\n <ea-icon-alert-circle class=\"ea-time-picker-field__message-icon\" />\n {{ errorMsg() }}\n </p>\n }\n\n @if (showHint()) {\n <p\n class=\"ea-time-picker-field__message ea-time-picker-field__message--hint\"\n [id]=\"id() + '-hint'\">\n {{ hint() }}\n </p>\n }\n</div>\n", styles: [".ea-time-picker-field{display:flex;flex-direction:column;gap:var(--space-1-5)}.ea-time-picker-field__label{font-size:var(--text-label-md-size);font-weight:var(--text-label-md-weight);line-height:var(--text-label-md-lh);color:var(--color-text-primary)}.ea-time-picker-field__label--required:after{content:\" *\";color:var(--color-error-default)}.ea-time-picker-field__message{display:flex;align-items:center;gap:var(--space-1);font-size:var(--text-helper-size);font-weight:var(--text-helper-weight);line-height:var(--text-helper-lh)}.ea-time-picker-field__message--hint{color:var(--color-text-secondary)}.ea-time-picker-field__message--error{color:var(--color-error-default)}.ea-time-picker-field__message-icon{flex-shrink:0;width:.875em;height:.875em}.ea-time-picker,.ea-time-picker__trigger-wrapper{position:relative}.ea-time-picker__trigger{display:flex;align-items:center;gap:var(--space-2);width:100%;background-color:var(--color-bg-base);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);font-family:var(--font-family-sans);color:var(--color-text-primary);cursor:pointer;transition:var(--transition-colors),var(--transition-shadow);text-align:left}.ea-time-picker__trigger:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__trigger--sm{padding:var(--space-1-5) var(--space-2);font-size:var(--font-size-sm);min-height:2rem}.ea-time-picker__trigger--md{padding:var(--space-2) var(--space-3);font-size:var(--font-size-sm);min-height:2.5rem}.ea-time-picker__trigger--lg{padding:var(--space-2-5) var(--space-4);font-size:var(--font-size-md);min-height:3rem}.ea-time-picker__trigger--open{border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring)}.ea-time-picker__trigger--error{border-color:var(--color-error-default)}.ea-time-picker__trigger--error.ea-time-picker__trigger--open{box-shadow:var(--shadow-focus-ring-error)}.ea-time-picker__trigger--disabled{background-color:var(--color-bg-muted);opacity:.6;cursor:not-allowed}.ea-time-picker__trigger--placeholder .ea-time-picker__trigger-value{color:var(--color-text-tertiary)}.ea-time-picker__trigger-icon{flex-shrink:0;width:1em;height:1em;color:var(--color-text-secondary)}.ea-time-picker__trigger-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums}.ea-time-picker__clear{position:absolute;top:50%;right:var(--space-2);z-index:1;display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.25rem;height:1.25rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);font-size:1rem;line-height:1;cursor:pointer;transition:var(--transition-colors);transform:translateY(-50%)}.ea-time-picker__clear:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__clear:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-time-picker__popover{display:flex;align-items:center;gap:var(--space-2);padding:var(--space-3);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-md);box-shadow:var(--shadow-lg);background-color:var(--color-bg-base)}.ea-time-picker__column{display:flex;flex-direction:column;align-items:stretch;gap:var(--space-1)}.ea-time-picker__step{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2.25rem;height:1.75rem;padding:0;border:none;border-radius:var(--radius-sm);background:none;color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-time-picker__step:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-time-picker__step:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__step ea-icon-chevron-up,.ea-time-picker__step ea-icon-chevron-down{width:.875em;height:.875em}.ea-time-picker__value{width:2.25rem;height:2.25rem;padding:0;border:var(--border-width-thin) solid transparent;border-radius:var(--radius-sm);background-color:var(--color-bg-muted);font-family:var(--font-family-mono);font-size:var(--font-size-md);font-weight:var(--font-weight-medium);text-align:center;color:var(--color-text-primary);font-variant-numeric:tabular-nums;appearance:none;cursor:text}.ea-time-picker__value::selection{background-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-time-picker__value:hover{border-color:var(--color-border-default)}.ea-time-picker__value:focus{outline:none;border-color:var(--color-border-focus);box-shadow:var(--shadow-focus-ring);background-color:var(--color-bg-base)}.ea-time-picker__separator{font-family:var(--font-family-mono);font-size:var(--font-size-md);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);-webkit-user-select:none;user-select:none}.ea-time-picker__period{display:flex;flex-direction:column;gap:var(--space-1);margin-left:var(--space-1)}.ea-time-picker__period-option{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:2.5rem;padding:var(--space-1) var(--space-2);border:var(--border-width-thin) solid var(--color-border-default);border-radius:var(--radius-sm);background-color:var(--color-bg-base);font-family:var(--font-family-sans);font-size:var(--font-size-xs);font-weight:var(--font-weight-medium);color:var(--color-text-secondary);cursor:pointer;transition:var(--transition-colors)}.ea-time-picker__period-option:hover{background-color:var(--color-bg-muted);color:var(--color-text-primary)}.ea-time-picker__period-option:focus-visible{outline:none;box-shadow:var(--shadow-focus-ring)}.ea-time-picker__period-option--active{background-color:var(--color-brand-default);border-color:var(--color-brand-default);color:var(--color-text-inverse)}.ea-time-picker__period-option--active:hover{background-color:var(--color-brand-hover);border-color:var(--color-brand-hover);color:var(--color-text-inverse)}\n"] }]
29973
+ }], ctorParameters: () => [], propDecorators: { triggerEl: [{ type: i0.ViewChild, args: ['triggerEl', { isSignal: true }] }], hoursEl: [{ type: i0.ViewChild, args: ['hoursEl', { isSignal: true }] }], minutesEl: [{ type: i0.ViewChild, args: ['minutesEl', { isSignal: true }] }], secondsEl: [{ type: i0.ViewChild, args: ['secondsEl', { isSignal: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], errorMsg: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMsg", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], includeSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "includeSeconds", required: false }] }], minuteStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "minuteStep", required: false }] }], secondStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "secondStep", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
29974
+ // ─── Constants ──────────────────────────────────────────────────────────
29975
+ /** Delay before a held chevron button starts repeating, in ms. */
29976
+ const HOLD_INITIAL_DELAY = 400;
29977
+ /** Repeat interval while a chevron button is held, in ms. */
29978
+ const HOLD_INTERVAL_MS = 90;
29979
+ /** After this many ms of continuous hold, the repeat accelerates. */
29980
+ const HOLD_ACCELERATE_AFTER_MS = 1500;
29981
+ /** Repeat interval once the long-press has accelerated, in ms. */
29982
+ const HOLD_FAST_INTERVAL_MS = 35;
29983
+ // ─── Pure helpers ───────────────────────────────────────────────────────
29984
+ /** Pad a 0–59 unit to two digits. */
29985
+ function pad2(n) {
29986
+ return n < 10 ? `0${n}` : `${n}`;
29987
+ }
29988
+ /** Parse `"HH:MM"` / `"HH:MM:SS"`; returns `null` for any malformed input. */
29989
+ function parseTime(input) {
29990
+ if (!input)
29991
+ return null;
29992
+ const match = /^(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/.exec(input.trim());
29993
+ if (!match)
29994
+ return null;
29995
+ const hours = clamp(parseInt(match[1], 10), 0, 23);
29996
+ const minutes = clamp(parseInt(match[2], 10), 0, 59);
29997
+ const seconds = match[3] !== undefined ? clamp(parseInt(match[3], 10), 0, 59) : 0;
29998
+ if (isNaN(hours) || isNaN(minutes) || isNaN(seconds))
29999
+ return null;
30000
+ return { hours, minutes, seconds };
30001
+ }
30002
+ function clamp(n, lo, hi) {
30003
+ return Math.min(hi, Math.max(lo, n));
30004
+ }
30005
+ function formatTime(time, includeSeconds) {
30006
+ const base = `${pad2(time.hours)}:${pad2(time.minutes)}`;
30007
+ return includeSeconds ? `${base}:${pad2(time.seconds)}` : base;
30008
+ }
30009
+ /** Wrap-around step for a unit. Hours wrap at 24, minutes/seconds at 60. */
30010
+ function nextTime(current, unit, direction, minuteStep, secondStep) {
30011
+ const { hours, minutes, seconds } = current;
30012
+ if (unit === 'hours') {
30013
+ const nextHours = (hours + direction + 24) % 24;
30014
+ return { hours: nextHours, minutes, seconds };
30015
+ }
30016
+ if (unit === 'minutes') {
30017
+ const nextMinutes = (minutes + direction * minuteStep + 60) % 60;
30018
+ return { hours, minutes: nextMinutes, seconds };
30019
+ }
30020
+ const nextSeconds = (seconds + direction * secondStep + 60) % 60;
30021
+ return { hours, minutes, seconds: nextSeconds };
30022
+ }
30023
+
28438
30024
  /**
28439
30025
  * Application-wide notification service. Use the convenience methods
28440
30026
  * (`success`, `error`, `warning`, `info`) to push a toast, or call
@@ -28519,5 +30105,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImpo
28519
30105
  * Generated bundle index. Do not edit.
28520
30106
  */
28521
30107
 
28522
- export { AccordionComponent, AccordionItemComponent, ActivityIconComponent, AirplayIconComponent, AlertCircleIconComponent, AlertComponent, AlertOctagonIconComponent, AlertTriangleIconComponent, AlignCenterIconComponent, AlignJustifyIconComponent, AlignLeftIconComponent, AlignRightIconComponent, AnchorIconComponent, ApertureIconComponent, AppleIconComponent, ArchiveIconComponent, ArrowDownCircleIconComponent, ArrowDownIconComponent, ArrowDownLeftIconComponent, ArrowDownRightIconComponent, ArrowLeftCircleIconComponent, ArrowLeftIconComponent, ArrowRightCircleIconComponent, ArrowRightIconComponent, ArrowUpCircleIconComponent, ArrowUpIconComponent, ArrowUpLeftIconComponent, ArrowUpRightIconComponent, AtSignIconComponent, AutocompleteComponent, AvatarComponent, AvatarEditorComponent, AwardIconComponent, BadgeComponent, BarChart2IconComponent, BarChartIconComponent, BatteryChargingIconComponent, BatteryIconComponent, BellIconComponent, BellOffIconComponent, BluetoothIconComponent, BoldIconComponent, BookIconComponent, BookOpenIconComponent, BookmarkIconComponent, BottleIconComponent, BoxIconComponent, BreadcrumbsComponent, BriefcaseIconComponent, ButtonComponent, CalendarIconComponent, CameraIconComponent, CameraOffIconComponent, CandleIconComponent, CardComponent, CastIconComponent, CheckCircleIconComponent, CheckIconComponent, CheckSquareIconComponent, CheckboxComponent, ChevronDownIconComponent, ChevronLeftIconComponent, ChevronRightIconComponent, ChevronUpIconComponent, ChevronsDownIconComponent, ChevronsLeftIconComponent, ChevronsRightIconComponent, ChevronsUpDownIconComponent, ChevronsUpIconComponent, ChromeIconComponent, CircleIconComponent, ClipboardIconComponent, ClockIconComponent, CloudDrizzleIconComponent, CloudIconComponent, CloudLightningIconComponent, CloudOffIconComponent, CloudRainIconComponent, CloudSnowIconComponent, CloudflareIconComponent, CodeIconComponent, CodeInputComponent, CodepenIconComponent, CodesandboxIconComponent, CoffeeIconComponent, ColorPickerComponent, ColumnsIconComponent, CommandIconComponent, CompassIconComponent, CopyIconComponent, CornerDownLeftIconComponent, CornerDownRightIconComponent, CornerLeftDownIconComponent, CornerLeftUpIconComponent, CornerRightDownIconComponent, CornerRightUpIconComponent, CornerUpLeftIconComponent, CornerUpRightIconComponent, CpuIconComponent, CreditCardIconComponent, CropIconComponent, CrosshairIconComponent, DataTableComponent, DatabaseIconComponent, DatePickerComponent, DeleteIconComponent, DialogComponent, DiscIconComponent, DiscordIconComponent, DivideCircleIconComponent, DivideIconComponent, DivideSquareIconComponent, DividerComponent, DockerIconComponent, DollarSignIconComponent, DownloadCloudIconComponent, DownloadIconComponent, DrawerComponent, DribbbleIconComponent, DropboxIconComponent, DropdownComponent, DropletIconComponent, EAGAMI_I18N_CONFIG, EAGAMI_LOCALES, EAGAMI_MESSAGES, EagamiI18nService, EagamiIconComponent, EagamiWordmarkComponent, Edit2IconComponent, Edit3IconComponent, EditIconComponent, EmptyStateComponent, ExternalLinkIconComponent, EyeIconComponent, EyeOffIconComponent, Facebook2IconComponent, FacebookIconComponent, FastForwardIconComponent, FeatherIconComponent, Figma2IconComponent, FigmaIconComponent, FileIconComponent, FileMinusIconComponent, FilePlusIconComponent, FileTextIconComponent, FilmIconComponent, FilterIconComponent, FlagIconComponent, FolderIconComponent, FolderMinusIconComponent, FolderPlusIconComponent, FramerIconComponent, FrownIconComponent, GiftIconComponent, GitBranchIconComponent, GitCommitIconComponent, GitMergeIconComponent, GitPullRequestIconComponent, Github2IconComponent, GithubIconComponent, GitlabIconComponent, GlobeIconComponent, GoogleIconComponent, GridIconComponent, HardDriveIconComponent, HashIconComponent, HeadphonesIconComponent, HeartIconComponent, HelpCircleIconComponent, HeptagonIconComponent, HexagonIconComponent, HomeIconComponent, ICONS, IconComponentBase, ImageIconComponent, InboxIconComponent, InfoIconComponent, InputComponent, InstagramIconComponent, ItalicIconComponent, KeyIconComponent, KubernetesIconComponent, LampIconComponent, LayersIconComponent, LayoutIconComponent, LifeBuoyIconComponent, Link2IconComponent, LinkIconComponent, Linkedin2IconComponent, LinkedinIconComponent, ListIconComponent, LoaderIconComponent, LockIconComponent, LogInIconComponent, LogOutIconComponent, MailIconComponent, MapIconComponent, MapPinIconComponent, MastercardIconComponent, Maximize2IconComponent, MaximizeIconComponent, MehIconComponent, MenuComponent, MenuIconComponent, MenuItemComponent, MenuTriggerDirective, MessageCircleIconComponent, MessageSquareIconComponent, MicIconComponent, MicOffIconComponent, MicrosoftIconComponent, Minimize2IconComponent, MinimizeIconComponent, MinusCircleIconComponent, MinusIconComponent, MinusSquareIconComponent, MongodbIconComponent, MonitorIconComponent, MoonIconComponent, MoreHorizontalIconComponent, MoreVerticalIconComponent, MousePointerIconComponent, MoveIconComponent, MusicIconComponent, Navigation2IconComponent, NavigationIconComponent, NetlifyIconComponent, NotionIconComponent, NpmIconComponent, OctagonIconComponent, PackageIconComponent, PaginatorComponent, PaperclipIconComponent, PauseCircleIconComponent, PauseIconComponent, PaypalIconComponent, PenToolIconComponent, PencilIconComponent, PentagonIconComponent, PercentIconComponent, PhoneCallIconComponent, PhoneForwardedIconComponent, PhoneIconComponent, PhoneIncomingIconComponent, PhoneMissedIconComponent, PhoneOffIconComponent, PhoneOutgoingIconComponent, PieChartIconComponent, PlayCircleIconComponent, PlayIconComponent, PlusCircleIconComponent, PlusIconComponent, PlusSquareIconComponent, PocketIconComponent, PowerIconComponent, PrinterIconComponent, ProgressBarComponent, RadioComponent, RadioGroupComponent, RadioIconComponent, RectangleHorizontalIconComponent, RectangleVerticalIconComponent, RedditIconComponent, RefreshCcwIconComponent, RefreshCwIconComponent, RepeatIconComponent, RewindIconComponent, RotateCcwIconComponent, RotateCwIconComponent, RssIconComponent, SaveIconComponent, ScissorsIconComponent, SearchIconComponent, SegmentedComponent, SendIconComponent, ServerIconComponent, SettingsIconComponent, Share2IconComponent, ShareIconComponent, ShieldIconComponent, ShieldOffIconComponent, ShoppingBagIconComponent, ShoppingCartIconComponent, ShuffleIconComponent, SidebarIconComponent, SkeletonComponent, SkipBackIconComponent, SkipForwardIconComponent, Slack2IconComponent, SlackIconComponent, SlashIconComponent, SliderComponent, SlidersIconComponent, SmartphoneIconComponent, SmileIconComponent, SoccerBallIconComponent, SpeakerIconComponent, SpinnerComponent, SpotifyIconComponent, SquareIconComponent, StarIconComponent, StopCircleIconComponent, StripeIconComponent, SunIconComponent, SunriseIconComponent, SunsetIconComponent, SwitchComponent, TabComponent, TableIconComponent, TabletIconComponent, TabsComponent, TagComponent, TagIconComponent, TargetIconComponent, TerminalIconComponent, TextareaComponent, ThermometerIconComponent, ThumbsDownIconComponent, ThumbsUpIconComponent, ToastComponent, ToastService, ToggleLeftIconComponent, ToggleRightIconComponent, ToolIconComponent, TooltipDirective, Trash2IconComponent, TrashIconComponent, TrelloIconComponent, TrendingDownIconComponent, TrendingUpIconComponent, TriangleIconComponent, TrophyIconComponent, TruckIconComponent, TvIconComponent, Twitch2IconComponent, TwitchIconComponent, TwitterIconComponent, TypeIconComponent, UmbrellaIconComponent, UnderlineIconComponent, UnlockIconComponent, UploadCloudIconComponent, UploadIconComponent, UserCheckIconComponent, UserIconComponent, UserMinusIconComponent, UserPlusIconComponent, UserXIconComponent, UsersIconComponent, VercelIconComponent, VideoIconComponent, VideoOffIconComponent, VoicemailIconComponent, Volume1IconComponent, Volume2IconComponent, VolumeIconComponent, VolumeXIconComponent, WatchIconComponent, WifiIconComponent, WifiOffIconComponent, WindIconComponent, XCircleIconComponent, XIconComponent, XOctagonIconComponent, XSquareIconComponent, XTwitterIconComponent, Youtube2IconComponent, YoutubeIconComponent, ZapIconComponent, ZapOffIconComponent, ZoomInIconComponent, ZoomOutIconComponent, el, en, esES, frFR, frenchSpacing, iconDisplayName, pl, provideEagamiUi };
30108
+ export { AccordionComponent, AccordionItemComponent, ActivityIconComponent, AirplayIconComponent, AlertCircleIconComponent, AlertComponent, AlertOctagonIconComponent, AlertTriangleIconComponent, AlignCenterIconComponent, AlignJustifyIconComponent, AlignLeftIconComponent, AlignRightIconComponent, AnchorIconComponent, ApertureIconComponent, ArchiveIconComponent, ArrowDownCircleIconComponent, ArrowDownIconComponent, ArrowDownLeftIconComponent, ArrowDownRightIconComponent, ArrowLeftCircleIconComponent, ArrowLeftIconComponent, ArrowRightCircleIconComponent, ArrowRightIconComponent, ArrowUpCircleIconComponent, ArrowUpIconComponent, ArrowUpLeftIconComponent, ArrowUpRightIconComponent, AtSignIconComponent, AutocompleteComponent, AvatarComponent, AvatarEditorComponent, AwardIconComponent, BadgeComponent, BarChart2IconComponent, BarChartIconComponent, BatteryChargingIconComponent, BatteryIconComponent, BellIconComponent, BellOffIconComponent, BluetoothIconComponent, BoldIconComponent, BookIconComponent, BookOpenIconComponent, BookmarkIconComponent, BottleIconComponent, BoxIconComponent, BreadcrumbsComponent, BriefcaseIconComponent, ButtonComponent, CalendarIconComponent, CameraIconComponent, CameraOffIconComponent, CandleIconComponent, CardComponent, CastIconComponent, CheckCircleIconComponent, CheckIconComponent, CheckSquareIconComponent, CheckboxComponent, ChevronDownIconComponent, ChevronLeftIconComponent, ChevronRightIconComponent, ChevronUpIconComponent, ChevronsDownIconComponent, ChevronsLeftIconComponent, ChevronsRightIconComponent, ChevronsUpDownIconComponent, ChevronsUpIconComponent, ChromeIconComponent, CircleIconComponent, ClipboardIconComponent, ClockIconComponent, CloudDrizzleIconComponent, CloudIconComponent, CloudLightningIconComponent, CloudOffIconComponent, CloudRainIconComponent, CloudSnowIconComponent, CloudflareIconComponent, CodeIconComponent, CodeInputComponent, CodepenIconComponent, CodesandboxIconComponent, CoffeeIconComponent, ColorPickerComponent, ColumnsIconComponent, CommandIconComponent, CompassIconComponent, CopyIconComponent, CornerDownLeftIconComponent, CornerDownRightIconComponent, CornerLeftDownIconComponent, CornerLeftUpIconComponent, CornerRightDownIconComponent, CornerRightUpIconComponent, CornerUpLeftIconComponent, CornerUpRightIconComponent, CpuIconComponent, CreditCardIconComponent, CropIconComponent, CrosshairIconComponent, DataTableComponent, DatabaseIconComponent, DatePickerComponent, DeleteIconComponent, DialogComponent, DiscIconComponent, DiscordIconComponent, DivideCircleIconComponent, DivideIconComponent, DivideSquareIconComponent, DividerComponent, DockerIconComponent, DollarSignIconComponent, DownloadCloudIconComponent, DownloadIconComponent, DrawerComponent, DribbbleIconComponent, DropboxIconComponent, DropdownComponent, DropletIconComponent, EAGAMI_I18N_CONFIG, EAGAMI_LOCALES, EAGAMI_MESSAGES, EagamiI18nService, EagamiIconComponent, EagamiWordmarkComponent, Edit2IconComponent, Edit3IconComponent, EditIconComponent, EmptyStateComponent, ExternalLinkIconComponent, EyeIconComponent, EyeOffIconComponent, Facebook2IconComponent, FacebookIconComponent, FastForwardIconComponent, FeatherIconComponent, Figma2IconComponent, FigmaIconComponent, FileIconComponent, FileMinusIconComponent, FilePlusIconComponent, FileTextIconComponent, FilmIconComponent, FilterIconComponent, FlagIconComponent, FolderIconComponent, FolderMinusIconComponent, FolderPlusIconComponent, FramerIconComponent, FrownIconComponent, GiftIconComponent, GitBranchIconComponent, GitCommitIconComponent, GitMergeIconComponent, GitPullRequestIconComponent, Github2IconComponent, GithubIconComponent, GitlabIconComponent, GlobeIconComponent, GoogleIconComponent, GridIconComponent, HardDriveIconComponent, HashIconComponent, HeadphonesIconComponent, HeartIconComponent, HelpCircleIconComponent, HeptagonIconComponent, HexagonIconComponent, HomeIconComponent, ICONS, IconComponentBase, ImageIconComponent, InboxIconComponent, InfoIconComponent, InputComponent, InstagramIconComponent, ItalicIconComponent, KeyIconComponent, KubernetesIconComponent, LampIconComponent, LayersIconComponent, LayoutIconComponent, LeftHalfStarIconComponent, LifeBuoyIconComponent, Link2IconComponent, LinkIconComponent, Linkedin2IconComponent, LinkedinIconComponent, ListIconComponent, LoaderIconComponent, LockIconComponent, LogInIconComponent, LogOutIconComponent, MailIconComponent, MapIconComponent, MapPinIconComponent, MastercardIconComponent, Maximize2IconComponent, MaximizeIconComponent, MehIconComponent, MenuComponent, MenuIconComponent, MenuItemComponent, MenuTriggerDirective, MessageCircleIconComponent, MessageSquareIconComponent, MicIconComponent, MicOffIconComponent, MicrosoftIconComponent, Minimize2IconComponent, MinimizeIconComponent, MinusCircleIconComponent, MinusIconComponent, MinusSquareIconComponent, MongodbIconComponent, MonitorIconComponent, MoonIconComponent, MoreHorizontalIconComponent, MoreVerticalIconComponent, MousePointerIconComponent, MoveIconComponent, MultiSelectComponent, MusicIconComponent, Navigation2IconComponent, NavigationIconComponent, NetlifyIconComponent, NotionIconComponent, NpmIconComponent, OctagonIconComponent, PackageIconComponent, PaginatorComponent, PaperclipIconComponent, PauseCircleIconComponent, PauseIconComponent, PaypalIconComponent, PenToolIconComponent, PentagonIconComponent, PercentIconComponent, PhoneCallIconComponent, PhoneForwardedIconComponent, PhoneIconComponent, PhoneIncomingIconComponent, PhoneMissedIconComponent, PhoneOffIconComponent, PhoneOutgoingIconComponent, PieChartIconComponent, PlayCircleIconComponent, PlayIconComponent, PlusCircleIconComponent, PlusIconComponent, PlusSquareIconComponent, PocketIconComponent, PopoverComponent, PowerIconComponent, PrinterIconComponent, ProgressBarComponent, RadioComponent, RadioGroupComponent, RadioIconComponent, RangeSliderComponent, RectangleHorizontalIconComponent, RectangleVerticalIconComponent, RedditIconComponent, RefreshCcwIconComponent, RefreshCwIconComponent, RepeatIconComponent, RewindIconComponent, RightHalfStarIconComponent, RotateCcwIconComponent, RotateCwIconComponent, RssIconComponent, SaveIconComponent, ScissorsIconComponent, SearchIconComponent, SegmentedComponent, SendIconComponent, ServerIconComponent, SettingsIconComponent, Share2IconComponent, ShareIconComponent, ShieldIconComponent, ShieldOffIconComponent, ShoppingBagIconComponent, ShoppingCartIconComponent, ShuffleIconComponent, SidebarIconComponent, SkeletonComponent, SkipBackIconComponent, SkipForwardIconComponent, Slack2IconComponent, SlackIconComponent, SlashIconComponent, SliderComponent, SlidersIconComponent, SmartphoneIconComponent, SmileIconComponent, SoccerBallIconComponent, SpeakerIconComponent, SpinnerComponent, SpotifyIconComponent, SquareIconComponent, StarIconComponent, StepComponent, StepperComponent, StopCircleIconComponent, StripeIconComponent, SunIconComponent, SunriseIconComponent, SunsetIconComponent, SwitchComponent, TabComponent, TableIconComponent, TabletIconComponent, TabsComponent, TagComponent, TagIconComponent, TargetIconComponent, TerminalIconComponent, TextareaComponent, ThermometerIconComponent, ThumbsDownIconComponent, ThumbsUpIconComponent, TimePickerComponent, ToastComponent, ToastService, ToggleLeftIconComponent, ToggleRightIconComponent, ToolIconComponent, TooltipDirective, Trash2IconComponent, TrashIconComponent, TrelloIconComponent, TrendingDownIconComponent, TrendingUpIconComponent, TriangleIconComponent, TrophyIconComponent, TruckIconComponent, TvIconComponent, Twitch2IconComponent, TwitchIconComponent, TwitterIconComponent, TypeIconComponent, UmbrellaIconComponent, UnderlineIconComponent, UnlockIconComponent, UploadCloudIconComponent, UploadIconComponent, UserCheckIconComponent, UserIconComponent, UserMinusIconComponent, UserPlusIconComponent, UserXIconComponent, UsersIconComponent, VercelIconComponent, VideoIconComponent, VideoOffIconComponent, VoicemailIconComponent, Volume1IconComponent, Volume2IconComponent, VolumeIconComponent, VolumeXIconComponent, WatchIconComponent, WifiIconComponent, WifiOffIconComponent, WindIconComponent, XCircleIconComponent, XIconComponent, XOctagonIconComponent, XSquareIconComponent, XTwitterIconComponent, Youtube2IconComponent, YoutubeIconComponent, ZapIconComponent, ZapOffIconComponent, ZoomInIconComponent, ZoomOutIconComponent, computePopoverPosition, el, en, esES, frFR, frenchSpacing, iconDisplayName, pl, provideEagamiUi };
28523
30109
  //# sourceMappingURL=eagami-ui.mjs.map