ps-helix 7.0.0 → 7.0.2

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, inject, PLATFORM_ID, signal, computed, afterNextRender, Injectable, isDevMode, viewChild, model, output, input, effect, ChangeDetectionStrategy, Component, ElementRef, Injector, DestroyRef, Directive, Renderer2, NgZone, contentChild, linkedSignal, contentChildren, viewChildren, ChangeDetectorRef, ViewContainerRef, makeEnvironmentProviders, ViewEncapsulation, afterRenderEffect } from '@angular/core';
2
+ import { InjectionToken, inject, PLATFORM_ID, signal, computed, afterNextRender, Injectable, isDevMode, viewChild, model, output, input, effect, ChangeDetectionStrategy, Component, ElementRef, Injector, DestroyRef, Directive, Renderer2, contentChild, linkedSignal, contentChildren, viewChildren, NgZone, ChangeDetectorRef, ViewContainerRef, makeEnvironmentProviders, ViewEncapsulation, afterRenderEffect } from '@angular/core';
3
3
  import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet } from '@angular/common';
4
4
  import { NG_VALIDATORS, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
5
5
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@@ -214,23 +214,31 @@ class ThemeService {
214
214
  this.initializeTheme();
215
215
  afterNextRender(() => this.applyCustomerTheme());
216
216
  }
217
+ /**
218
+ * Switches theme *and* remembers the choice — the two halves of what a theme toggle
219
+ * means. They used to be split across two methods: `setDarkTheme` wrote `data-theme`
220
+ * without persisting, `updateTheme` persisted without writing `data-theme`. Whichever
221
+ * one a consumer picked, half the job was missing, and the demo's own toggle reverted
222
+ * on every reload.
223
+ */
217
224
  setDarkTheme(isDark) {
218
- if (this.isBrowser) {
219
- this.document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
220
- }
221
- this.isDarkThemeSignal.set(isDark);
222
- this.themeNameSignal.set(isDark ? 'dark' : 'light');
223
- this.lastChangeSignal.set(new Date());
224
- this.applyCustomerTheme();
225
+ this.applyTheme(isDark);
226
+ this.saveThemePreference(isDark ? 'dark' : 'light');
225
227
  }
226
228
  toggleTheme() {
227
229
  this.setDarkTheme(!this.isDarkThemeSignal());
228
230
  }
229
231
  updateTheme(name) {
230
- this.themeNameSignal.set(name);
231
- this.isDarkThemeSignal.set(name === 'dark');
232
+ this.setDarkTheme(name === 'dark');
233
+ }
234
+ /** The visible half: the attribute the stylesheets read, and the derived palette. */
235
+ applyTheme(isDark) {
236
+ if (this.isBrowser) {
237
+ this.document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
238
+ }
239
+ this.isDarkThemeSignal.set(isDark);
240
+ this.themeNameSignal.set(isDark ? 'dark' : 'light');
232
241
  this.lastChangeSignal.set(new Date());
233
- this.saveThemePreference(name);
234
242
  this.applyCustomerTheme();
235
243
  }
236
244
  /**
@@ -322,7 +330,9 @@ class ThemeService {
322
330
  const isValid = savedTheme === 'light' || savedTheme === 'dark';
323
331
  // No stored preference → honour the OS "prefers-color-scheme" setting.
324
332
  const initial = isValid ? savedTheme : this.prefersDarkScheme() ? 'dark' : 'light';
325
- this.setDarkTheme(initial === 'dark');
333
+ // Applied, not saved: with nothing stored the theme follows the OS, and writing the
334
+ // first value read would pin it there forever.
335
+ this.applyTheme(initial === 'dark');
326
336
  }
327
337
  /** True when the OS/browser requests a dark colour scheme. */
328
338
  prefersDarkScheme() {
@@ -1231,6 +1241,82 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
1231
1241
  args: [{ providedIn: 'root' }]
1232
1242
  }] });
1233
1243
 
1244
+ /**
1245
+ * One media query per breakpoint, for the whole application.
1246
+ *
1247
+ * `psh-card` and `psh-info-card` each built a `ResizeObserver` on `document.documentElement`
1248
+ * to answer one question — is the viewport narrow? — so a grid of fifty cards installed fifty
1249
+ * observers on the root element, each firing on every resize frame. The answer is the same for
1250
+ * all of them, and `matchMedia` gives it without measuring anything: the browser evaluates the
1251
+ * query and fires only when it flips.
1252
+ *
1253
+ * The queries are also back on the documented scale. Both components asked
1254
+ * `innerWidth <= 640`, a pixel breakpoint written in TypeScript, which is why
1255
+ * `verify:breakpoints` never saw it — that script reads stylesheets. An `em` query follows the
1256
+ * user's root font size, so a component and the CSS beside it switch together under zoom.
1257
+ *
1258
+ * @example
1259
+ * private readonly viewport = inject(PshViewportService);
1260
+ * readonly isMobile = this.viewport.below('sm');
1261
+ */
1262
+ /** The scale of `breakpoints.tokens.css`, as the exclusive `max-width` of each step. */
1263
+ const BELOW = {
1264
+ xs: '29.9375em',
1265
+ sm: '39.9375em',
1266
+ md: '47.9375em',
1267
+ lg: '63.9375em',
1268
+ xl: '79.9375em',
1269
+ '2xl': '95.9375em',
1270
+ };
1271
+ class PshViewportService {
1272
+ constructor() {
1273
+ this.document = inject(DOCUMENT);
1274
+ this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
1275
+ this.destroyRef = inject(DestroyRef);
1276
+ /** One entry per distinct query, however many components ask for it. */
1277
+ this.queries = new Map();
1278
+ }
1279
+ /**
1280
+ * Whether the viewport is narrower than the given breakpoint.
1281
+ *
1282
+ * Exclusive, like the `max-width` rules in the stylesheets: at exactly the breakpoint the
1283
+ * answer is `false`, so a component and its CSS never disagree about which side they are on.
1284
+ *
1285
+ * On the server it is `false` and never changes — the same value the components defaulted to
1286
+ * before, so the first paint is unchanged.
1287
+ */
1288
+ below(breakpoint) {
1289
+ return this.matches(`(max-width: ${BELOW[breakpoint]})`);
1290
+ }
1291
+ /** Any media query, as a signal. Shared with every other caller that passes the same one. */
1292
+ matches(query) {
1293
+ const existing = this.queries.get(query);
1294
+ if (existing)
1295
+ return existing;
1296
+ const state = signal(false, /* @ts-ignore */
1297
+ ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
1298
+ // The read-only view is what is cached, so two callers get the *same* signal rather than
1299
+ // two wrappers over one — and nothing outside can write it.
1300
+ const readonly = state.asReadonly();
1301
+ this.queries.set(query, readonly);
1302
+ const view = this.isBrowser ? this.document.defaultView : null;
1303
+ if (view?.matchMedia) {
1304
+ const list = view.matchMedia(query);
1305
+ state.set(list.matches);
1306
+ const onChange = (event) => state.set(event.matches);
1307
+ list.addEventListener('change', onChange);
1308
+ this.destroyRef.onDestroy(() => list.removeEventListener('change', onChange));
1309
+ }
1310
+ return readonly;
1311
+ }
1312
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1313
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshViewportService, providedIn: 'root' }); }
1314
+ }
1315
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshViewportService, decorators: [{
1316
+ type: Injectable,
1317
+ args: [{ providedIn: 'root' }]
1318
+ }] });
1319
+
1234
1320
  /**
1235
1321
  * Injection token for global modal configuration
1236
1322
  *
@@ -1368,7 +1454,6 @@ class PshModalComponent {
1368
1454
  this.overlay = inject(PshOverlayService);
1369
1455
  this.renderer = inject(Renderer2);
1370
1456
  this.platformId = inject(PLATFORM_ID);
1371
- this.zone = inject(NgZone);
1372
1457
  this.document = inject(DOCUMENT);
1373
1458
  /** Elements this modal marked `inert`, so it only ever undoes its own. */
1374
1459
  this.inertedByThisModal = [];
@@ -1379,9 +1464,17 @@ class PshModalComponent {
1379
1464
  this.zIndex = signal(null, /* @ts-ignore */
1380
1465
  ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
1381
1466
  this.isAttachedToBody = false;
1382
- this.isMobileSignal = signal(false, /* @ts-ignore */
1383
- ...(ngDevMode ? [{ debugName: "isMobileSignal" }] : /* istanbul ignore next */ []));
1384
- this.mobileBreakpoint = 768;
1467
+ /**
1468
+ * Read from the shared `matchMedia`, on the same `md` step the stylesheet uses.
1469
+ *
1470
+ * It was `innerWidth < 768` behind a resize listener per modal — a pixel breakpoint written
1471
+ * in TypeScript, which no amount of `verify:breakpoints` could see because that script reads
1472
+ * stylesheets. It also did not follow browser zoom: at 150% the stylesheet switched at an
1473
+ * effective 1150px while this stayed at 768, so the modal was in its mobile layout while
1474
+ * `isMobileScreen()` still said no, and a consumer binding it — the demo does, for full-width
1475
+ * footer buttons — got desktop buttons in a mobile dialog.
1476
+ */
1477
+ this.isMobile = inject(PshViewportService).below('md');
1385
1478
  /**
1386
1479
  * Controls the visibility of the modal (two-way binding)
1387
1480
  */
@@ -1528,8 +1621,7 @@ class PshModalComponent {
1528
1621
  /**
1529
1622
  * Computed signal indicating if the screen is mobile-sized
1530
1623
  */
1531
- this.isMobileScreen = computed(() => this.isMobileSignal(), /* @ts-ignore */
1532
- ...(ngDevMode ? [{ debugName: "isMobileScreen" }] : /* istanbul ignore next */ []));
1624
+ this.isMobileScreen = this.isMobile;
1533
1625
  effect(() => {
1534
1626
  if (this.open()) {
1535
1627
  this.onModalOpen();
@@ -1538,13 +1630,9 @@ class PshModalComponent {
1538
1630
  this.onModalClose();
1539
1631
  }
1540
1632
  });
1541
- if (isPlatformBrowser(this.platformId)) {
1542
- this.checkScreenSize();
1543
- }
1544
1633
  }
1545
1634
  ngAfterViewInit() {
1546
1635
  this.attachModalToBody();
1547
- this.setupResizeListener();
1548
1636
  }
1549
1637
  /**
1550
1638
  * Handles all setup when modal opens
@@ -1607,35 +1695,6 @@ class PshModalComponent {
1607
1695
  }
1608
1696
  this.zIndex.set(null);
1609
1697
  }
1610
- /**
1611
- * Checks if the current screen size is mobile
1612
- */
1613
- checkScreenSize() {
1614
- const view = this.document.defaultView;
1615
- if (view) {
1616
- this.isMobileSignal.set(view.innerWidth < this.mobileBreakpoint);
1617
- }
1618
- }
1619
- /**
1620
- * Sets up resize listener to detect screen size changes
1621
- */
1622
- setupResizeListener() {
1623
- const view = this.document.defaultView;
1624
- if (view) {
1625
- this.resizeListener = () => this.checkScreenSize();
1626
- // Outside Angular: resize fires continuously while a window is dragged, and the
1627
- // handler only writes a signal — which schedules its own refresh when it changes.
1628
- this.zone.runOutsideAngular(() => view.addEventListener('resize', this.resizeListener));
1629
- }
1630
- }
1631
- /**
1632
- * Removes resize listener
1633
- */
1634
- removeResizeListener() {
1635
- if (this.resizeListener) {
1636
- this.document.defaultView?.removeEventListener('resize', this.resizeListener);
1637
- }
1638
- }
1639
1698
  /**
1640
1699
  * Adds keyboard event listeners
1641
1700
  */
@@ -1722,7 +1781,6 @@ class PshModalComponent {
1722
1781
  ngOnDestroy() {
1723
1782
  this.removeScrollLock();
1724
1783
  this.removeEventListeners();
1725
- this.removeResizeListener();
1726
1784
  this.modalService.unregister(this.modalId);
1727
1785
  this.releaseOverlay();
1728
1786
  this.detachModalFromBody();
@@ -2583,7 +2641,7 @@ const SIDEBAR_DEFAULTS = {
2583
2641
  mode: 'fixed',
2584
2642
  position: 'left',
2585
2643
  width: '250px',
2586
- breakpoint: '768px',
2644
+ breakpoint: '47.9375em',
2587
2645
  autoFocus: true,
2588
2646
  ariaLabel: 'Sidebar navigation',
2589
2647
  closeOnBackdrop: true,
@@ -2615,7 +2673,17 @@ class PshSidebarComponent {
2615
2673
  ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
2616
2674
  this.width = input(this.config.width ?? '250px', /* @ts-ignore */
2617
2675
  ...(ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []));
2618
- this.breakpoint = input(this.config.breakpoint ?? '768px', /* @ts-ignore */
2676
+ /**
2677
+ * The width below which the sidebar becomes an overlay.
2678
+ *
2679
+ * Defaults to the `md` step of the library's scale, in `em` like every media query it ships:
2680
+ * a px breakpoint does not follow browser zoom, so at 150% the rest of the page had switched
2681
+ * to its narrow layout while the sidebar was still docked. It is also exclusive — `768px` was
2682
+ * true at exactly 768px, where a `min-width: 48em` rule is true as well.
2683
+ *
2684
+ * Any CSS length is still accepted, so `'768px'` keeps working.
2685
+ */
2686
+ this.breakpoint = input(this.config.breakpoint ?? '47.9375em', /* @ts-ignore */
2619
2687
  ...(ngDevMode ? [{ debugName: "breakpoint" }] : /* istanbul ignore next */ []));
2620
2688
  this.autoFocus = input(this.config.autoFocus ?? true, /* @ts-ignore */
2621
2689
  ...(ngDevMode ? [{ debugName: "autoFocus" }] : /* istanbul ignore next */ []));
@@ -4370,10 +4438,15 @@ class PshInputComponent {
4370
4438
  }
4371
4439
  break;
4372
4440
  case 'Escape':
4373
- event.preventDefault();
4374
- this.suggestionsVisible.set(false);
4375
- this.focusedSuggestionIndex.set(-1);
4376
- this.syncPanel();
4441
+ // Only when suggestions are showing. Otherwise the keypress belongs to whatever
4442
+ // encloses the field — a modal, most often — and must reach it.
4443
+ if (this.suggestionsVisible()) {
4444
+ event.preventDefault();
4445
+ event.stopPropagation();
4446
+ this.suggestionsVisible.set(false);
4447
+ this.focusedSuggestionIndex.set(-1);
4448
+ this.syncPanel();
4449
+ }
4377
4450
  break;
4378
4451
  }
4379
4452
  }
@@ -4799,14 +4872,14 @@ class PshTableComponent {
4799
4872
  this.expandedRowIds.set(new Set());
4800
4873
  }
4801
4874
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4802
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshTableComponent, isStandalone: true, selector: "psh-table", inputs: { appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, hoverable: { classPropertyName: "hoverable", publicName: "hoverable", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, globalSearch: { classPropertyName: "globalSearch", publicName: "globalSearch", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, emptyMessageInput: { classPropertyName: "emptyMessageInput", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessageInput: { classPropertyName: "noResultsMessageInput", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, globalSearchPlaceholderInput: { classPropertyName: "globalSearchPlaceholderInput", publicName: "globalSearchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, tableLayout: { classPropertyName: "tableLayout", publicName: "tableLayout", isSignal: true, isRequired: false, transformFunction: null }, truncateText: { classPropertyName: "truncateText", publicName: "truncateText", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, singleExpand: { classPropertyName: "singleExpand", publicName: "singleExpand", isSignal: true, isRequired: false, transformFunction: null }, expandedRowTemplate: { classPropertyName: "expandedRowTemplate", publicName: "expandedRowTemplate", isSignal: true, isRequired: false, transformFunction: null }, headerTemplate: { classPropertyName: "headerTemplate", publicName: "headerTemplate", isSignal: true, isRequired: false, transformFunction: null }, emptyTemplate: { classPropertyName: "emptyTemplate", publicName: "emptyTemplate", isSignal: true, isRequired: false, transformFunction: null }, rowClass: { classPropertyName: "rowClass", publicName: "rowClass", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, expandColumnLabelInput: { classPropertyName: "expandColumnLabelInput", publicName: "expandColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, expandRowLabelInput: { classPropertyName: "expandRowLabelInput", publicName: "expandRowLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseRowLabelInput: { classPropertyName: "collapseRowLabelInput", publicName: "collapseRowLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", globalSearchChange: "globalSearchChange", rowClicked: "rowClicked", rowExpanded: "rowExpanded", rowCollapsed: "rowCollapsed" }, host: { properties: { "class.psh-full-width": "fullWidth()" }, classAttribute: "psh-table" }, ngImport: i0, template: "<div\r\n class=\"psh-table-wrapper\"\r\n [class.psh-striped]=\"striped()\"\r\n [class.psh-hoverable]=\"hoverable()\"\r\n [class.psh-bordered]=\"bordered()\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-outline]=\"appearance() === 'outline'\"\r\n [class.psh-table-fixed]=\"tableLayout() === 'fixed'\"\r\n [class.psh-truncate]=\"truncateText()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n @if (globalSearch()) {\r\n <div class=\"psh-global-search\" role=\"search\">\r\n <psh-input\r\n [placeholder]=\"globalSearchPlaceholder()\"\r\n [ariaLabel]=\"globalSearchPlaceholder()\"\r\n [size]=\"size()\"\r\n [fullWidth]=\"true\"\r\n [showLabel]=\"false\"\r\n iconStart=\"magnifying-glass\"\r\n type=\"search\"\r\n [(value)]=\"searchTermSignal\"\r\n (valueChange)=\"onSearchValueChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <table role=\"table\" [attr.aria-label]=\"ariaLabel()\">\r\n <thead>\r\n <tr>\r\n @if (expandable()) {\r\n <th class=\"psh-expand-header\" scope=\"col\" [attr.aria-label]=\"expandColumnLabel()\"></th>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <th\r\n [style.width]=\"column.width\"\r\n scope=\"col\"\r\n [attr.aria-sort]=\"column.sortable ? (currentSort()?.key === column.key ? (currentSort()?.direction === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\r\n [class.psh-sortable]=\"column.sortable\"\r\n >\r\n @if (headerTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"headerTemplate()!\"\r\n [ngTemplateOutletContext]=\"headerContext(column)\"\r\n ></ng-container>\r\n } @else if (column.sortable) {\r\n <!-- A real button, so sorting is reachable by keyboard and gets a native\r\n focus ring. The icons are decorative: aria-sort on the th carries the\r\n state, which is why they had aria-hidden cancelling their aria-label. -->\r\n <button\r\n type=\"button\"\r\n class=\"psh-th-content psh-sort-button\"\r\n (click)=\"handleSort(column)\"\r\n >\r\n {{ column.label }}\r\n @if (currentSort()?.key === column.key) {\r\n <i\r\n [class]=\"'ph ' + (currentSort()?.direction === 'desc' ? 'ph-sort-descending' : 'ph-sort-ascending')\"\r\n aria-hidden=\"true\">\r\n </i>\r\n } @else {\r\n <i class=\"ph ph-arrows-down-up psh-sort-icon-neutral\" aria-hidden=\"true\"></i>\r\n }\r\n </button>\r\n } @else {\r\n <div class=\"psh-th-content\">{{ column.label }}</div>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @if (loading()) {\r\n <tr class=\"psh-loading-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <div class=\"psh-loading-indicator\">\r\n <div class=\"psh-spinner\"></div>\r\n </div>\r\n </td>\r\n </tr>\r\n } @else if (filteredData().length === 0) {\r\n <tr class=\"psh-empty-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n @if (emptyTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"emptyTemplate()!\"\r\n [ngTemplateOutletContext]=\"emptyContext()\"\r\n ></ng-container>\r\n } @else {\r\n {{ computedEmptyMessage() }}\r\n }\r\n </td>\r\n </tr>\r\n } @else {\r\n @for (row of filteredData(); track row.id) {\r\n <tr\r\n [class]=\"rowClasses(row)\"\r\n [class.psh-expanded]=\"expandable() && isRowExpanded(row)\"\r\n [attr.tabindex]=\"hoverable() ? 0 : null\"\r\n (click)=\"handleRowClick(row)\"\r\n (keydown.enter)=\"handleRowClick(row)\"\r\n (keydown.space)=\"handleRowClick(row); $event.preventDefault()\"\r\n >\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\">\r\n @if (isRowExpandable(row)) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-expand-toggle\"\r\n [attr.aria-expanded]=\"isRowExpanded(row)\"\r\n [attr.aria-label]=\"isRowExpanded(row) ? collapseRowLabel() : expandRowLabel()\"\r\n (click)=\"toggleRow(row); $event.stopPropagation()\"\r\n >\r\n <i class=\"ph ph-caret-right\"></i>\r\n </button>\r\n }\r\n </td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(row, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n\r\n @if (expandable() && isRowExpanded(row)) {\r\n @if (expandedRowTemplate()) {\r\n <tr class=\"psh-expanded-content-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandedRowTemplate()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row }\"\r\n ></ng-container>\r\n </td>\r\n </tr>\r\n } @else if (row.children?.length) {\r\n @for (child of row.children; track child.id) {\r\n <tr class=\"psh-child-row\">\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\"></td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(child, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [":host{display:block}:host(.psh-full-width){max-width:none;width:100%}.psh-table-wrapper{width:100%;overflow-x:auto;background:var(--psh-surface-card);border-radius:var(--psh-radius-lg)}.psh-table-wrapper.psh-outline{background:transparent;border:var(--psh-border-width-1) solid var(--psh-surface-border)}table{width:100%;border-collapse:collapse;text-align:left}th,td{padding:var(--psh-spacing-md);color:var(--psh-text-color);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}th{font-weight:600;color:var(--psh-text-color);background:var(--psh-surface-ground);white-space:nowrap;-webkit-user-select:none;user-select:none}th.psh-sortable{cursor:pointer}th.psh-sortable:hover{background:var(--psh-surface-hover)}.psh-th-content{display:flex;align-items:center;gap:var(--psh-spacing-xs)}.psh-th-content i{font-size:var(--psh-font-size-base);color:var(--psh-primary-color);display:inline-block;transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-th-content i.psh-sort-icon-neutral{color:var(--psh-text-color-secondary);opacity:.5}th.psh-sortable:hover .psh-sort-icon-neutral{opacity:1;color:var(--psh-primary-color)}.psh-table-wrapper.psh-striped tr:nth-child(2n){background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable tr:hover{background:var(--psh-surface-hover)}.psh-table-wrapper.psh-bordered th,.psh-table-wrapper.psh-bordered td{border:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-table-wrapper.psh-small th,.psh-table-wrapper.psh-small td{padding:var(--psh-spacing-sm);font-size:var(--psh-font-size-sm)}.psh-table-wrapper.psh-large th,.psh-table-wrapper.psh-large td{padding:var(--psh-spacing-lg);font-size:var(--psh-font-size-lg)}.psh-loading-row td,.psh-empty-row td{text-align:center;padding:var(--psh-spacing-xl);color:var(--psh-text-color-secondary)}.psh-loading-indicator{display:flex;justify-content:center;align-items:center}.psh-spinner{width:var(--psh-size-6);height:var(--psh-size-6);border:var(--psh-border-width-2) solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-normal) var(--psh-animation-easing-linear) infinite}@keyframes spin{to{transform:rotate(360deg)}}.psh-global-search{margin-bottom:var(--psh-spacing-md)}.psh-sort-button{width:100%;background:transparent;border:none;padding:0;font:inherit;color:inherit;text-align:left;cursor:pointer;border-radius:var(--psh-radius-lg);transition:color var(--psh-animation-duration-normal) var(--psh-animation-easing-default)}.psh-sort-button:hover{color:var(--psh-primary-color)}.psh-sort-button:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}tbody tr[tabindex]:focus-visible{outline:none;box-shadow:inset 0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-table-wrapper.psh-table-fixed table{table-layout:fixed}.psh-table-wrapper.psh-truncate td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:0}.psh-table-wrapper.psh-truncate th{overflow:hidden;text-overflow:ellipsis}.psh-expand-header{width:48px;min-width:48px;max-width:48px;padding:0}.psh-expand-cell{width:48px;min-width:48px;max-width:48px;text-align:center;padding:var(--psh-spacing-xs);vertical-align:middle}.psh-expand-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--psh-size-8);height:var(--psh-size-8);padding:0;background:transparent;border:none;border-radius:var(--psh-radius-sm);cursor:pointer;color:var(--psh-text-color-secondary);font-size:var(--psh-font-size-base);transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle:hover{color:var(--psh-primary-color);background:var(--psh-surface-hover)}.psh-expand-toggle:focus-visible{outline:var(--psh-focus-outline-width) solid var(--psh-focus-ring-color);outline-offset:2px}.psh-expand-toggle i{display:inline-block;transition:transform var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle[aria-expanded=true] i{transform:rotate(90deg)}tr.psh-expanded{border-bottom-color:transparent}.psh-expanded-content-row td{background:var(--psh-surface-ground);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-child-row{background:var(--psh-surface-ground)}.psh-child-row td{font-size:.95em;color:var(--psh-text-color-secondary)}.psh-table-wrapper.psh-striped .psh-child-row,.psh-table-wrapper.psh-striped .psh-expanded-content-row{background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable .psh-child-row:hover{background:var(--psh-surface-hover)}@media(max-width:47.9375em){.psh-table-wrapper{font-size:var(--psh-font-size-sm)}th,td{padding:var(--psh-spacing-sm)}.psh-global-search{margin-bottom:var(--psh-spacing-sm)}}@media(max-width:29.9375em){.psh-table-wrapper{border-radius:0;margin:0 calc(-1 * var(--psh-spacing-sm))}th,td{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);font-size:var(--psh-font-size-xs)}.psh-th-content{gap:var(--psh-spacing-xxs)}.psh-th-content i{font-size:var(--psh-font-size-sm)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: PshInputComponent, selector: "psh-input", inputs: ["value", "disabled", "readonly", "loading", "touched", "appearance", "size", "fullWidth", "required", "showLabel", "type", "placeholder", "label", "ariaLabel", "iconStart", "iconEnd", "error", "success", "hint", "ariaDescribedBy", "ariaLabelledBy", "suggestions", "autocompleteConfig", "showPasswordLabel", "hidePasswordLabel"], outputs: ["valueChange", "disabledChange", "touchedChange", "touch", "focused", "blurred", "suggestionSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4875
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshTableComponent, isStandalone: true, selector: "psh-table", inputs: { appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, hoverable: { classPropertyName: "hoverable", publicName: "hoverable", isSignal: true, isRequired: false, transformFunction: null }, bordered: { classPropertyName: "bordered", publicName: "bordered", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, globalSearch: { classPropertyName: "globalSearch", publicName: "globalSearch", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, emptyMessageInput: { classPropertyName: "emptyMessageInput", publicName: "emptyMessage", isSignal: true, isRequired: false, transformFunction: null }, noResultsMessageInput: { classPropertyName: "noResultsMessageInput", publicName: "noResultsMessage", isSignal: true, isRequired: false, transformFunction: null }, globalSearchPlaceholderInput: { classPropertyName: "globalSearchPlaceholderInput", publicName: "globalSearchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, tableLayout: { classPropertyName: "tableLayout", publicName: "tableLayout", isSignal: true, isRequired: false, transformFunction: null }, truncateText: { classPropertyName: "truncateText", publicName: "truncateText", isSignal: true, isRequired: false, transformFunction: null }, expandable: { classPropertyName: "expandable", publicName: "expandable", isSignal: true, isRequired: false, transformFunction: null }, singleExpand: { classPropertyName: "singleExpand", publicName: "singleExpand", isSignal: true, isRequired: false, transformFunction: null }, expandedRowTemplate: { classPropertyName: "expandedRowTemplate", publicName: "expandedRowTemplate", isSignal: true, isRequired: false, transformFunction: null }, headerTemplate: { classPropertyName: "headerTemplate", publicName: "headerTemplate", isSignal: true, isRequired: false, transformFunction: null }, emptyTemplate: { classPropertyName: "emptyTemplate", publicName: "emptyTemplate", isSignal: true, isRequired: false, transformFunction: null }, rowClass: { classPropertyName: "rowClass", publicName: "rowClass", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, expandColumnLabelInput: { classPropertyName: "expandColumnLabelInput", publicName: "expandColumnLabel", isSignal: true, isRequired: false, transformFunction: null }, expandRowLabelInput: { classPropertyName: "expandRowLabelInput", publicName: "expandRowLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseRowLabelInput: { classPropertyName: "collapseRowLabelInput", publicName: "collapseRowLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortChange: "sortChange", globalSearchChange: "globalSearchChange", rowClicked: "rowClicked", rowExpanded: "rowExpanded", rowCollapsed: "rowCollapsed" }, host: { properties: { "class.psh-full-width": "fullWidth()" }, classAttribute: "psh-table" }, ngImport: i0, template: "<div\r\n class=\"psh-table-wrapper\"\r\n [class.psh-striped]=\"striped()\"\r\n [class.psh-hoverable]=\"hoverable()\"\r\n [class.psh-bordered]=\"bordered()\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-outline]=\"appearance() === 'outline'\"\r\n [class.psh-table-fixed]=\"tableLayout() === 'fixed'\"\r\n [class.psh-truncate]=\"truncateText()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n @if (globalSearch()) {\r\n <div class=\"psh-global-search\" role=\"search\">\r\n <psh-input\r\n [placeholder]=\"globalSearchPlaceholder()\"\r\n [ariaLabel]=\"globalSearchPlaceholder()\"\r\n [size]=\"size()\"\r\n [fullWidth]=\"true\"\r\n [showLabel]=\"false\"\r\n iconStart=\"magnifying-glass\"\r\n type=\"search\"\r\n [(value)]=\"searchTermSignal\"\r\n (valueChange)=\"onSearchValueChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <table role=\"table\" [attr.aria-label]=\"ariaLabel()\">\r\n <thead>\r\n <tr>\r\n @if (expandable()) {\r\n <th class=\"psh-expand-header\" scope=\"col\" [attr.aria-label]=\"expandColumnLabel()\"></th>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <th\r\n [style.width]=\"column.width\"\r\n scope=\"col\"\r\n [attr.aria-sort]=\"column.sortable ? (currentSort()?.key === column.key ? (currentSort()?.direction === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\r\n [class.psh-sortable]=\"column.sortable\"\r\n >\r\n @if (headerTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"headerTemplate()!\"\r\n [ngTemplateOutletContext]=\"headerContext(column)\"\r\n ></ng-container>\r\n } @else if (column.sortable) {\r\n <!-- A real button, so sorting is reachable by keyboard and gets a native\r\n focus ring. The icons are decorative: aria-sort on the th carries the\r\n state, which is why they had aria-hidden cancelling their aria-label. -->\r\n <button\r\n type=\"button\"\r\n class=\"psh-th-content psh-sort-button\"\r\n (click)=\"handleSort(column)\"\r\n >\r\n {{ column.label }}\r\n @if (currentSort()?.key === column.key) {\r\n <i\r\n [class]=\"'ph ' + (currentSort()?.direction === 'desc' ? 'ph-sort-descending' : 'ph-sort-ascending')\"\r\n aria-hidden=\"true\">\r\n </i>\r\n } @else {\r\n <i class=\"ph ph-arrows-down-up psh-sort-icon-neutral\" aria-hidden=\"true\"></i>\r\n }\r\n </button>\r\n } @else {\r\n <div class=\"psh-th-content\">{{ column.label }}</div>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @if (loading()) {\r\n <tr class=\"psh-loading-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <div class=\"psh-loading-indicator\">\r\n <div class=\"psh-spinner\"></div>\r\n </div>\r\n </td>\r\n </tr>\r\n } @else if (filteredData().length === 0) {\r\n <tr class=\"psh-empty-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n @if (emptyTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"emptyTemplate()!\"\r\n [ngTemplateOutletContext]=\"emptyContext()\"\r\n ></ng-container>\r\n } @else {\r\n {{ computedEmptyMessage() }}\r\n }\r\n </td>\r\n </tr>\r\n } @else {\r\n @for (row of filteredData(); track row.id) {\r\n <tr\r\n [class]=\"rowClasses(row)\"\r\n [class.psh-expanded]=\"expandable() && isRowExpanded(row)\"\r\n [attr.tabindex]=\"hoverable() ? 0 : null\"\r\n (click)=\"handleRowClick(row)\"\r\n (keydown.enter)=\"handleRowClick(row)\"\r\n (keydown.space)=\"handleRowClick(row); $event.preventDefault()\"\r\n >\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\">\r\n @if (isRowExpandable(row)) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-expand-toggle\"\r\n [attr.aria-expanded]=\"isRowExpanded(row)\"\r\n [attr.aria-label]=\"isRowExpanded(row) ? collapseRowLabel() : expandRowLabel()\"\r\n (click)=\"toggleRow(row); $event.stopPropagation()\"\r\n >\r\n <i class=\"ph ph-caret-right\"></i>\r\n </button>\r\n }\r\n </td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(row, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n\r\n @if (expandable() && isRowExpanded(row)) {\r\n @if (expandedRowTemplate()) {\r\n <tr class=\"psh-expanded-content-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandedRowTemplate()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row }\"\r\n ></ng-container>\r\n </td>\r\n </tr>\r\n } @else if (row.children?.length) {\r\n @for (child of row.children; track child.id) {\r\n <tr class=\"psh-child-row\">\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\"></td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(child, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [":host{display:block}:host(.psh-full-width){max-width:none;width:100%}.psh-table-wrapper{width:100%;overflow-x:auto;background:var(--psh-surface-card);border-radius:var(--psh-radius-lg)}.psh-table-wrapper.psh-outline{background:transparent;border:var(--psh-border-width-1) solid var(--psh-surface-border)}table{width:100%;border-collapse:collapse;text-align:left}th,td{padding:var(--psh-spacing-md);color:var(--psh-text-color);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}th{font-weight:600;color:var(--psh-text-color);background:var(--psh-surface-ground);white-space:nowrap;-webkit-user-select:none;user-select:none}th.psh-sortable{cursor:pointer}th.psh-sortable:hover{background:var(--psh-surface-hover)}.psh-th-content{display:flex;align-items:center;gap:var(--psh-spacing-xs)}.psh-th-content i{font-size:var(--psh-font-size-base);color:var(--psh-primary-color);display:inline-block;transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-th-content i.psh-sort-icon-neutral{color:var(--psh-text-color-secondary);opacity:.5}th.psh-sortable:hover .psh-sort-icon-neutral{opacity:1;color:var(--psh-primary-color)}.psh-table-wrapper.psh-striped tr:nth-child(2n){background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable tr:hover{background:var(--psh-surface-hover)}.psh-table-wrapper.psh-bordered th,.psh-table-wrapper.psh-bordered td{border:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-table-wrapper.psh-small th,.psh-table-wrapper.psh-small td{padding:var(--psh-spacing-sm);font-size:var(--psh-font-size-sm)}.psh-table-wrapper.psh-large th,.psh-table-wrapper.psh-large td{padding:var(--psh-spacing-lg);font-size:var(--psh-font-size-lg)}.psh-loading-row td,.psh-empty-row td{text-align:center;padding:var(--psh-spacing-xl);color:var(--psh-text-color-secondary)}.psh-loading-indicator{display:flex;justify-content:center;align-items:center}.psh-spinner{width:var(--psh-size-6);height:var(--psh-size-6);border:var(--psh-border-width-2) solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-normal) var(--psh-animation-easing-linear) infinite}@keyframes spin{to{transform:rotate(360deg)}}.psh-global-search{margin-bottom:var(--psh-spacing-md)}th.psh-sortable{padding:0}.psh-sort-button{width:100%;background:transparent;border:none;padding:var(--psh-spacing-md);font:inherit;color:inherit;text-align:left;cursor:pointer;border-radius:var(--psh-radius-lg);transition:color var(--psh-animation-duration-normal) var(--psh-animation-easing-default)}.psh-sort-button:hover{color:var(--psh-primary-color)}.psh-sort-button:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}tbody tr[tabindex]:focus-visible{outline:none;box-shadow:inset 0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-table-wrapper.psh-table-fixed table{table-layout:fixed}.psh-table-wrapper.psh-truncate td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:0}.psh-table-wrapper.psh-truncate th{overflow:hidden;text-overflow:ellipsis}.psh-expand-header{width:48px;min-width:48px;max-width:48px;padding:0}.psh-expand-cell{width:48px;min-width:48px;max-width:48px;text-align:center;padding:var(--psh-spacing-xs);vertical-align:middle}.psh-expand-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--psh-size-8);height:var(--psh-size-8);padding:0;background:transparent;border:none;border-radius:var(--psh-radius-sm);cursor:pointer;color:var(--psh-text-color-secondary);font-size:var(--psh-font-size-base);transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle:hover{color:var(--psh-primary-color);background:var(--psh-surface-hover)}.psh-expand-toggle:focus-visible{outline:var(--psh-focus-outline-width) solid var(--psh-focus-ring-color);outline-offset:2px}.psh-expand-toggle i{display:inline-block;transition:transform var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle[aria-expanded=true] i{transform:rotate(90deg)}tr.psh-expanded{border-bottom-color:transparent}.psh-expanded-content-row td{background:var(--psh-surface-ground);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-child-row{background:var(--psh-surface-ground)}.psh-child-row td{font-size:.95em;color:var(--psh-text-color-secondary)}.psh-table-wrapper.psh-striped .psh-child-row,.psh-table-wrapper.psh-striped .psh-expanded-content-row{background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable .psh-child-row:hover{background:var(--psh-surface-hover)}@media(max-width:47.9375em){.psh-table-wrapper{font-size:var(--psh-font-size-sm)}th,td{padding:var(--psh-spacing-sm)}.psh-global-search{margin-bottom:var(--psh-spacing-sm)}}@media(max-width:29.9375em){.psh-table-wrapper{border-radius:0;margin:0 calc(-1 * var(--psh-spacing-sm))}th,td{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);font-size:var(--psh-font-size-xs)}.psh-th-content{gap:var(--psh-spacing-xxs)}.psh-th-content i{font-size:var(--psh-font-size-sm)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: PshInputComponent, selector: "psh-input", inputs: ["value", "disabled", "readonly", "loading", "touched", "appearance", "size", "fullWidth", "required", "showLabel", "type", "placeholder", "label", "ariaLabel", "iconStart", "iconEnd", "error", "success", "hint", "ariaDescribedBy", "ariaLabelledBy", "suggestions", "autocompleteConfig", "showPasswordLabel", "hidePasswordLabel"], outputs: ["valueChange", "disabledChange", "touchedChange", "touch", "focused", "blurred", "suggestionSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4803
4876
  }
4804
4877
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshTableComponent, decorators: [{
4805
4878
  type: Component,
4806
4879
  args: [{ selector: 'psh-table', imports: [NgTemplateOutlet, PshInputComponent], changeDetection: ChangeDetectionStrategy.OnPush, host: {
4807
4880
  'class': 'psh-table',
4808
4881
  '[class.psh-full-width]': 'fullWidth()'
4809
- }, template: "<div\r\n class=\"psh-table-wrapper\"\r\n [class.psh-striped]=\"striped()\"\r\n [class.psh-hoverable]=\"hoverable()\"\r\n [class.psh-bordered]=\"bordered()\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-outline]=\"appearance() === 'outline'\"\r\n [class.psh-table-fixed]=\"tableLayout() === 'fixed'\"\r\n [class.psh-truncate]=\"truncateText()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n @if (globalSearch()) {\r\n <div class=\"psh-global-search\" role=\"search\">\r\n <psh-input\r\n [placeholder]=\"globalSearchPlaceholder()\"\r\n [ariaLabel]=\"globalSearchPlaceholder()\"\r\n [size]=\"size()\"\r\n [fullWidth]=\"true\"\r\n [showLabel]=\"false\"\r\n iconStart=\"magnifying-glass\"\r\n type=\"search\"\r\n [(value)]=\"searchTermSignal\"\r\n (valueChange)=\"onSearchValueChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <table role=\"table\" [attr.aria-label]=\"ariaLabel()\">\r\n <thead>\r\n <tr>\r\n @if (expandable()) {\r\n <th class=\"psh-expand-header\" scope=\"col\" [attr.aria-label]=\"expandColumnLabel()\"></th>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <th\r\n [style.width]=\"column.width\"\r\n scope=\"col\"\r\n [attr.aria-sort]=\"column.sortable ? (currentSort()?.key === column.key ? (currentSort()?.direction === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\r\n [class.psh-sortable]=\"column.sortable\"\r\n >\r\n @if (headerTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"headerTemplate()!\"\r\n [ngTemplateOutletContext]=\"headerContext(column)\"\r\n ></ng-container>\r\n } @else if (column.sortable) {\r\n <!-- A real button, so sorting is reachable by keyboard and gets a native\r\n focus ring. The icons are decorative: aria-sort on the th carries the\r\n state, which is why they had aria-hidden cancelling their aria-label. -->\r\n <button\r\n type=\"button\"\r\n class=\"psh-th-content psh-sort-button\"\r\n (click)=\"handleSort(column)\"\r\n >\r\n {{ column.label }}\r\n @if (currentSort()?.key === column.key) {\r\n <i\r\n [class]=\"'ph ' + (currentSort()?.direction === 'desc' ? 'ph-sort-descending' : 'ph-sort-ascending')\"\r\n aria-hidden=\"true\">\r\n </i>\r\n } @else {\r\n <i class=\"ph ph-arrows-down-up psh-sort-icon-neutral\" aria-hidden=\"true\"></i>\r\n }\r\n </button>\r\n } @else {\r\n <div class=\"psh-th-content\">{{ column.label }}</div>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @if (loading()) {\r\n <tr class=\"psh-loading-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <div class=\"psh-loading-indicator\">\r\n <div class=\"psh-spinner\"></div>\r\n </div>\r\n </td>\r\n </tr>\r\n } @else if (filteredData().length === 0) {\r\n <tr class=\"psh-empty-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n @if (emptyTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"emptyTemplate()!\"\r\n [ngTemplateOutletContext]=\"emptyContext()\"\r\n ></ng-container>\r\n } @else {\r\n {{ computedEmptyMessage() }}\r\n }\r\n </td>\r\n </tr>\r\n } @else {\r\n @for (row of filteredData(); track row.id) {\r\n <tr\r\n [class]=\"rowClasses(row)\"\r\n [class.psh-expanded]=\"expandable() && isRowExpanded(row)\"\r\n [attr.tabindex]=\"hoverable() ? 0 : null\"\r\n (click)=\"handleRowClick(row)\"\r\n (keydown.enter)=\"handleRowClick(row)\"\r\n (keydown.space)=\"handleRowClick(row); $event.preventDefault()\"\r\n >\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\">\r\n @if (isRowExpandable(row)) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-expand-toggle\"\r\n [attr.aria-expanded]=\"isRowExpanded(row)\"\r\n [attr.aria-label]=\"isRowExpanded(row) ? collapseRowLabel() : expandRowLabel()\"\r\n (click)=\"toggleRow(row); $event.stopPropagation()\"\r\n >\r\n <i class=\"ph ph-caret-right\"></i>\r\n </button>\r\n }\r\n </td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(row, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n\r\n @if (expandable() && isRowExpanded(row)) {\r\n @if (expandedRowTemplate()) {\r\n <tr class=\"psh-expanded-content-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandedRowTemplate()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row }\"\r\n ></ng-container>\r\n </td>\r\n </tr>\r\n } @else if (row.children?.length) {\r\n @for (child of row.children; track child.id) {\r\n <tr class=\"psh-child-row\">\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\"></td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(child, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [":host{display:block}:host(.psh-full-width){max-width:none;width:100%}.psh-table-wrapper{width:100%;overflow-x:auto;background:var(--psh-surface-card);border-radius:var(--psh-radius-lg)}.psh-table-wrapper.psh-outline{background:transparent;border:var(--psh-border-width-1) solid var(--psh-surface-border)}table{width:100%;border-collapse:collapse;text-align:left}th,td{padding:var(--psh-spacing-md);color:var(--psh-text-color);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}th{font-weight:600;color:var(--psh-text-color);background:var(--psh-surface-ground);white-space:nowrap;-webkit-user-select:none;user-select:none}th.psh-sortable{cursor:pointer}th.psh-sortable:hover{background:var(--psh-surface-hover)}.psh-th-content{display:flex;align-items:center;gap:var(--psh-spacing-xs)}.psh-th-content i{font-size:var(--psh-font-size-base);color:var(--psh-primary-color);display:inline-block;transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-th-content i.psh-sort-icon-neutral{color:var(--psh-text-color-secondary);opacity:.5}th.psh-sortable:hover .psh-sort-icon-neutral{opacity:1;color:var(--psh-primary-color)}.psh-table-wrapper.psh-striped tr:nth-child(2n){background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable tr:hover{background:var(--psh-surface-hover)}.psh-table-wrapper.psh-bordered th,.psh-table-wrapper.psh-bordered td{border:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-table-wrapper.psh-small th,.psh-table-wrapper.psh-small td{padding:var(--psh-spacing-sm);font-size:var(--psh-font-size-sm)}.psh-table-wrapper.psh-large th,.psh-table-wrapper.psh-large td{padding:var(--psh-spacing-lg);font-size:var(--psh-font-size-lg)}.psh-loading-row td,.psh-empty-row td{text-align:center;padding:var(--psh-spacing-xl);color:var(--psh-text-color-secondary)}.psh-loading-indicator{display:flex;justify-content:center;align-items:center}.psh-spinner{width:var(--psh-size-6);height:var(--psh-size-6);border:var(--psh-border-width-2) solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-normal) var(--psh-animation-easing-linear) infinite}@keyframes spin{to{transform:rotate(360deg)}}.psh-global-search{margin-bottom:var(--psh-spacing-md)}.psh-sort-button{width:100%;background:transparent;border:none;padding:0;font:inherit;color:inherit;text-align:left;cursor:pointer;border-radius:var(--psh-radius-lg);transition:color var(--psh-animation-duration-normal) var(--psh-animation-easing-default)}.psh-sort-button:hover{color:var(--psh-primary-color)}.psh-sort-button:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}tbody tr[tabindex]:focus-visible{outline:none;box-shadow:inset 0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-table-wrapper.psh-table-fixed table{table-layout:fixed}.psh-table-wrapper.psh-truncate td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:0}.psh-table-wrapper.psh-truncate th{overflow:hidden;text-overflow:ellipsis}.psh-expand-header{width:48px;min-width:48px;max-width:48px;padding:0}.psh-expand-cell{width:48px;min-width:48px;max-width:48px;text-align:center;padding:var(--psh-spacing-xs);vertical-align:middle}.psh-expand-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--psh-size-8);height:var(--psh-size-8);padding:0;background:transparent;border:none;border-radius:var(--psh-radius-sm);cursor:pointer;color:var(--psh-text-color-secondary);font-size:var(--psh-font-size-base);transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle:hover{color:var(--psh-primary-color);background:var(--psh-surface-hover)}.psh-expand-toggle:focus-visible{outline:var(--psh-focus-outline-width) solid var(--psh-focus-ring-color);outline-offset:2px}.psh-expand-toggle i{display:inline-block;transition:transform var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle[aria-expanded=true] i{transform:rotate(90deg)}tr.psh-expanded{border-bottom-color:transparent}.psh-expanded-content-row td{background:var(--psh-surface-ground);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-child-row{background:var(--psh-surface-ground)}.psh-child-row td{font-size:.95em;color:var(--psh-text-color-secondary)}.psh-table-wrapper.psh-striped .psh-child-row,.psh-table-wrapper.psh-striped .psh-expanded-content-row{background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable .psh-child-row:hover{background:var(--psh-surface-hover)}@media(max-width:47.9375em){.psh-table-wrapper{font-size:var(--psh-font-size-sm)}th,td{padding:var(--psh-spacing-sm)}.psh-global-search{margin-bottom:var(--psh-spacing-sm)}}@media(max-width:29.9375em){.psh-table-wrapper{border-radius:0;margin:0 calc(-1 * var(--psh-spacing-sm))}th,td{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);font-size:var(--psh-font-size-xs)}.psh-th-content{gap:var(--psh-spacing-xxs)}.psh-th-content i{font-size:var(--psh-font-size-sm)}}\n"] }]
4882
+ }, template: "<div\r\n class=\"psh-table-wrapper\"\r\n [class.psh-striped]=\"striped()\"\r\n [class.psh-hoverable]=\"hoverable()\"\r\n [class.psh-bordered]=\"bordered()\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-outline]=\"appearance() === 'outline'\"\r\n [class.psh-table-fixed]=\"tableLayout() === 'fixed'\"\r\n [class.psh-truncate]=\"truncateText()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n @if (globalSearch()) {\r\n <div class=\"psh-global-search\" role=\"search\">\r\n <psh-input\r\n [placeholder]=\"globalSearchPlaceholder()\"\r\n [ariaLabel]=\"globalSearchPlaceholder()\"\r\n [size]=\"size()\"\r\n [fullWidth]=\"true\"\r\n [showLabel]=\"false\"\r\n iconStart=\"magnifying-glass\"\r\n type=\"search\"\r\n [(value)]=\"searchTermSignal\"\r\n (valueChange)=\"onSearchValueChange($event)\"\r\n />\r\n </div>\r\n }\r\n\r\n <table role=\"table\" [attr.aria-label]=\"ariaLabel()\">\r\n <thead>\r\n <tr>\r\n @if (expandable()) {\r\n <th class=\"psh-expand-header\" scope=\"col\" [attr.aria-label]=\"expandColumnLabel()\"></th>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <th\r\n [style.width]=\"column.width\"\r\n scope=\"col\"\r\n [attr.aria-sort]=\"column.sortable ? (currentSort()?.key === column.key ? (currentSort()?.direction === 'asc' ? 'ascending' : 'descending') : 'none') : null\"\r\n [class.psh-sortable]=\"column.sortable\"\r\n >\r\n @if (headerTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"headerTemplate()!\"\r\n [ngTemplateOutletContext]=\"headerContext(column)\"\r\n ></ng-container>\r\n } @else if (column.sortable) {\r\n <!-- A real button, so sorting is reachable by keyboard and gets a native\r\n focus ring. The icons are decorative: aria-sort on the th carries the\r\n state, which is why they had aria-hidden cancelling their aria-label. -->\r\n <button\r\n type=\"button\"\r\n class=\"psh-th-content psh-sort-button\"\r\n (click)=\"handleSort(column)\"\r\n >\r\n {{ column.label }}\r\n @if (currentSort()?.key === column.key) {\r\n <i\r\n [class]=\"'ph ' + (currentSort()?.direction === 'desc' ? 'ph-sort-descending' : 'ph-sort-ascending')\"\r\n aria-hidden=\"true\">\r\n </i>\r\n } @else {\r\n <i class=\"ph ph-arrows-down-up psh-sort-icon-neutral\" aria-hidden=\"true\"></i>\r\n }\r\n </button>\r\n } @else {\r\n <div class=\"psh-th-content\">{{ column.label }}</div>\r\n }\r\n </th>\r\n }\r\n </tr>\r\n </thead>\r\n\r\n <tbody>\r\n @if (loading()) {\r\n <tr class=\"psh-loading-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <div class=\"psh-loading-indicator\">\r\n <div class=\"psh-spinner\"></div>\r\n </div>\r\n </td>\r\n </tr>\r\n } @else if (filteredData().length === 0) {\r\n <tr class=\"psh-empty-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n @if (emptyTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"emptyTemplate()!\"\r\n [ngTemplateOutletContext]=\"emptyContext()\"\r\n ></ng-container>\r\n } @else {\r\n {{ computedEmptyMessage() }}\r\n }\r\n </td>\r\n </tr>\r\n } @else {\r\n @for (row of filteredData(); track row.id) {\r\n <tr\r\n [class]=\"rowClasses(row)\"\r\n [class.psh-expanded]=\"expandable() && isRowExpanded(row)\"\r\n [attr.tabindex]=\"hoverable() ? 0 : null\"\r\n (click)=\"handleRowClick(row)\"\r\n (keydown.enter)=\"handleRowClick(row)\"\r\n (keydown.space)=\"handleRowClick(row); $event.preventDefault()\"\r\n >\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\">\r\n @if (isRowExpandable(row)) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-expand-toggle\"\r\n [attr.aria-expanded]=\"isRowExpanded(row)\"\r\n [attr.aria-label]=\"isRowExpanded(row) ? collapseRowLabel() : expandRowLabel()\"\r\n (click)=\"toggleRow(row); $event.stopPropagation()\"\r\n >\r\n <i class=\"ph ph-caret-right\"></i>\r\n </button>\r\n }\r\n </td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(row, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n\r\n @if (expandable() && isRowExpanded(row)) {\r\n @if (expandedRowTemplate()) {\r\n <tr class=\"psh-expanded-content-row\">\r\n <td [attr.colspan]=\"totalColumns()\">\r\n <ng-container\r\n [ngTemplateOutlet]=\"expandedRowTemplate()!\"\r\n [ngTemplateOutletContext]=\"{ $implicit: row }\"\r\n ></ng-container>\r\n </td>\r\n </tr>\r\n } @else if (row.children?.length) {\r\n @for (child of row.children; track child.id) {\r\n <tr class=\"psh-child-row\">\r\n @if (expandable()) {\r\n <td class=\"psh-expand-cell\"></td>\r\n }\r\n @for (column of columns(); track column.key) {\r\n <td>\r\n @if (column.template) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"column.template\"\r\n [ngTemplateOutletContext]=\"{ $implicit: child, column: column }\"\r\n ></ng-container>\r\n } @else {\r\n {{ getCellValue(child, column) }}\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n }\r\n }\r\n }\r\n }\r\n </tbody>\r\n </table>\r\n</div>\r\n", styles: [":host{display:block}:host(.psh-full-width){max-width:none;width:100%}.psh-table-wrapper{width:100%;overflow-x:auto;background:var(--psh-surface-card);border-radius:var(--psh-radius-lg)}.psh-table-wrapper.psh-outline{background:transparent;border:var(--psh-border-width-1) solid var(--psh-surface-border)}table{width:100%;border-collapse:collapse;text-align:left}th,td{padding:var(--psh-spacing-md);color:var(--psh-text-color);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}th{font-weight:600;color:var(--psh-text-color);background:var(--psh-surface-ground);white-space:nowrap;-webkit-user-select:none;user-select:none}th.psh-sortable{cursor:pointer}th.psh-sortable:hover{background:var(--psh-surface-hover)}.psh-th-content{display:flex;align-items:center;gap:var(--psh-spacing-xs)}.psh-th-content i{font-size:var(--psh-font-size-base);color:var(--psh-primary-color);display:inline-block;transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-th-content i.psh-sort-icon-neutral{color:var(--psh-text-color-secondary);opacity:.5}th.psh-sortable:hover .psh-sort-icon-neutral{opacity:1;color:var(--psh-primary-color)}.psh-table-wrapper.psh-striped tr:nth-child(2n){background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable tr:hover{background:var(--psh-surface-hover)}.psh-table-wrapper.psh-bordered th,.psh-table-wrapper.psh-bordered td{border:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-table-wrapper.psh-small th,.psh-table-wrapper.psh-small td{padding:var(--psh-spacing-sm);font-size:var(--psh-font-size-sm)}.psh-table-wrapper.psh-large th,.psh-table-wrapper.psh-large td{padding:var(--psh-spacing-lg);font-size:var(--psh-font-size-lg)}.psh-loading-row td,.psh-empty-row td{text-align:center;padding:var(--psh-spacing-xl);color:var(--psh-text-color-secondary)}.psh-loading-indicator{display:flex;justify-content:center;align-items:center}.psh-spinner{width:var(--psh-size-6);height:var(--psh-size-6);border:var(--psh-border-width-2) solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-normal) var(--psh-animation-easing-linear) infinite}@keyframes spin{to{transform:rotate(360deg)}}.psh-global-search{margin-bottom:var(--psh-spacing-md)}th.psh-sortable{padding:0}.psh-sort-button{width:100%;background:transparent;border:none;padding:var(--psh-spacing-md);font:inherit;color:inherit;text-align:left;cursor:pointer;border-radius:var(--psh-radius-lg);transition:color var(--psh-animation-duration-normal) var(--psh-animation-easing-default)}.psh-sort-button:hover{color:var(--psh-primary-color)}.psh-sort-button:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}tbody tr[tabindex]:focus-visible{outline:none;box-shadow:inset 0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-table-wrapper.psh-table-fixed table{table-layout:fixed}.psh-table-wrapper.psh-truncate td{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:0}.psh-table-wrapper.psh-truncate th{overflow:hidden;text-overflow:ellipsis}.psh-expand-header{width:48px;min-width:48px;max-width:48px;padding:0}.psh-expand-cell{width:48px;min-width:48px;max-width:48px;text-align:center;padding:var(--psh-spacing-xs);vertical-align:middle}.psh-expand-toggle{display:inline-flex;align-items:center;justify-content:center;width:var(--psh-size-8);height:var(--psh-size-8);padding:0;background:transparent;border:none;border-radius:var(--psh-radius-sm);cursor:pointer;color:var(--psh-text-color-secondary);font-size:var(--psh-font-size-base);transition:color var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle:hover{color:var(--psh-primary-color);background:var(--psh-surface-hover)}.psh-expand-toggle:focus-visible{outline:var(--psh-focus-outline-width) solid var(--psh-focus-ring-color);outline-offset:2px}.psh-expand-toggle i{display:inline-block;transition:transform var(--psh-animation-duration-fast) var(--psh-animation-easing-default)}.psh-expand-toggle[aria-expanded=true] i{transform:rotate(90deg)}tr.psh-expanded{border-bottom-color:transparent}.psh-expanded-content-row td{background:var(--psh-surface-ground);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-bottom:var(--psh-border-width-1) solid var(--psh-surface-border)}.psh-child-row{background:var(--psh-surface-ground)}.psh-child-row td{font-size:.95em;color:var(--psh-text-color-secondary)}.psh-table-wrapper.psh-striped .psh-child-row,.psh-table-wrapper.psh-striped .psh-expanded-content-row{background:var(--psh-surface-ground)}.psh-table-wrapper.psh-hoverable .psh-child-row:hover{background:var(--psh-surface-hover)}@media(max-width:47.9375em){.psh-table-wrapper{font-size:var(--psh-font-size-sm)}th,td{padding:var(--psh-spacing-sm)}.psh-global-search{margin-bottom:var(--psh-spacing-sm)}}@media(max-width:29.9375em){.psh-table-wrapper{border-radius:0;margin:0 calc(-1 * var(--psh-spacing-sm))}th,td{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);font-size:var(--psh-font-size-xs)}.psh-th-content{gap:var(--psh-spacing-xxs)}.psh-th-content i{font-size:var(--psh-font-size-sm)}}\n"] }]
4810
4883
  }], propDecorators: { appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], hoverable: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverable", required: false }] }], bordered: [{ type: i0.Input, args: [{ isSignal: true, alias: "bordered", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], globalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalSearch", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], emptyMessageInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyMessage", required: false }] }], noResultsMessageInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsMessage", required: false }] }], globalSearchPlaceholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "globalSearchPlaceholder", required: false }] }], tableLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableLayout", required: false }] }], truncateText: [{ type: i0.Input, args: [{ isSignal: true, alias: "truncateText", required: false }] }], expandable: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandable", required: false }] }], singleExpand: [{ type: i0.Input, args: [{ isSignal: true, alias: "singleExpand", required: false }] }], expandedRowTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandedRowTemplate", required: false }] }], headerTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerTemplate", required: false }] }], emptyTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyTemplate", required: false }] }], rowClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowClass", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], expandColumnLabelInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandColumnLabel", required: false }] }], expandRowLabelInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandRowLabel", required: false }] }], collapseRowLabelInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseRowLabel", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }], globalSearchChange: [{ type: i0.Output, args: ["globalSearchChange"] }], rowClicked: [{ type: i0.Output, args: ["rowClicked"] }], rowExpanded: [{ type: i0.Output, args: ["rowExpanded"] }], rowCollapsed: [{ type: i0.Output, args: ["rowCollapsed"] }] } });
4811
4884
 
4812
4885
  const PSH_TABS = new InjectionToken('PSH_TABS');
@@ -5117,11 +5190,11 @@ class PshTagComponent {
5117
5190
  }
5118
5191
  }
5119
5192
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshTagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5120
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshTagComponent, isStandalone: true, selector: "psh-tag", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, closeLabelInput: { classPropertyName: "closeLabelInput", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked", closed: "closed" }, ngImport: i0, template: "<div\r\n class=\"psh-tag\"\r\n [class.psh-primary]=\"color() === 'primary'\"\r\n [class.psh-secondary]=\"color() === 'secondary'\"\r\n [class.psh-success]=\"color() === 'success'\"\r\n [class.psh-warning]=\"color() === 'warning'\"\r\n [class.psh-danger]=\"color() === 'danger'\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-disabled]=\"disabled()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.tabindex]=\"computedTabIndex()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-disabled]=\"disabled() || null\"\r\n [attr.data-state]=\"state()\"\r\n (click)=\"handleClick($event)\"\r\n (keydown)=\"handleKeydown($event)\"\r\n>\r\n @if (icon()) {\r\n <i class=\"ph ph-{{ icon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"psh-tag-content\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </span>\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-tag-close\"\r\n (click)=\"handleClose($event)\"\r\n [attr.aria-label]=\"closeLabel()\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-tag{display:inline-flex;align-items:center;gap:var(--psh-spacing-xs);padding:var(--psh-tag-padding-y, var(--psh-spacing-xs)) var(--psh-tag-padding-x, var(--psh-spacing-sm));border-radius:var(--psh-radius-lg);font-size:var(--psh-tag-font-size, var(--psh-font-size-sm));font-weight:var(--psh-font-weight-medium);line-height:var(--psh-line-height-tight);cursor:default;transition:var(--psh-tag-transition, all var(--psh-animation-duration-normal) var(--psh-animation-easing-default));-webkit-user-select:none;user-select:none}.psh-tag[role=button]{cursor:pointer}.psh-tag[role=button]:focus-visible{outline:var(--psh-focus-outline-width) var(--psh-focus-outline-style) var(--psh-focus-outline-color);outline-offset:var(--psh-focus-outline-offset)}.psh-tag i{font-size:var(--psh-tag-icon-size, var(--psh-icon-size-sm))}.psh-tag-content{display:inline-block;vertical-align:middle}.psh-tag-close{display:inline-flex;align-items:center;justify-content:center;padding:var(--psh-tag-close-padding, var(--psh-spacing-xxs));border:none;background:transparent;color:inherit;cursor:pointer;opacity:var(--psh-tag-close-opacity, .7);transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);margin-left:var(--psh-spacing-xs)}.psh-tag-close:hover:not(:disabled){opacity:var(--psh-tag-close-opacity-hover, 1);background:var(--psh-tag-close-hover-bg, rgba(0, 0, 0, .1))}.psh-tag-close:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-tag.psh-primary{background:var(--psh-primary-gradient);color:var(--psh-text-on-primary)}.psh-tag.psh-secondary{background:var(--psh-secondary-color);color:var(--psh-text-on-secondary)}.psh-tag.psh-success{background:var(--psh-success-color);color:var(--psh-text-on-success)}.psh-tag.psh-warning{background:var(--psh-warning-color);color:var(--psh-text-on-warning)}.psh-tag.psh-danger{background:var(--psh-danger-color);color:var(--psh-text-on-danger)}.psh-tag.psh-info{background:var(--psh-info-color);color:var(--psh-text-on-info)}.psh-tag.psh-neutral{background:var(--psh-neutral-color);color:var(--psh-text-on-neutral)}.psh-tag.psh-small{--psh-tag-padding-y: calc(var(--psh-spacing-xs) * .5);--psh-tag-padding-x: var(--psh-spacing-xs);--psh-tag-font-size: var(--psh-font-size-xs);--psh-tag-icon-size: var(--psh-icon-size-xs)}.psh-tag.psh-large{--psh-tag-padding-y: var(--psh-spacing-sm);--psh-tag-padding-x: var(--psh-spacing-md);--psh-tag-font-size: var(--psh-font-size-base);--psh-tag-icon-size: var(--psh-icon-size-md)}.psh-tag.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-tag.psh-disabled .psh-tag-close{cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5193
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshTagComponent, isStandalone: true, selector: "psh-tag", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, closeLabelInput: { classPropertyName: "closeLabelInput", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked", closed: "closed" }, ngImport: i0, template: "<div\r\n class=\"psh-tag\"\r\n [class.psh-primary]=\"color() === 'primary'\"\r\n [class.psh-secondary]=\"color() === 'secondary'\"\r\n [class.psh-success]=\"color() === 'success'\"\r\n [class.psh-warning]=\"color() === 'warning'\"\r\n [class.psh-danger]=\"color() === 'danger'\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-disabled]=\"disabled()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.tabindex]=\"computedTabIndex()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-disabled]=\"disabled() || null\"\r\n [attr.data-state]=\"state()\"\r\n (click)=\"handleClick($event)\"\r\n (keydown)=\"handleKeydown($event)\"\r\n>\r\n @if (icon()) {\r\n <i class=\"ph ph-{{ icon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"psh-tag-content\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </span>\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-tag-close\"\r\n (click)=\"handleClose($event)\"\r\n [attr.aria-label]=\"closeLabel()\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-tag{display:inline-flex;align-items:center;gap:var(--psh-spacing-xs);padding:var(--psh-tag-padding-y, var(--psh-spacing-xs)) var(--psh-tag-padding-x, var(--psh-spacing-sm));border-radius:var(--psh-radius-lg);font-size:var(--psh-tag-font-size, var(--psh-font-size-sm));font-weight:var(--psh-font-weight-medium);line-height:var(--psh-line-height-tight);cursor:default;transition:var(--psh-tag-transition, all var(--psh-animation-duration-normal) var(--psh-animation-easing-default));-webkit-user-select:none;user-select:none}.psh-tag[role=button]{cursor:pointer}.psh-tag[role=button]:focus-visible{outline:var(--psh-focus-outline-width) var(--psh-focus-outline-style) var(--psh-focus-outline-color);outline-offset:var(--psh-focus-outline-offset)}.psh-tag i{font-size:var(--psh-tag-icon-size, var(--psh-icon-size-sm))}.psh-tag-content{display:inline-block;vertical-align:middle}.psh-tag-close{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:var(--psh-tag-close-padding, var(--psh-spacing-xxs));border:none;background:transparent;color:inherit;cursor:pointer;opacity:var(--psh-tag-close-opacity, .7);transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);margin-left:var(--psh-spacing-xs)}.psh-tag-close:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:100%;height:100%;min-width:var(--psh-touch-target-compact);min-height:var(--psh-touch-target-compact)}.psh-tag-close:hover:not(:disabled){opacity:var(--psh-tag-close-opacity-hover, 1);background:var(--psh-tag-close-hover-bg, rgba(0, 0, 0, .1))}.psh-tag-close:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-tag.psh-primary{background:var(--psh-primary-gradient);color:var(--psh-text-on-primary)}.psh-tag.psh-secondary{background:var(--psh-secondary-color);color:var(--psh-text-on-secondary)}.psh-tag.psh-success{background:var(--psh-success-color);color:var(--psh-text-on-success)}.psh-tag.psh-warning{background:var(--psh-warning-color);color:var(--psh-text-on-warning)}.psh-tag.psh-danger{background:var(--psh-danger-color);color:var(--psh-text-on-danger)}.psh-tag.psh-info{background:var(--psh-info-color);color:var(--psh-text-on-info)}.psh-tag.psh-neutral{background:var(--psh-neutral-color);color:var(--psh-text-on-neutral)}.psh-tag.psh-small{--psh-tag-padding-y: calc(var(--psh-spacing-xs) * .5);--psh-tag-padding-x: var(--psh-spacing-xs);--psh-tag-font-size: var(--psh-font-size-xs);--psh-tag-icon-size: var(--psh-icon-size-xs)}.psh-tag.psh-large{--psh-tag-padding-y: var(--psh-spacing-sm);--psh-tag-padding-x: var(--psh-spacing-md);--psh-tag-font-size: var(--psh-font-size-base);--psh-tag-icon-size: var(--psh-icon-size-md)}.psh-tag.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-tag.psh-disabled .psh-tag-close{cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5121
5194
  }
5122
5195
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshTagComponent, decorators: [{
5123
5196
  type: Component,
5124
- args: [{ selector: 'psh-tag', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"psh-tag\"\r\n [class.psh-primary]=\"color() === 'primary'\"\r\n [class.psh-secondary]=\"color() === 'secondary'\"\r\n [class.psh-success]=\"color() === 'success'\"\r\n [class.psh-warning]=\"color() === 'warning'\"\r\n [class.psh-danger]=\"color() === 'danger'\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-disabled]=\"disabled()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.tabindex]=\"computedTabIndex()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-disabled]=\"disabled() || null\"\r\n [attr.data-state]=\"state()\"\r\n (click)=\"handleClick($event)\"\r\n (keydown)=\"handleKeydown($event)\"\r\n>\r\n @if (icon()) {\r\n <i class=\"ph ph-{{ icon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"psh-tag-content\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </span>\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-tag-close\"\r\n (click)=\"handleClose($event)\"\r\n [attr.aria-label]=\"closeLabel()\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-tag{display:inline-flex;align-items:center;gap:var(--psh-spacing-xs);padding:var(--psh-tag-padding-y, var(--psh-spacing-xs)) var(--psh-tag-padding-x, var(--psh-spacing-sm));border-radius:var(--psh-radius-lg);font-size:var(--psh-tag-font-size, var(--psh-font-size-sm));font-weight:var(--psh-font-weight-medium);line-height:var(--psh-line-height-tight);cursor:default;transition:var(--psh-tag-transition, all var(--psh-animation-duration-normal) var(--psh-animation-easing-default));-webkit-user-select:none;user-select:none}.psh-tag[role=button]{cursor:pointer}.psh-tag[role=button]:focus-visible{outline:var(--psh-focus-outline-width) var(--psh-focus-outline-style) var(--psh-focus-outline-color);outline-offset:var(--psh-focus-outline-offset)}.psh-tag i{font-size:var(--psh-tag-icon-size, var(--psh-icon-size-sm))}.psh-tag-content{display:inline-block;vertical-align:middle}.psh-tag-close{display:inline-flex;align-items:center;justify-content:center;padding:var(--psh-tag-close-padding, var(--psh-spacing-xxs));border:none;background:transparent;color:inherit;cursor:pointer;opacity:var(--psh-tag-close-opacity, .7);transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);margin-left:var(--psh-spacing-xs)}.psh-tag-close:hover:not(:disabled){opacity:var(--psh-tag-close-opacity-hover, 1);background:var(--psh-tag-close-hover-bg, rgba(0, 0, 0, .1))}.psh-tag-close:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-tag.psh-primary{background:var(--psh-primary-gradient);color:var(--psh-text-on-primary)}.psh-tag.psh-secondary{background:var(--psh-secondary-color);color:var(--psh-text-on-secondary)}.psh-tag.psh-success{background:var(--psh-success-color);color:var(--psh-text-on-success)}.psh-tag.psh-warning{background:var(--psh-warning-color);color:var(--psh-text-on-warning)}.psh-tag.psh-danger{background:var(--psh-danger-color);color:var(--psh-text-on-danger)}.psh-tag.psh-info{background:var(--psh-info-color);color:var(--psh-text-on-info)}.psh-tag.psh-neutral{background:var(--psh-neutral-color);color:var(--psh-text-on-neutral)}.psh-tag.psh-small{--psh-tag-padding-y: calc(var(--psh-spacing-xs) * .5);--psh-tag-padding-x: var(--psh-spacing-xs);--psh-tag-font-size: var(--psh-font-size-xs);--psh-tag-icon-size: var(--psh-icon-size-xs)}.psh-tag.psh-large{--psh-tag-padding-y: var(--psh-spacing-sm);--psh-tag-padding-x: var(--psh-spacing-md);--psh-tag-font-size: var(--psh-font-size-base);--psh-tag-icon-size: var(--psh-icon-size-md)}.psh-tag.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-tag.psh-disabled .psh-tag-close{cursor:not-allowed}\n"] }]
5197
+ args: [{ selector: 'psh-tag', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"psh-tag\"\r\n [class.psh-primary]=\"color() === 'primary'\"\r\n [class.psh-secondary]=\"color() === 'secondary'\"\r\n [class.psh-success]=\"color() === 'success'\"\r\n [class.psh-warning]=\"color() === 'warning'\"\r\n [class.psh-danger]=\"color() === 'danger'\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-disabled]=\"disabled()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.tabindex]=\"computedTabIndex()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-disabled]=\"disabled() || null\"\r\n [attr.data-state]=\"state()\"\r\n (click)=\"handleClick($event)\"\r\n (keydown)=\"handleKeydown($event)\"\r\n>\r\n @if (icon()) {\r\n <i class=\"ph ph-{{ icon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <span class=\"psh-tag-content\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </span>\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-tag-close\"\r\n (click)=\"handleClose($event)\"\r\n [attr.aria-label]=\"closeLabel()\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-tag{display:inline-flex;align-items:center;gap:var(--psh-spacing-xs);padding:var(--psh-tag-padding-y, var(--psh-spacing-xs)) var(--psh-tag-padding-x, var(--psh-spacing-sm));border-radius:var(--psh-radius-lg);font-size:var(--psh-tag-font-size, var(--psh-font-size-sm));font-weight:var(--psh-font-weight-medium);line-height:var(--psh-line-height-tight);cursor:default;transition:var(--psh-tag-transition, all var(--psh-animation-duration-normal) var(--psh-animation-easing-default));-webkit-user-select:none;user-select:none}.psh-tag[role=button]{cursor:pointer}.psh-tag[role=button]:focus-visible{outline:var(--psh-focus-outline-width) var(--psh-focus-outline-style) var(--psh-focus-outline-color);outline-offset:var(--psh-focus-outline-offset)}.psh-tag i{font-size:var(--psh-tag-icon-size, var(--psh-icon-size-sm))}.psh-tag-content{display:inline-block;vertical-align:middle}.psh-tag-close{position:relative;display:inline-flex;align-items:center;justify-content:center;padding:var(--psh-tag-close-padding, var(--psh-spacing-xxs));border:none;background:transparent;color:inherit;cursor:pointer;opacity:var(--psh-tag-close-opacity, .7);transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);margin-left:var(--psh-spacing-xs)}.psh-tag-close:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:100%;height:100%;min-width:var(--psh-touch-target-compact);min-height:var(--psh-touch-target-compact)}.psh-tag-close:hover:not(:disabled){opacity:var(--psh-tag-close-opacity-hover, 1);background:var(--psh-tag-close-hover-bg, rgba(0, 0, 0, .1))}.psh-tag-close:focus-visible{outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}.psh-tag.psh-primary{background:var(--psh-primary-gradient);color:var(--psh-text-on-primary)}.psh-tag.psh-secondary{background:var(--psh-secondary-color);color:var(--psh-text-on-secondary)}.psh-tag.psh-success{background:var(--psh-success-color);color:var(--psh-text-on-success)}.psh-tag.psh-warning{background:var(--psh-warning-color);color:var(--psh-text-on-warning)}.psh-tag.psh-danger{background:var(--psh-danger-color);color:var(--psh-text-on-danger)}.psh-tag.psh-info{background:var(--psh-info-color);color:var(--psh-text-on-info)}.psh-tag.psh-neutral{background:var(--psh-neutral-color);color:var(--psh-text-on-neutral)}.psh-tag.psh-small{--psh-tag-padding-y: calc(var(--psh-spacing-xs) * .5);--psh-tag-padding-x: var(--psh-spacing-xs);--psh-tag-font-size: var(--psh-font-size-xs);--psh-tag-icon-size: var(--psh-icon-size-xs)}.psh-tag.psh-large{--psh-tag-padding-y: var(--psh-spacing-sm);--psh-tag-padding-x: var(--psh-spacing-md);--psh-tag-font-size: var(--psh-font-size-base);--psh-tag-icon-size: var(--psh-icon-size-md)}.psh-tag.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-tag.psh-disabled .psh-tag-close{cursor:not-allowed}\n"] }]
5125
5198
  }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], closeLabelInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
5126
5199
 
5127
5200
  const TEXTAREA_LABELS = {
@@ -5693,11 +5766,11 @@ class PshAlertComponent {
5693
5766
  this.closed.emit();
5694
5767
  }
5695
5768
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5696
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshAlertComponent, isStandalone: true, selector: "psh-alert", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, iconPosition: { classPropertyName: "iconPosition", publicName: "iconPosition", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showIcon: { classPropertyName: "showIcon", publicName: "showIcon", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, dismissLabelInput: { classPropertyName: "dismissLabelInput", publicName: "dismissLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLive: { classPropertyName: "ariaLive", publicName: "ariaLive", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "<div\r\n class=\"psh-alert\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class]=\"'psh-' + color()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.aria-live]=\"computedAriaLive()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n <div class=\"psh-alert-content\" [class.psh-icon-right]=\"iconPosition() === 'right'\">\r\n @if (showIcon()) {\r\n <i class=\"ph ph-{{ getIcon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <div class=\"psh-alert-message\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n Actions. The alert had one slot, in the message area, so the standard pattern \u2014 a\r\n \"Retry\" button aligned to the right of the text \u2014 had nowhere to go.\r\n -->\r\n <div class=\"psh-alert-actions\">\r\n <ng-content select=\"[psh-alert-actions]\"></ng-content>\r\n </div>\r\n\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-alert-dismiss\"\r\n (click)=\"handleClose()\"\r\n [attr.aria-label]=\"dismissLabel()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-alert{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--psh-spacing-md);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-radius:var(--psh-radius-lg);border:var(--psh-border-width-1) solid transparent;animation:slideIn var(--psh-alert-animation-duration, var(--psh-animation-duration-fast)) var(--psh-animation-easing-default)}.psh-alert-content{display:flex;align-items:flex-start;flex-direction:row;gap:var(--psh-spacing-md);flex:1}.psh-alert-content.psh-icon-right{flex-direction:row-reverse}.psh-alert i{font-size:var(--psh-alert-icon-size, var(--psh-icon-size-md));flex-shrink:0}.psh-alert-message{color:inherit;font-size:var(--psh-font-size-base);line-height:var(--psh-line-height-relaxed);word-break:break-word;overflow-wrap:break-word}.psh-alert.psh-info{background:var(--psh-alert-info-bg);border-color:var(--psh-alert-info-border-color);color:var(--psh-alert-info-text-color)}.psh-alert.psh-success{background:rgba(var(--psh-success-color-rgb),.1);border-color:var(--psh-success-color);color:var(--psh-success-color)}.psh-alert.psh-warning{background:rgba(var(--psh-warning-color-rgb),.1);border-color:var(--psh-warning-color);color:var(--psh-warning-color)}.psh-alert.psh-danger{background:rgba(var(--psh-danger-color-rgb),.1);border-color:var(--psh-danger-color);color:var(--psh-danger-color)}.psh-alert.psh-small{padding:var(--psh-spacing-sm) var(--psh-spacing-md);font-size:var(--psh-font-size-sm)}.psh-alert.psh-small i{font-size:var(--psh-alert-icon-size-sm, var(--psh-icon-size-sm))}.psh-alert.psh-large{padding:var(--psh-spacing-lg) var(--psh-spacing-xl);font-size:var(--psh-font-size-lg)}.psh-alert.psh-large i{font-size:var(--psh-alert-icon-size-lg, var(--psh-icon-size-lg))}.psh-alert-dismiss{background:transparent;border:none;color:inherit;padding:var(--psh-spacing-xs);cursor:pointer;opacity:.7;transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);display:flex;align-items:center;justify-content:center;z-index:2}.psh-alert-dismiss:hover{opacity:1;background:var(--psh-alert-dismiss-hover-bg, rgba(0, 0, 0, .1))}@keyframes slideIn{0%{opacity:0;transform:translateY(calc(-1 * var(--psh-alert-animation-distance, var(--psh-animation-distance-sm))))}to{opacity:1;transform:translateY(0)}}@media(max-width:47.9375em){.psh-alert{padding:var(--psh-spacing-sm) var(--psh-spacing-md);gap:var(--psh-spacing-sm)}.psh-alert-content{gap:var(--psh-spacing-sm)}.psh-alert-message{font-size:var(--psh-font-size-sm);word-break:break-word;overflow-wrap:break-word}.psh-alert i{font-size:var(--psh-icon-size-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-md) var(--psh-spacing-lg)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-md)}}@media(max-width:29.9375em){.psh-alert{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);gap:var(--psh-spacing-xs)}.psh-alert-content{gap:var(--psh-spacing-xs)}.psh-alert-message{font-size:var(--psh-font-size-xs)}.psh-alert i{font-size:var(--psh-icon-size-xs)}.psh-alert.psh-small{padding:var(--psh-spacing-xxs) var(--psh-spacing-xs)}.psh-alert.psh-medium{padding:var(--psh-spacing-xs) var(--psh-spacing-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-sm) var(--psh-spacing-md)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-sm)}.psh-alert-dismiss{padding:var(--psh-spacing-xxs)}}.psh-alert-actions{display:flex;align-items:center;gap:var(--psh-alert-actions-gap, var(--psh-spacing-sm));margin-left:auto}.psh-alert-actions:empty{display:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5769
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: PshAlertComponent, isStandalone: true, selector: "psh-alert", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, iconPosition: { classPropertyName: "iconPosition", publicName: "iconPosition", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showIcon: { classPropertyName: "showIcon", publicName: "showIcon", isSignal: true, isRequired: false, transformFunction: null }, role: { classPropertyName: "role", publicName: "role", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, dismissLabelInput: { classPropertyName: "dismissLabelInput", publicName: "dismissLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLive: { classPropertyName: "ariaLive", publicName: "ariaLive", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "<div\r\n class=\"psh-alert\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class]=\"'psh-' + color()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.aria-live]=\"computedAriaLive()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n <div class=\"psh-alert-content\" [class.psh-icon-right]=\"iconPosition() === 'right'\">\r\n @if (showIcon()) {\r\n <i class=\"ph ph-{{ getIcon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <div class=\"psh-alert-message\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n Actions. The alert had one slot, in the message area, so the standard pattern \u2014 a\r\n \"Retry\" button aligned to the right of the text \u2014 had nowhere to go.\r\n -->\r\n <div class=\"psh-alert-actions\">\r\n <ng-content select=\"[psh-alert-actions]\"></ng-content>\r\n </div>\r\n\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-alert-dismiss\"\r\n (click)=\"handleClose()\"\r\n [attr.aria-label]=\"dismissLabel()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-alert{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--psh-spacing-md);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-radius:var(--psh-radius-lg);border:var(--psh-border-width-1) solid transparent;animation:slideIn var(--psh-alert-animation-duration, var(--psh-animation-duration-fast)) var(--psh-animation-easing-default)}.psh-alert-content{display:flex;align-items:flex-start;flex-direction:row;gap:var(--psh-spacing-md);flex:1}.psh-alert-content.psh-icon-right{flex-direction:row-reverse}.psh-alert i{font-size:var(--psh-alert-icon-size, var(--psh-icon-size-md));flex-shrink:0}.psh-alert-message{color:inherit;font-size:var(--psh-font-size-base);line-height:var(--psh-line-height-relaxed);word-break:break-word;overflow-wrap:break-word}.psh-alert.psh-info{background:var(--psh-alert-info-bg);border-color:var(--psh-alert-info-border-color);color:var(--psh-alert-info-text-color)}.psh-alert.psh-success{background:rgba(var(--psh-success-color-rgb),.1);border-color:var(--psh-success-color);color:var(--psh-success-color)}.psh-alert.psh-warning{background:rgba(var(--psh-warning-color-rgb),.1);border-color:var(--psh-warning-color);color:var(--psh-warning-color)}.psh-alert.psh-danger{background:rgba(var(--psh-danger-color-rgb),.1);border-color:var(--psh-danger-color);color:var(--psh-danger-color)}.psh-alert.psh-small{padding:var(--psh-spacing-sm) var(--psh-spacing-md);font-size:var(--psh-font-size-sm)}.psh-alert.psh-small i{font-size:var(--psh-alert-icon-size-sm, var(--psh-icon-size-sm))}.psh-alert.psh-large{padding:var(--psh-spacing-lg) var(--psh-spacing-xl);font-size:var(--psh-font-size-lg)}.psh-alert.psh-large i{font-size:var(--psh-alert-icon-size-lg, var(--psh-icon-size-lg))}.psh-alert-dismiss{position:relative;background:transparent;border:none;color:inherit;padding:var(--psh-spacing-xs);cursor:pointer;opacity:.7;transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);display:flex;align-items:center;justify-content:center;z-index:2}.psh-alert-dismiss:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:100%;height:100%;min-width:var(--psh-touch-target-min);min-height:var(--psh-touch-target-min)}.psh-alert-dismiss:hover{opacity:1;background:var(--psh-alert-dismiss-hover-bg, rgba(0, 0, 0, .1))}@keyframes slideIn{0%{opacity:0;transform:translateY(calc(-1 * var(--psh-alert-animation-distance, var(--psh-animation-distance-sm))))}to{opacity:1;transform:translateY(0)}}@media(max-width:47.9375em){.psh-alert{padding:var(--psh-spacing-sm) var(--psh-spacing-md);gap:var(--psh-spacing-sm)}.psh-alert-content{gap:var(--psh-spacing-sm)}.psh-alert-message{font-size:var(--psh-font-size-sm);word-break:break-word;overflow-wrap:break-word}.psh-alert i{font-size:var(--psh-icon-size-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-md) var(--psh-spacing-lg)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-md)}}@media(max-width:29.9375em){.psh-alert{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);gap:var(--psh-spacing-xs)}.psh-alert-content{gap:var(--psh-spacing-xs)}.psh-alert-message{font-size:var(--psh-font-size-xs)}.psh-alert i{font-size:var(--psh-icon-size-xs)}.psh-alert.psh-small{padding:var(--psh-spacing-xxs) var(--psh-spacing-xs)}.psh-alert.psh-medium{padding:var(--psh-spacing-xs) var(--psh-spacing-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-sm) var(--psh-spacing-md)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-sm)}}.psh-alert-actions{display:flex;align-items:center;gap:var(--psh-alert-actions-gap, var(--psh-spacing-sm));margin-left:auto}.psh-alert-actions:empty{display:none}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
5697
5770
  }
5698
5771
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshAlertComponent, decorators: [{
5699
5772
  type: Component,
5700
- args: [{ selector: 'psh-alert', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"psh-alert\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class]=\"'psh-' + color()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.aria-live]=\"computedAriaLive()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n <div class=\"psh-alert-content\" [class.psh-icon-right]=\"iconPosition() === 'right'\">\r\n @if (showIcon()) {\r\n <i class=\"ph ph-{{ getIcon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <div class=\"psh-alert-message\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n Actions. The alert had one slot, in the message area, so the standard pattern \u2014 a\r\n \"Retry\" button aligned to the right of the text \u2014 had nowhere to go.\r\n -->\r\n <div class=\"psh-alert-actions\">\r\n <ng-content select=\"[psh-alert-actions]\"></ng-content>\r\n </div>\r\n\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-alert-dismiss\"\r\n (click)=\"handleClose()\"\r\n [attr.aria-label]=\"dismissLabel()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-alert{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--psh-spacing-md);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-radius:var(--psh-radius-lg);border:var(--psh-border-width-1) solid transparent;animation:slideIn var(--psh-alert-animation-duration, var(--psh-animation-duration-fast)) var(--psh-animation-easing-default)}.psh-alert-content{display:flex;align-items:flex-start;flex-direction:row;gap:var(--psh-spacing-md);flex:1}.psh-alert-content.psh-icon-right{flex-direction:row-reverse}.psh-alert i{font-size:var(--psh-alert-icon-size, var(--psh-icon-size-md));flex-shrink:0}.psh-alert-message{color:inherit;font-size:var(--psh-font-size-base);line-height:var(--psh-line-height-relaxed);word-break:break-word;overflow-wrap:break-word}.psh-alert.psh-info{background:var(--psh-alert-info-bg);border-color:var(--psh-alert-info-border-color);color:var(--psh-alert-info-text-color)}.psh-alert.psh-success{background:rgba(var(--psh-success-color-rgb),.1);border-color:var(--psh-success-color);color:var(--psh-success-color)}.psh-alert.psh-warning{background:rgba(var(--psh-warning-color-rgb),.1);border-color:var(--psh-warning-color);color:var(--psh-warning-color)}.psh-alert.psh-danger{background:rgba(var(--psh-danger-color-rgb),.1);border-color:var(--psh-danger-color);color:var(--psh-danger-color)}.psh-alert.psh-small{padding:var(--psh-spacing-sm) var(--psh-spacing-md);font-size:var(--psh-font-size-sm)}.psh-alert.psh-small i{font-size:var(--psh-alert-icon-size-sm, var(--psh-icon-size-sm))}.psh-alert.psh-large{padding:var(--psh-spacing-lg) var(--psh-spacing-xl);font-size:var(--psh-font-size-lg)}.psh-alert.psh-large i{font-size:var(--psh-alert-icon-size-lg, var(--psh-icon-size-lg))}.psh-alert-dismiss{background:transparent;border:none;color:inherit;padding:var(--psh-spacing-xs);cursor:pointer;opacity:.7;transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);display:flex;align-items:center;justify-content:center;z-index:2}.psh-alert-dismiss:hover{opacity:1;background:var(--psh-alert-dismiss-hover-bg, rgba(0, 0, 0, .1))}@keyframes slideIn{0%{opacity:0;transform:translateY(calc(-1 * var(--psh-alert-animation-distance, var(--psh-animation-distance-sm))))}to{opacity:1;transform:translateY(0)}}@media(max-width:47.9375em){.psh-alert{padding:var(--psh-spacing-sm) var(--psh-spacing-md);gap:var(--psh-spacing-sm)}.psh-alert-content{gap:var(--psh-spacing-sm)}.psh-alert-message{font-size:var(--psh-font-size-sm);word-break:break-word;overflow-wrap:break-word}.psh-alert i{font-size:var(--psh-icon-size-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-md) var(--psh-spacing-lg)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-md)}}@media(max-width:29.9375em){.psh-alert{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);gap:var(--psh-spacing-xs)}.psh-alert-content{gap:var(--psh-spacing-xs)}.psh-alert-message{font-size:var(--psh-font-size-xs)}.psh-alert i{font-size:var(--psh-icon-size-xs)}.psh-alert.psh-small{padding:var(--psh-spacing-xxs) var(--psh-spacing-xs)}.psh-alert.psh-medium{padding:var(--psh-spacing-xs) var(--psh-spacing-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-sm) var(--psh-spacing-md)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-sm)}.psh-alert-dismiss{padding:var(--psh-spacing-xxs)}}.psh-alert-actions{display:flex;align-items:center;gap:var(--psh-alert-actions-gap, var(--psh-spacing-sm));margin-left:auto}.psh-alert-actions:empty{display:none}\n"] }]
5773
+ args: [{ selector: 'psh-alert', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n class=\"psh-alert\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class]=\"'psh-' + color()\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [attr.aria-live]=\"computedAriaLive()\"\r\n [attr.data-state]=\"state()\"\r\n>\r\n <div class=\"psh-alert-content\" [class.psh-icon-right]=\"iconPosition() === 'right'\">\r\n @if (showIcon()) {\r\n <i class=\"ph ph-{{ getIcon() }}\" aria-hidden=\"true\"></i>\r\n }\r\n <div class=\"psh-alert-message\">\r\n <ng-content>{{ content() }}</ng-content>\r\n </div>\r\n </div>\r\n\r\n <!--\r\n Actions. The alert had one slot, in the message area, so the standard pattern \u2014 a\r\n \"Retry\" button aligned to the right of the text \u2014 had nowhere to go.\r\n -->\r\n <div class=\"psh-alert-actions\">\r\n <ng-content select=\"[psh-alert-actions]\"></ng-content>\r\n </div>\r\n\r\n @if (closable()) {\r\n <button\r\n type=\"button\"\r\n class=\"psh-alert-dismiss\"\r\n (click)=\"handleClose()\"\r\n [attr.aria-label]=\"dismissLabel()\"\r\n >\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n</div>", styles: [".psh-alert{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--psh-spacing-md);padding:var(--psh-spacing-md) var(--psh-spacing-lg);border-radius:var(--psh-radius-lg);border:var(--psh-border-width-1) solid transparent;animation:slideIn var(--psh-alert-animation-duration, var(--psh-animation-duration-fast)) var(--psh-animation-easing-default)}.psh-alert-content{display:flex;align-items:flex-start;flex-direction:row;gap:var(--psh-spacing-md);flex:1}.psh-alert-content.psh-icon-right{flex-direction:row-reverse}.psh-alert i{font-size:var(--psh-alert-icon-size, var(--psh-icon-size-md));flex-shrink:0}.psh-alert-message{color:inherit;font-size:var(--psh-font-size-base);line-height:var(--psh-line-height-relaxed);word-break:break-word;overflow-wrap:break-word}.psh-alert.psh-info{background:var(--psh-alert-info-bg);border-color:var(--psh-alert-info-border-color);color:var(--psh-alert-info-text-color)}.psh-alert.psh-success{background:rgba(var(--psh-success-color-rgb),.1);border-color:var(--psh-success-color);color:var(--psh-success-color)}.psh-alert.psh-warning{background:rgba(var(--psh-warning-color-rgb),.1);border-color:var(--psh-warning-color);color:var(--psh-warning-color)}.psh-alert.psh-danger{background:rgba(var(--psh-danger-color-rgb),.1);border-color:var(--psh-danger-color);color:var(--psh-danger-color)}.psh-alert.psh-small{padding:var(--psh-spacing-sm) var(--psh-spacing-md);font-size:var(--psh-font-size-sm)}.psh-alert.psh-small i{font-size:var(--psh-alert-icon-size-sm, var(--psh-icon-size-sm))}.psh-alert.psh-large{padding:var(--psh-spacing-lg) var(--psh-spacing-xl);font-size:var(--psh-font-size-lg)}.psh-alert.psh-large i{font-size:var(--psh-alert-icon-size-lg, var(--psh-icon-size-lg))}.psh-alert-dismiss{position:relative;background:transparent;border:none;color:inherit;padding:var(--psh-spacing-xs);cursor:pointer;opacity:.7;transition:opacity var(--psh-animation-duration-normal) var(--psh-animation-easing-default);border-radius:var(--psh-radius-lg);display:flex;align-items:center;justify-content:center;z-index:2}.psh-alert-dismiss:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:100%;height:100%;min-width:var(--psh-touch-target-min);min-height:var(--psh-touch-target-min)}.psh-alert-dismiss:hover{opacity:1;background:var(--psh-alert-dismiss-hover-bg, rgba(0, 0, 0, .1))}@keyframes slideIn{0%{opacity:0;transform:translateY(calc(-1 * var(--psh-alert-animation-distance, var(--psh-animation-distance-sm))))}to{opacity:1;transform:translateY(0)}}@media(max-width:47.9375em){.psh-alert{padding:var(--psh-spacing-sm) var(--psh-spacing-md);gap:var(--psh-spacing-sm)}.psh-alert-content{gap:var(--psh-spacing-sm)}.psh-alert-message{font-size:var(--psh-font-size-sm);word-break:break-word;overflow-wrap:break-word}.psh-alert i{font-size:var(--psh-icon-size-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-md) var(--psh-spacing-lg)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-md)}}@media(max-width:29.9375em){.psh-alert{padding:var(--psh-spacing-xs) var(--psh-spacing-sm);gap:var(--psh-spacing-xs)}.psh-alert-content{gap:var(--psh-spacing-xs)}.psh-alert-message{font-size:var(--psh-font-size-xs)}.psh-alert i{font-size:var(--psh-icon-size-xs)}.psh-alert.psh-small{padding:var(--psh-spacing-xxs) var(--psh-spacing-xs)}.psh-alert.psh-medium{padding:var(--psh-spacing-xs) var(--psh-spacing-sm)}.psh-alert.psh-large{padding:var(--psh-spacing-sm) var(--psh-spacing-md)}.psh-alert.psh-large i{font-size:var(--psh-icon-size-sm)}}.psh-alert-actions{display:flex;align-items:center;gap:var(--psh-alert-actions-gap, var(--psh-spacing-sm));margin-left:auto}.psh-alert-actions:empty{display:none}\n"] }]
5701
5774
  }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], iconPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "iconPosition", required: false }] }], closable: [{ type: i0.Input, args: [{ isSignal: true, alias: "closable", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcon", required: false }] }], role: [{ type: i0.Input, args: [{ isSignal: true, alias: "role", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], dismissLabelInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissLabel", required: false }] }], ariaLive: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLive", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
5702
5775
 
5703
5776
  // Default configuration
@@ -5935,82 +6008,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
5935
6008
  args: [{ selector: 'psh-badge', changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Badge click is an optional convenience; the badge is a status/img indicator, not a primary control. -->\r\n<!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\r\n<div\r\n class=\"psh-badge\"\r\n [class.psh-primary]=\"color() === 'primary'\"\r\n [class.psh-secondary]=\"color() === 'secondary'\"\r\n [class.psh-success]=\"color() === 'success'\"\r\n [class.psh-warning]=\"color() === 'warning'\"\r\n [class.psh-danger]=\"color() === 'danger'\"\r\n [class.psh-info]=\"color() === 'info'\"\r\n [class.psh-neutral]=\"color() === 'neutral'\"\r\n [class.psh-disabled]=\"disabled()\"\r\n [class.psh-dot]=\"displayType() === 'dot'\"\r\n [class.psh-counter]=\"displayType() === 'counter'\"\r\n [class.psh-overlap]=\"overlap()\"\r\n [class.psh-small]=\"size() === 'small'\"\r\n [class.psh-medium]=\"size() === 'medium'\"\r\n [class.psh-large]=\"size() === 'large'\"\r\n [class.psh-top-right]=\"position() === 'top-right'\"\r\n [class.psh-top-left]=\"position() === 'top-left'\"\r\n [class.psh-bottom-right]=\"position() === 'bottom-right'\"\r\n [class.psh-bottom-left]=\"position() === 'bottom-left'\"\r\n [attr.role]=\"computedRole()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.data-state]=\"state()\"\r\n (click)=\"onBadgeClick()\"\r\n>\r\n @if (displayType() === 'text') {\r\n <ng-content></ng-content>\r\n } @else if (displayType() === 'counter') {\r\n {{ displayValue() }}\r\n }\r\n</div>\r\n", styles: [".psh-badge{display:inline-flex;align-items:center;justify-content:center;min-width:var(--psh-badge-width, var(--psh-size-5));min-height:var(--psh-badge-height, var(--psh-size-5));padding:var(--psh-spacing-xs);border-radius:var(--psh-radius-base);font-size:var(--psh-font-size-xs);font-weight:var(--psh-font-weight-medium);line-height:1;white-space:nowrap;transition:all var(--psh-animation-duration-fast) var(--psh-animation-easing-default);min-width:max-content}.psh-badge.psh-primary{background:var(--psh-primary-gradient);color:var(--psh-text-on-primary)}.psh-badge.psh-secondary{background-color:var(--psh-secondary-color);color:var(--psh-text-on-secondary)}.psh-badge.psh-success{background-color:var(--psh-success-color);color:var(--psh-text-on-success)}.psh-badge.psh-warning{background-color:var(--psh-warning-color);color:var(--psh-text-on-warning)}.psh-badge.psh-danger{background-color:var(--psh-danger-color);color:var(--psh-text-on-danger)}.psh-badge.psh-info{background-color:var(--psh-info-color);color:var(--psh-text-on-info)}.psh-badge.psh-neutral{background-color:var(--psh-neutral-color);color:var(--psh-text-on-neutral)}.psh-badge.psh-disabled{background-color:var(--psh-surface-400);color:var(--psh-surface-0);cursor:not-allowed;opacity:var(--psh-opacity-disabled)}.psh-badge.psh-medium{min-width:var(--psh-badge-width, var(--psh-size-5));min-height:var(--psh-badge-height, var(--psh-size-5));font-size:var(--psh-font-size-xs);padding:var(--psh-spacing-xs)}.psh-badge.psh-small{min-width:var(--psh-badge-width-sm, var(--psh-size-4));min-height:var(--psh-badge-height-sm, var(--psh-size-4));font-size:var(--psh-font-size-xs);padding:var(--psh-spacing-xxs)}.psh-badge.psh-large{min-width:var(--psh-badge-width-lg, var(--psh-size-6));min-height:var(--psh-badge-height-lg, var(--psh-size-6));font-size:var(--psh-font-size-sm);padding:var(--psh-spacing-sm)}.psh-badge.psh-overlap{position:absolute;transform:translate(50%,-50%)}.psh-badge.psh-top-right{top:0;right:0}.psh-badge.psh-top-left{top:0;left:0;transform:translate(-50%,-50%)}.psh-badge.psh-bottom-right{bottom:0;right:0;transform:translate(50%,50%)}.psh-badge.psh-bottom-left{bottom:0;left:0;transform:translate(-50%,50%)}.psh-badge.psh-dot{border-radius:var(--psh-radius-full);box-shadow:var(--psh-badge-dot-shadow, 0 0 0 var(--psh-border-width-2)) var(--psh-surface-card)}.psh-badge.psh-counter{min-width:var(--psh-size-5);min-height:var(--psh-size-5);padding:0 var(--psh-spacing-xs)}\n"] }]
5936
6009
  }], propDecorators: { color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], displayType: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayType", required: false }] }], content: [{ type: i0.Input, args: [{ isSignal: true, alias: "content", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], showZero: [{ type: i0.Input, args: [{ isSignal: true, alias: "showZero", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], overlap: [{ type: i0.Input, args: [{ isSignal: true, alias: "overlap", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], formatter: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatter", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
5937
6010
 
5938
- /**
5939
- * One media query per breakpoint, for the whole application.
5940
- *
5941
- * `psh-card` and `psh-info-card` each built a `ResizeObserver` on `document.documentElement`
5942
- * to answer one question — is the viewport narrow? — so a grid of fifty cards installed fifty
5943
- * observers on the root element, each firing on every resize frame. The answer is the same for
5944
- * all of them, and `matchMedia` gives it without measuring anything: the browser evaluates the
5945
- * query and fires only when it flips.
5946
- *
5947
- * The queries are also back on the documented scale. Both components asked
5948
- * `innerWidth <= 640`, a pixel breakpoint written in TypeScript, which is why
5949
- * `verify:breakpoints` never saw it — that script reads stylesheets. An `em` query follows the
5950
- * user's root font size, so a component and the CSS beside it switch together under zoom.
5951
- *
5952
- * @example
5953
- * private readonly viewport = inject(PshViewportService);
5954
- * readonly isMobile = this.viewport.below('sm');
5955
- */
5956
- /** The scale of `breakpoints.tokens.css`, as the exclusive `max-width` of each step. */
5957
- const BELOW = {
5958
- xs: '29.9375em',
5959
- sm: '39.9375em',
5960
- md: '47.9375em',
5961
- lg: '63.9375em',
5962
- xl: '79.9375em',
5963
- '2xl': '95.9375em',
5964
- };
5965
- class PshViewportService {
5966
- constructor() {
5967
- this.document = inject(DOCUMENT);
5968
- this.isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
5969
- this.destroyRef = inject(DestroyRef);
5970
- /** One entry per distinct query, however many components ask for it. */
5971
- this.queries = new Map();
5972
- }
5973
- /**
5974
- * Whether the viewport is narrower than the given breakpoint.
5975
- *
5976
- * Exclusive, like the `max-width` rules in the stylesheets: at exactly the breakpoint the
5977
- * answer is `false`, so a component and its CSS never disagree about which side they are on.
5978
- *
5979
- * On the server it is `false` and never changes — the same value the components defaulted to
5980
- * before, so the first paint is unchanged.
5981
- */
5982
- below(breakpoint) {
5983
- return this.matches(`(max-width: ${BELOW[breakpoint]})`);
5984
- }
5985
- /** Any media query, as a signal. Shared with every other caller that passes the same one. */
5986
- matches(query) {
5987
- const existing = this.queries.get(query);
5988
- if (existing)
5989
- return existing;
5990
- const state = signal(false, /* @ts-ignore */
5991
- ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
5992
- // The read-only view is what is cached, so two callers get the *same* signal rather than
5993
- // two wrappers over one — and nothing outside can write it.
5994
- const readonly = state.asReadonly();
5995
- this.queries.set(query, readonly);
5996
- const view = this.isBrowser ? this.document.defaultView : null;
5997
- if (view?.matchMedia) {
5998
- const list = view.matchMedia(query);
5999
- state.set(list.matches);
6000
- const onChange = (event) => state.set(event.matches);
6001
- list.addEventListener('change', onChange);
6002
- this.destroyRef.onDestroy(() => list.removeEventListener('change', onChange));
6003
- }
6004
- return readonly;
6005
- }
6006
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshViewportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6007
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshViewportService, providedIn: 'root' }); }
6008
- }
6009
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshViewportService, decorators: [{
6010
- type: Injectable,
6011
- args: [{ providedIn: 'root' }]
6012
- }] });
6013
-
6014
6011
  /**
6015
6012
  * Composant carte métier - conteneur structuré pour contenu professionnel
6016
6013
  *
@@ -6859,6 +6856,7 @@ class PshCollapseComponent {
6859
6856
  case 'Escape':
6860
6857
  if (this.expanded()) {
6861
6858
  event.preventDefault();
6859
+ event.stopPropagation();
6862
6860
  this.close();
6863
6861
  }
6864
6862
  break;
@@ -7120,8 +7118,10 @@ class PshDropdownComponent {
7120
7118
  }
7121
7119
  break;
7122
7120
  case 'Escape':
7121
+ // Consumed here, so an enclosing modal does not also close on the same keypress.
7123
7122
  if (this.isOpen()) {
7124
7123
  event.preventDefault();
7124
+ event.stopPropagation();
7125
7125
  this.close();
7126
7126
  }
7127
7127
  break;
@@ -7152,6 +7152,7 @@ class PshDropdownComponent {
7152
7152
  break;
7153
7153
  case 'Escape':
7154
7154
  event.preventDefault();
7155
+ event.stopPropagation();
7155
7156
  this.close();
7156
7157
  break;
7157
7158
  case 'Tab':
@@ -7682,6 +7683,7 @@ class PshMenuComponent {
7682
7683
  case 'Escape':
7683
7684
  if (this.collapsible() && !this.collapsed()) {
7684
7685
  event.preventDefault();
7686
+ event.stopPropagation();
7685
7687
  this.toggleCollapse();
7686
7688
  }
7687
7689
  break;
@@ -8160,7 +8162,14 @@ class PshSelectComponent {
8160
8162
  this.focusLast();
8161
8163
  break;
8162
8164
  case 'Escape':
8163
- this.close();
8165
+ // Only when there is a panel to dismiss, and then the event stops here: a modal
8166
+ // listens for Escape on the document, so letting it through would close the whole
8167
+ // dialog — the user's form — for someone who only wanted the list gone.
8168
+ if (this.isOpen()) {
8169
+ event.preventDefault();
8170
+ event.stopPropagation();
8171
+ this.close();
8172
+ }
8164
8173
  break;
8165
8174
  case 'Tab':
8166
8175
  this.close();
@@ -8253,7 +8262,7 @@ class PshSelectComponent {
8253
8262
  useExisting: PshSelectComponent,
8254
8263
  multi: true
8255
8264
  }
8256
- ], viewQueries: [{ propertyName: "panelTpl", first: true, predicate: ["panelTpl"], descendants: true, isSignal: true }], hostDirectives: [{ directive: PshClickOutsideDirective }], ngImport: i0, template: "<div class=\"psh-select-container\">\r\n @if (label()) {\r\n <!-- label[for] delegates focus to its control natively; the click handler is a convenience. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\r\n <label class=\"psh-select-label\" [attr.for]=\"selectId\" (click)=\"focusSelect()\" [class.psh-required]=\"required()\">\r\n {{ label() }}\r\n @if (required()) { <span class=\"psh-required-mark\">*</span> }\r\n </label>\r\n }\r\n\r\n <div class=\"psh-select-trigger-wrapper\">\r\n <div class=\"psh-select-trigger\"\r\n role=\"combobox\"\r\n [id]=\"selectId\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-controls]=\"selectId + '-listbox'\"\r\n [attr.aria-activedescendant]=\"activeDescendant()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-invalid]=\"!!error()\"\r\n [attr.aria-required]=\"required()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-busy]=\"loading()\"\r\n [attr.aria-describedby]=\"describedBy()\"\r\n [attr.tabindex]=\"disabled() || loading() ? -1 : 0\"\r\n (keydown)=\"handleKeydown($event)\"\r\n (click)=\"toggle()\">\r\n <div class=\"psh-select-value\">\r\n <span [class.psh-placeholder]=\"!hasValue()\">\r\n {{ selectedLabel() }}\r\n </span>\r\n </div>\r\n <div class=\"psh-select-actions\">\r\n @if (clearable() && hasValue() && !disabled()) {\r\n <!-- Icon-only control: without an explicit name it is announced as \"button\",\r\n and without type=\"button\" it submits any surrounding form. -->\r\n <button class=\"psh-select-clear\"\r\n type=\"button\"\r\n [attr.aria-label]=\"clearLabel()\"\r\n (click)=\"clear($event)\">\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n @if (loading()) {\r\n <div class=\"psh-select-loader-trigger\"></div>\r\n } @else {\r\n <i class=\"ph ph-caret-down psh-select-arrow\"></i>\r\n }\r\n </div>\r\n </div>\r\n\r\n <ng-template #panelTpl>\r\n <div class=\"psh-select-dropdown\" [class.psh-open-top]=\"resolvedSide() === 'top'\">\r\n @if (searchable()) {\r\n <div class=\"psh-select-search\">\r\n <i class=\"ph ph-magnifying-glass psh-select-search-icon\" aria-hidden=\"true\"></i>\r\n <input type=\"text\"\r\n [attr.aria-label]=\"searchPlaceholder()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n }\r\n <div class=\"psh-select-options\"\r\n role=\"listbox\"\r\n [id]=\"selectId + '-listbox'\"\r\n [attr.aria-multiselectable]=\"multiple() || null\"\r\n (scroll)=\"onScroll($event)\">\r\n @for (item of filteredOptions(); track getOptionKey(item)) {\r\n @if (isOptionGroup(item)) {\r\n <div class=\"psh-select-group\" role=\"group\" [attr.aria-label]=\"item.label\">\r\n <div class=\"psh-select-group-label\">{{ item.label }}</div>\r\n @for (opt of item.options; track opt.label) {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + opt.value\"\r\n [attr.aria-selected]=\"optionView(opt).selected\"\r\n [attr.aria-disabled]=\"optionView(opt).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(opt).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(opt).selected\"\r\n [class.psh-disabled]=\"optionView(opt).disabled\"\r\n [class.psh-focused]=\"optionView(opt).index === focusedIndex()\"\r\n (click)=\"select(opt, !!item.disabled)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(opt).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (opt.icon) { <i [class]=\"'ph ph-' + opt.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ opt.label }}</span>\r\n @if (opt.description) { <span class=\"psh-select-option-description\">{{ opt.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + item.value\"\r\n [attr.aria-selected]=\"optionView(item).selected\"\r\n [attr.aria-disabled]=\"optionView(item).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(item).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(item).selected\"\r\n [class.psh-disabled]=\"optionView(item).disabled\"\r\n [class.psh-focused]=\"optionView(item).index === focusedIndex()\"\r\n (click)=\"select(item)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(item).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (item.icon) { <i [class]=\"'ph ph-' + item.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ item.label }}</span>\r\n @if (item.description) { <span class=\"psh-select-option-description\">{{ item.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @empty {\r\n <div class=\"psh-select-no-results\">{{ noResultsText() }}</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n\r\n @if (error()) {\r\n <div [id]=\"selectId + '-error'\" class=\"psh-select-error-message\" role=\"alert\">{{ error() }}</div>\r\n } @else if (success()) {\r\n <div [id]=\"selectId + '-success'\" class=\"psh-select-success-message\" role=\"status\">{{ success() }}</div>\r\n } @else if (hint()) {\r\n <div [id]=\"selectId + '-hint'\" class=\"psh-select-hint\">{{ hint() }}</div>\r\n }\r\n</div>\r\n\r\n", styles: [":host{display:block;width:100%;max-width:var(--psh-select-max-width, 18.75rem)}:host.psh-full-width{max-width:none}.psh-select-container{width:100%;display:flex;flex-direction:column;gap:var(--psh-form-field-gap)}.psh-select-trigger-wrapper{position:relative}.psh-select-label{display:block;color:var(--psh-text-color);font-size:var(--psh-font-size-sm);font-weight:500;cursor:pointer}.psh-select-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;height:var(--psh-control-height-md);padding:0 var(--psh-spacing-md);background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);cursor:pointer;box-sizing:border-box}.psh-select-trigger:focus-visible{border-color:var(--psh-primary-color);outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}:host.psh-error .psh-select-trigger{border-color:var(--psh-danger-color)}:host.psh-error .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-error)}:host.psh-success .psh-select-trigger{border-color:var(--psh-success-color)}:host.psh-success .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-success)}:host.psh-disabled .psh-select-trigger{background:var(--psh-surface-ground);cursor:not-allowed;opacity:var(--psh-opacity-disabled)}:host.psh-solid .psh-select-trigger{background:var(--psh-surface-ground);border:.125rem solid var(--psh-surface-border)}:host.psh-solid .psh-select-trigger:hover:not([disabled]):not(:focus){background:var(--psh-surface-hover)}.psh-select-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.psh-select-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.psh-select-clear{background:none;border:none;cursor:pointer;padding:0;color:var(--psh-text-color-secondary);display:flex}.psh-select-clear:hover{color:var(--psh-danger-color)}.psh-select-loader-trigger{width:1rem;height:1rem;border:2px solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-fast) var(--psh-animation-easing-linear) infinite}.psh-select-arrow{transition:transform var(--psh-animation-duration-normal);font-size:var(--psh-font-size-base);color:var(--psh-text-color-secondary)}:host[aria-expanded=true] .psh-select-arrow{transform:rotate(180deg)}.psh-select-dropdown{display:flex;flex-direction:column;overflow:hidden;pointer-events:auto;background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);box-shadow:var(--psh-shadow-lg)}.psh-select-search{position:relative;flex-shrink:0;padding:.5rem;border-bottom:.0625rem solid var(--psh-surface-border)}.psh-select-search-icon{position:absolute;left:1.25rem;top:50%;transform:translateY(-50%);color:var(--psh-text-color-secondary);font-size:.875rem;pointer-events:none}.psh-select-search input{width:100%;height:2rem;padding:0 .75rem 0 2rem;background:var(--psh-surface-ground);border:.0625rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);color:var(--psh-text-color);font-size:var(--psh-font-size-sm);outline:none;box-sizing:border-box;transition:border-color var(--psh-animation-duration-fast)}.psh-select-search input::placeholder{color:var(--psh-text-color-secondary)}.psh-select-search input:focus-visible{border-color:var(--psh-primary-color)}.psh-select-options{flex:0 1 auto;max-height:var(--psh-select-panel-max-height, 15rem);overflow-y:auto}.psh-select-group-label{padding:.5rem 1rem;font-size:.75rem;font-weight:600;color:var(--psh-text-color-secondary);background:var(--psh-surface-ground)}.psh-select-option{padding:.625rem 1rem;cursor:pointer;display:flex;align-items:flex-start;gap:.5rem}.psh-select-option:hover{background:var(--psh-surface-hover)}.psh-select-option.psh-selected{background:rgba(var(--psh-primary-color-rgb),.1);color:var(--psh-primary-color);font-weight:500}.psh-select-option.psh-focused{background:var(--psh-surface-hover)}.psh-select-option.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-select-option i{flex-shrink:0;line-height:1.4}.psh-select-option-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:.125rem}.psh-select-option-label{min-width:0}.psh-select-option-description{font-size:.75rem;color:var(--psh-text-color-secondary)}.psh-select-error-message,.psh-select-success-message,.psh-select-hint{font-size:.875rem}.psh-select-error-message{color:var(--psh-danger-color)}.psh-select-success-message{color:var(--psh-success-color)}.psh-select-hint{color:var(--psh-text-color-secondary)}:host.psh-small .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-sm);font-size:var(--psh-font-size-sm)}:host.psh-large .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-lg);font-size:var(--psh-font-size-lg)}@keyframes spin{to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8265
+ ], viewQueries: [{ propertyName: "panelTpl", first: true, predicate: ["panelTpl"], descendants: true, isSignal: true }], hostDirectives: [{ directive: PshClickOutsideDirective }], ngImport: i0, template: "<div class=\"psh-select-container\">\r\n @if (label()) {\r\n <!-- label[for] delegates focus to its control natively; the click handler is a convenience. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\r\n <label class=\"psh-select-label\" [attr.for]=\"selectId\" (click)=\"focusSelect()\" [class.psh-required]=\"required()\">\r\n {{ label() }}\r\n @if (required()) { <span class=\"psh-required-mark\">*</span> }\r\n </label>\r\n }\r\n\r\n <div class=\"psh-select-trigger-wrapper\">\r\n <div class=\"psh-select-trigger\"\r\n role=\"combobox\"\r\n [id]=\"selectId\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-controls]=\"selectId + '-listbox'\"\r\n [attr.aria-activedescendant]=\"activeDescendant()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-invalid]=\"!!error()\"\r\n [attr.aria-required]=\"required()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-busy]=\"loading()\"\r\n [attr.aria-describedby]=\"describedBy()\"\r\n [attr.tabindex]=\"disabled() || loading() ? -1 : 0\"\r\n (keydown)=\"handleKeydown($event)\"\r\n (click)=\"toggle()\">\r\n <div class=\"psh-select-value\">\r\n <span [class.psh-placeholder]=\"!hasValue()\">\r\n {{ selectedLabel() }}\r\n </span>\r\n </div>\r\n <div class=\"psh-select-actions\">\r\n @if (clearable() && hasValue() && !disabled()) {\r\n <!-- Icon-only control: without an explicit name it is announced as \"button\",\r\n and without type=\"button\" it submits any surrounding form. -->\r\n <button class=\"psh-select-clear\"\r\n type=\"button\"\r\n [attr.aria-label]=\"clearLabel()\"\r\n (click)=\"clear($event)\">\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n @if (loading()) {\r\n <div class=\"psh-select-loader-trigger\"></div>\r\n } @else {\r\n <i class=\"ph ph-caret-down psh-select-arrow\"></i>\r\n }\r\n </div>\r\n </div>\r\n\r\n <ng-template #panelTpl>\r\n <div class=\"psh-select-dropdown\" [class.psh-open-top]=\"resolvedSide() === 'top'\">\r\n @if (searchable()) {\r\n <div class=\"psh-select-search\">\r\n <i class=\"ph ph-magnifying-glass psh-select-search-icon\" aria-hidden=\"true\"></i>\r\n <input type=\"text\"\r\n [attr.aria-label]=\"searchPlaceholder()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n }\r\n <div class=\"psh-select-options\"\r\n role=\"listbox\"\r\n [id]=\"selectId + '-listbox'\"\r\n [attr.aria-multiselectable]=\"multiple() || null\"\r\n (scroll)=\"onScroll($event)\">\r\n @for (item of filteredOptions(); track getOptionKey(item)) {\r\n @if (isOptionGroup(item)) {\r\n <div class=\"psh-select-group\" role=\"group\" [attr.aria-label]=\"item.label\">\r\n <div class=\"psh-select-group-label\">{{ item.label }}</div>\r\n @for (opt of item.options; track opt.label) {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + opt.value\"\r\n [attr.aria-selected]=\"optionView(opt).selected\"\r\n [attr.aria-disabled]=\"optionView(opt).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(opt).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(opt).selected\"\r\n [class.psh-disabled]=\"optionView(opt).disabled\"\r\n [class.psh-focused]=\"optionView(opt).index === focusedIndex()\"\r\n (click)=\"select(opt, !!item.disabled)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(opt).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (opt.icon) { <i [class]=\"'ph ph-' + opt.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ opt.label }}</span>\r\n @if (opt.description) { <span class=\"psh-select-option-description\">{{ opt.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + item.value\"\r\n [attr.aria-selected]=\"optionView(item).selected\"\r\n [attr.aria-disabled]=\"optionView(item).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(item).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(item).selected\"\r\n [class.psh-disabled]=\"optionView(item).disabled\"\r\n [class.psh-focused]=\"optionView(item).index === focusedIndex()\"\r\n (click)=\"select(item)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(item).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (item.icon) { <i [class]=\"'ph ph-' + item.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ item.label }}</span>\r\n @if (item.description) { <span class=\"psh-select-option-description\">{{ item.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @empty {\r\n <div class=\"psh-select-no-results\">{{ noResultsText() }}</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n\r\n @if (error()) {\r\n <div [id]=\"selectId + '-error'\" class=\"psh-select-error-message\" role=\"alert\">{{ error() }}</div>\r\n } @else if (success()) {\r\n <div [id]=\"selectId + '-success'\" class=\"psh-select-success-message\" role=\"status\">{{ success() }}</div>\r\n } @else if (hint()) {\r\n <div [id]=\"selectId + '-hint'\" class=\"psh-select-hint\">{{ hint() }}</div>\r\n }\r\n</div>\r\n\r\n", styles: [":host{display:block;width:100%;max-width:var(--psh-select-max-width, 18.75rem)}:host.psh-full-width{max-width:none}.psh-select-container{width:100%;display:flex;flex-direction:column;gap:var(--psh-form-field-gap)}.psh-select-trigger-wrapper{position:relative}.psh-select-label{display:block;color:var(--psh-text-color);font-size:var(--psh-font-size-sm);font-weight:500;cursor:pointer}.psh-select-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;height:var(--psh-control-height-md);padding:0 var(--psh-spacing-md);background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);cursor:pointer;box-sizing:border-box}.psh-select-trigger:focus-visible{border-color:var(--psh-primary-color);outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}:host.psh-error .psh-select-trigger{border-color:var(--psh-danger-color)}:host.psh-error .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-error)}:host.psh-success .psh-select-trigger{border-color:var(--psh-success-color)}:host.psh-success .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-success)}:host.psh-disabled .psh-select-trigger{background:var(--psh-surface-ground);cursor:not-allowed;opacity:var(--psh-opacity-disabled)}:host.psh-solid .psh-select-trigger{background:var(--psh-surface-ground);border:.125rem solid var(--psh-surface-border)}:host.psh-solid .psh-select-trigger:hover:not([disabled]):not(:focus){background:var(--psh-surface-hover)}.psh-select-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.psh-select-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.psh-select-clear{position:relative;background:none;border:none;cursor:pointer;padding:0;color:var(--psh-text-color-secondary);display:flex}.psh-select-clear:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:100%;height:100%;min-width:var(--psh-touch-target-compact);min-height:var(--psh-touch-target-compact)}.psh-select-clear:hover{color:var(--psh-danger-color)}.psh-select-loader-trigger{width:1rem;height:1rem;border:2px solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-fast) var(--psh-animation-easing-linear) infinite}.psh-select-arrow{transition:transform var(--psh-animation-duration-normal);font-size:var(--psh-font-size-base);color:var(--psh-text-color-secondary)}:host[aria-expanded=true] .psh-select-arrow{transform:rotate(180deg)}.psh-select-dropdown{display:flex;flex-direction:column;overflow:hidden;pointer-events:auto;background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);box-shadow:var(--psh-shadow-lg)}.psh-select-search{position:relative;flex-shrink:0;padding:.5rem;border-bottom:.0625rem solid var(--psh-surface-border)}.psh-select-search-icon{position:absolute;left:1.25rem;top:50%;transform:translateY(-50%);color:var(--psh-text-color-secondary);font-size:.875rem;pointer-events:none}.psh-select-search input{width:100%;height:2rem;padding:0 .75rem 0 2rem;background:var(--psh-surface-ground);border:.0625rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);color:var(--psh-text-color);font-size:var(--psh-font-size-sm);outline:none;box-sizing:border-box;transition:border-color var(--psh-animation-duration-fast)}.psh-select-search input::placeholder{color:var(--psh-text-color-secondary)}.psh-select-search input:focus-visible{border-color:var(--psh-primary-color)}.psh-select-options{flex:0 1 auto;max-height:var(--psh-select-panel-max-height, 15rem);overflow-y:auto}.psh-select-group-label{padding:.5rem 1rem;font-size:.75rem;font-weight:600;color:var(--psh-text-color-secondary);background:var(--psh-surface-ground)}.psh-select-option{padding:.625rem 1rem;cursor:pointer;display:flex;align-items:flex-start;gap:.5rem}.psh-select-option:hover{background:var(--psh-surface-hover)}.psh-select-option.psh-selected{background:rgba(var(--psh-primary-color-rgb),.1);color:var(--psh-primary-color);font-weight:500}.psh-select-option.psh-focused{background:var(--psh-surface-hover)}.psh-select-option.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-select-option i{flex-shrink:0;line-height:1.4}.psh-select-option-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:.125rem}.psh-select-option-label{min-width:0}.psh-select-option-description{font-size:.75rem;color:var(--psh-text-color-secondary)}.psh-select-error-message,.psh-select-success-message,.psh-select-hint{font-size:.875rem}.psh-select-error-message{color:var(--psh-danger-color)}.psh-select-success-message{color:var(--psh-success-color)}.psh-select-hint{color:var(--psh-text-color-secondary)}:host.psh-small .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-sm);font-size:var(--psh-font-size-sm)}:host.psh-large .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-lg);font-size:var(--psh-font-size-lg)}@keyframes spin{to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8257
8266
  }
8258
8267
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: PshSelectComponent, decorators: [{
8259
8268
  type: Component,
@@ -8276,7 +8285,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImpor
8276
8285
  '[class.psh-loading]': 'loading()',
8277
8286
  '[attr.aria-expanded]': 'isOpen().toString()',
8278
8287
  '[attr.data-state]': 'state()'
8279
- }, template: "<div class=\"psh-select-container\">\r\n @if (label()) {\r\n <!-- label[for] delegates focus to its control natively; the click handler is a convenience. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\r\n <label class=\"psh-select-label\" [attr.for]=\"selectId\" (click)=\"focusSelect()\" [class.psh-required]=\"required()\">\r\n {{ label() }}\r\n @if (required()) { <span class=\"psh-required-mark\">*</span> }\r\n </label>\r\n }\r\n\r\n <div class=\"psh-select-trigger-wrapper\">\r\n <div class=\"psh-select-trigger\"\r\n role=\"combobox\"\r\n [id]=\"selectId\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-controls]=\"selectId + '-listbox'\"\r\n [attr.aria-activedescendant]=\"activeDescendant()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-invalid]=\"!!error()\"\r\n [attr.aria-required]=\"required()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-busy]=\"loading()\"\r\n [attr.aria-describedby]=\"describedBy()\"\r\n [attr.tabindex]=\"disabled() || loading() ? -1 : 0\"\r\n (keydown)=\"handleKeydown($event)\"\r\n (click)=\"toggle()\">\r\n <div class=\"psh-select-value\">\r\n <span [class.psh-placeholder]=\"!hasValue()\">\r\n {{ selectedLabel() }}\r\n </span>\r\n </div>\r\n <div class=\"psh-select-actions\">\r\n @if (clearable() && hasValue() && !disabled()) {\r\n <!-- Icon-only control: without an explicit name it is announced as \"button\",\r\n and without type=\"button\" it submits any surrounding form. -->\r\n <button class=\"psh-select-clear\"\r\n type=\"button\"\r\n [attr.aria-label]=\"clearLabel()\"\r\n (click)=\"clear($event)\">\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n @if (loading()) {\r\n <div class=\"psh-select-loader-trigger\"></div>\r\n } @else {\r\n <i class=\"ph ph-caret-down psh-select-arrow\"></i>\r\n }\r\n </div>\r\n </div>\r\n\r\n <ng-template #panelTpl>\r\n <div class=\"psh-select-dropdown\" [class.psh-open-top]=\"resolvedSide() === 'top'\">\r\n @if (searchable()) {\r\n <div class=\"psh-select-search\">\r\n <i class=\"ph ph-magnifying-glass psh-select-search-icon\" aria-hidden=\"true\"></i>\r\n <input type=\"text\"\r\n [attr.aria-label]=\"searchPlaceholder()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n }\r\n <div class=\"psh-select-options\"\r\n role=\"listbox\"\r\n [id]=\"selectId + '-listbox'\"\r\n [attr.aria-multiselectable]=\"multiple() || null\"\r\n (scroll)=\"onScroll($event)\">\r\n @for (item of filteredOptions(); track getOptionKey(item)) {\r\n @if (isOptionGroup(item)) {\r\n <div class=\"psh-select-group\" role=\"group\" [attr.aria-label]=\"item.label\">\r\n <div class=\"psh-select-group-label\">{{ item.label }}</div>\r\n @for (opt of item.options; track opt.label) {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + opt.value\"\r\n [attr.aria-selected]=\"optionView(opt).selected\"\r\n [attr.aria-disabled]=\"optionView(opt).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(opt).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(opt).selected\"\r\n [class.psh-disabled]=\"optionView(opt).disabled\"\r\n [class.psh-focused]=\"optionView(opt).index === focusedIndex()\"\r\n (click)=\"select(opt, !!item.disabled)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(opt).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (opt.icon) { <i [class]=\"'ph ph-' + opt.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ opt.label }}</span>\r\n @if (opt.description) { <span class=\"psh-select-option-description\">{{ opt.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + item.value\"\r\n [attr.aria-selected]=\"optionView(item).selected\"\r\n [attr.aria-disabled]=\"optionView(item).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(item).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(item).selected\"\r\n [class.psh-disabled]=\"optionView(item).disabled\"\r\n [class.psh-focused]=\"optionView(item).index === focusedIndex()\"\r\n (click)=\"select(item)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(item).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (item.icon) { <i [class]=\"'ph ph-' + item.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ item.label }}</span>\r\n @if (item.description) { <span class=\"psh-select-option-description\">{{ item.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @empty {\r\n <div class=\"psh-select-no-results\">{{ noResultsText() }}</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n\r\n @if (error()) {\r\n <div [id]=\"selectId + '-error'\" class=\"psh-select-error-message\" role=\"alert\">{{ error() }}</div>\r\n } @else if (success()) {\r\n <div [id]=\"selectId + '-success'\" class=\"psh-select-success-message\" role=\"status\">{{ success() }}</div>\r\n } @else if (hint()) {\r\n <div [id]=\"selectId + '-hint'\" class=\"psh-select-hint\">{{ hint() }}</div>\r\n }\r\n</div>\r\n\r\n", styles: [":host{display:block;width:100%;max-width:var(--psh-select-max-width, 18.75rem)}:host.psh-full-width{max-width:none}.psh-select-container{width:100%;display:flex;flex-direction:column;gap:var(--psh-form-field-gap)}.psh-select-trigger-wrapper{position:relative}.psh-select-label{display:block;color:var(--psh-text-color);font-size:var(--psh-font-size-sm);font-weight:500;cursor:pointer}.psh-select-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;height:var(--psh-control-height-md);padding:0 var(--psh-spacing-md);background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);cursor:pointer;box-sizing:border-box}.psh-select-trigger:focus-visible{border-color:var(--psh-primary-color);outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}:host.psh-error .psh-select-trigger{border-color:var(--psh-danger-color)}:host.psh-error .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-error)}:host.psh-success .psh-select-trigger{border-color:var(--psh-success-color)}:host.psh-success .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-success)}:host.psh-disabled .psh-select-trigger{background:var(--psh-surface-ground);cursor:not-allowed;opacity:var(--psh-opacity-disabled)}:host.psh-solid .psh-select-trigger{background:var(--psh-surface-ground);border:.125rem solid var(--psh-surface-border)}:host.psh-solid .psh-select-trigger:hover:not([disabled]):not(:focus){background:var(--psh-surface-hover)}.psh-select-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.psh-select-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.psh-select-clear{background:none;border:none;cursor:pointer;padding:0;color:var(--psh-text-color-secondary);display:flex}.psh-select-clear:hover{color:var(--psh-danger-color)}.psh-select-loader-trigger{width:1rem;height:1rem;border:2px solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-fast) var(--psh-animation-easing-linear) infinite}.psh-select-arrow{transition:transform var(--psh-animation-duration-normal);font-size:var(--psh-font-size-base);color:var(--psh-text-color-secondary)}:host[aria-expanded=true] .psh-select-arrow{transform:rotate(180deg)}.psh-select-dropdown{display:flex;flex-direction:column;overflow:hidden;pointer-events:auto;background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);box-shadow:var(--psh-shadow-lg)}.psh-select-search{position:relative;flex-shrink:0;padding:.5rem;border-bottom:.0625rem solid var(--psh-surface-border)}.psh-select-search-icon{position:absolute;left:1.25rem;top:50%;transform:translateY(-50%);color:var(--psh-text-color-secondary);font-size:.875rem;pointer-events:none}.psh-select-search input{width:100%;height:2rem;padding:0 .75rem 0 2rem;background:var(--psh-surface-ground);border:.0625rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);color:var(--psh-text-color);font-size:var(--psh-font-size-sm);outline:none;box-sizing:border-box;transition:border-color var(--psh-animation-duration-fast)}.psh-select-search input::placeholder{color:var(--psh-text-color-secondary)}.psh-select-search input:focus-visible{border-color:var(--psh-primary-color)}.psh-select-options{flex:0 1 auto;max-height:var(--psh-select-panel-max-height, 15rem);overflow-y:auto}.psh-select-group-label{padding:.5rem 1rem;font-size:.75rem;font-weight:600;color:var(--psh-text-color-secondary);background:var(--psh-surface-ground)}.psh-select-option{padding:.625rem 1rem;cursor:pointer;display:flex;align-items:flex-start;gap:.5rem}.psh-select-option:hover{background:var(--psh-surface-hover)}.psh-select-option.psh-selected{background:rgba(var(--psh-primary-color-rgb),.1);color:var(--psh-primary-color);font-weight:500}.psh-select-option.psh-focused{background:var(--psh-surface-hover)}.psh-select-option.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-select-option i{flex-shrink:0;line-height:1.4}.psh-select-option-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:.125rem}.psh-select-option-label{min-width:0}.psh-select-option-description{font-size:.75rem;color:var(--psh-text-color-secondary)}.psh-select-error-message,.psh-select-success-message,.psh-select-hint{font-size:.875rem}.psh-select-error-message{color:var(--psh-danger-color)}.psh-select-success-message{color:var(--psh-success-color)}.psh-select-hint{color:var(--psh-text-color-secondary)}:host.psh-small .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-sm);font-size:var(--psh-font-size-sm)}:host.psh-large .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-lg);font-size:var(--psh-font-size-lg)}@keyframes spin{to{transform:rotate(360deg)}}\n"] }]
8288
+ }, template: "<div class=\"psh-select-container\">\r\n @if (label()) {\r\n <!-- label[for] delegates focus to its control natively; the click handler is a convenience. -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -->\r\n <label class=\"psh-select-label\" [attr.for]=\"selectId\" (click)=\"focusSelect()\" [class.psh-required]=\"required()\">\r\n {{ label() }}\r\n @if (required()) { <span class=\"psh-required-mark\">*</span> }\r\n </label>\r\n }\r\n\r\n <div class=\"psh-select-trigger-wrapper\">\r\n <div class=\"psh-select-trigger\"\r\n role=\"combobox\"\r\n [id]=\"selectId\"\r\n [attr.aria-expanded]=\"isOpen()\"\r\n [attr.aria-haspopup]=\"'listbox'\"\r\n [attr.aria-controls]=\"selectId + '-listbox'\"\r\n [attr.aria-activedescendant]=\"activeDescendant()\"\r\n [attr.aria-label]=\"computedAriaLabel()\"\r\n [attr.aria-invalid]=\"!!error()\"\r\n [attr.aria-required]=\"required()\"\r\n [attr.aria-disabled]=\"disabled()\"\r\n [attr.aria-busy]=\"loading()\"\r\n [attr.aria-describedby]=\"describedBy()\"\r\n [attr.tabindex]=\"disabled() || loading() ? -1 : 0\"\r\n (keydown)=\"handleKeydown($event)\"\r\n (click)=\"toggle()\">\r\n <div class=\"psh-select-value\">\r\n <span [class.psh-placeholder]=\"!hasValue()\">\r\n {{ selectedLabel() }}\r\n </span>\r\n </div>\r\n <div class=\"psh-select-actions\">\r\n @if (clearable() && hasValue() && !disabled()) {\r\n <!-- Icon-only control: without an explicit name it is announced as \"button\",\r\n and without type=\"button\" it submits any surrounding form. -->\r\n <button class=\"psh-select-clear\"\r\n type=\"button\"\r\n [attr.aria-label]=\"clearLabel()\"\r\n (click)=\"clear($event)\">\r\n <i class=\"ph ph-x\" aria-hidden=\"true\"></i>\r\n </button>\r\n }\r\n @if (loading()) {\r\n <div class=\"psh-select-loader-trigger\"></div>\r\n } @else {\r\n <i class=\"ph ph-caret-down psh-select-arrow\"></i>\r\n }\r\n </div>\r\n </div>\r\n\r\n <ng-template #panelTpl>\r\n <div class=\"psh-select-dropdown\" [class.psh-open-top]=\"resolvedSide() === 'top'\">\r\n @if (searchable()) {\r\n <div class=\"psh-select-search\">\r\n <i class=\"ph ph-magnifying-glass psh-select-search-icon\" aria-hidden=\"true\"></i>\r\n <input type=\"text\"\r\n [attr.aria-label]=\"searchPlaceholder()\"\r\n [placeholder]=\"searchPlaceholder()\"\r\n [value]=\"searchTerm()\"\r\n (input)=\"onSearch($event)\"\r\n (click)=\"$event.stopPropagation()\">\r\n </div>\r\n }\r\n <div class=\"psh-select-options\"\r\n role=\"listbox\"\r\n [id]=\"selectId + '-listbox'\"\r\n [attr.aria-multiselectable]=\"multiple() || null\"\r\n (scroll)=\"onScroll($event)\">\r\n @for (item of filteredOptions(); track getOptionKey(item)) {\r\n @if (isOptionGroup(item)) {\r\n <div class=\"psh-select-group\" role=\"group\" [attr.aria-label]=\"item.label\">\r\n <div class=\"psh-select-group-label\">{{ item.label }}</div>\r\n @for (opt of item.options; track opt.label) {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + opt.value\"\r\n [attr.aria-selected]=\"optionView(opt).selected\"\r\n [attr.aria-disabled]=\"optionView(opt).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(opt).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(opt).selected\"\r\n [class.psh-disabled]=\"optionView(opt).disabled\"\r\n [class.psh-focused]=\"optionView(opt).index === focusedIndex()\"\r\n (click)=\"select(opt, !!item.disabled)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(opt).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (opt.icon) { <i [class]=\"'ph ph-' + opt.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ opt.label }}</span>\r\n @if (opt.description) { <span class=\"psh-select-option-description\">{{ opt.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n } @else {\r\n <!-- option in a listbox: keyboard is handled at the widget level (arrows + aria-activedescendant). -->\r\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events -->\r\n <div class=\"psh-select-option\"\r\n role=\"option\"\r\n [id]=\"selectId + '-' + item.value\"\r\n [attr.aria-selected]=\"optionView(item).selected\"\r\n [attr.aria-disabled]=\"optionView(item).disabled ? true : null\"\r\n [attr.tabindex]=\"optionView(item).disabled ? -1 : null\"\r\n [class.psh-selected]=\"optionView(item).selected\"\r\n [class.psh-disabled]=\"optionView(item).disabled\"\r\n [class.psh-focused]=\"optionView(item).index === focusedIndex()\"\r\n (click)=\"select(item)\">\r\n @if (optionTemplate()) {\r\n <ng-container\r\n [ngTemplateOutlet]=\"optionTemplate()!\"\r\n [ngTemplateOutletContext]=\"optionView(item).context\"\r\n ></ng-container>\r\n } @else {\r\n @if (item.icon) { <i [class]=\"'ph ph-' + item.icon\" aria-hidden=\"true\"></i> }\r\n <div class=\"psh-select-option-content\">\r\n <span class=\"psh-select-option-label\">{{ item.label }}</span>\r\n @if (item.description) { <span class=\"psh-select-option-description\">{{ item.description }}</span> }\r\n </div>\r\n }\r\n </div>\r\n }\r\n } @empty {\r\n <div class=\"psh-select-no-results\">{{ noResultsText() }}</div>\r\n }\r\n </div>\r\n </div>\r\n </ng-template>\r\n </div>\r\n\r\n @if (error()) {\r\n <div [id]=\"selectId + '-error'\" class=\"psh-select-error-message\" role=\"alert\">{{ error() }}</div>\r\n } @else if (success()) {\r\n <div [id]=\"selectId + '-success'\" class=\"psh-select-success-message\" role=\"status\">{{ success() }}</div>\r\n } @else if (hint()) {\r\n <div [id]=\"selectId + '-hint'\" class=\"psh-select-hint\">{{ hint() }}</div>\r\n }\r\n</div>\r\n\r\n", styles: [":host{display:block;width:100%;max-width:var(--psh-select-max-width, 18.75rem)}:host.psh-full-width{max-width:none}.psh-select-container{width:100%;display:flex;flex-direction:column;gap:var(--psh-form-field-gap)}.psh-select-trigger-wrapper{position:relative}.psh-select-label{display:block;color:var(--psh-text-color);font-size:var(--psh-font-size-sm);font-weight:500;cursor:pointer}.psh-select-trigger{display:flex;align-items:center;justify-content:space-between;width:100%;height:var(--psh-control-height-md);padding:0 var(--psh-spacing-md);background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);cursor:pointer;box-sizing:border-box}.psh-select-trigger:focus-visible{border-color:var(--psh-primary-color);outline:none;box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-color)}:host.psh-error .psh-select-trigger{border-color:var(--psh-danger-color)}:host.psh-error .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-error)}:host.psh-success .psh-select-trigger{border-color:var(--psh-success-color)}:host.psh-success .psh-select-trigger:focus-visible{box-shadow:0 0 0 var(--psh-focus-ring-width) var(--psh-focus-ring-success)}:host.psh-disabled .psh-select-trigger{background:var(--psh-surface-ground);cursor:not-allowed;opacity:var(--psh-opacity-disabled)}:host.psh-solid .psh-select-trigger{background:var(--psh-surface-ground);border:.125rem solid var(--psh-surface-border)}:host.psh-solid .psh-select-trigger:hover:not([disabled]):not(:focus){background:var(--psh-surface-hover)}.psh-select-value{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.psh-select-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.psh-select-clear{position:relative;background:none;border:none;cursor:pointer;padding:0;color:var(--psh-text-color-secondary);display:flex}.psh-select-clear:after{content:\"\";position:absolute;top:50%;left:50%;translate:-50% -50%;width:100%;height:100%;min-width:var(--psh-touch-target-compact);min-height:var(--psh-touch-target-compact)}.psh-select-clear:hover{color:var(--psh-danger-color)}.psh-select-loader-trigger{width:1rem;height:1rem;border:2px solid var(--psh-surface-border);border-top-color:var(--psh-primary-color);border-radius:50%;animation:spin var(--psh-animation-loop-fast) var(--psh-animation-easing-linear) infinite}.psh-select-arrow{transition:transform var(--psh-animation-duration-normal);font-size:var(--psh-font-size-base);color:var(--psh-text-color-secondary)}:host[aria-expanded=true] .psh-select-arrow{transform:rotate(180deg)}.psh-select-dropdown{display:flex;flex-direction:column;overflow:hidden;pointer-events:auto;background:var(--psh-surface-0);border:.125rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);box-shadow:var(--psh-shadow-lg)}.psh-select-search{position:relative;flex-shrink:0;padding:.5rem;border-bottom:.0625rem solid var(--psh-surface-border)}.psh-select-search-icon{position:absolute;left:1.25rem;top:50%;transform:translateY(-50%);color:var(--psh-text-color-secondary);font-size:.875rem;pointer-events:none}.psh-select-search input{width:100%;height:2rem;padding:0 .75rem 0 2rem;background:var(--psh-surface-ground);border:.0625rem solid var(--psh-surface-border);border-radius:var(--psh-radius-lg);color:var(--psh-text-color);font-size:var(--psh-font-size-sm);outline:none;box-sizing:border-box;transition:border-color var(--psh-animation-duration-fast)}.psh-select-search input::placeholder{color:var(--psh-text-color-secondary)}.psh-select-search input:focus-visible{border-color:var(--psh-primary-color)}.psh-select-options{flex:0 1 auto;max-height:var(--psh-select-panel-max-height, 15rem);overflow-y:auto}.psh-select-group-label{padding:.5rem 1rem;font-size:.75rem;font-weight:600;color:var(--psh-text-color-secondary);background:var(--psh-surface-ground)}.psh-select-option{padding:.625rem 1rem;cursor:pointer;display:flex;align-items:flex-start;gap:.5rem}.psh-select-option:hover{background:var(--psh-surface-hover)}.psh-select-option.psh-selected{background:rgba(var(--psh-primary-color-rgb),.1);color:var(--psh-primary-color);font-weight:500}.psh-select-option.psh-focused{background:var(--psh-surface-hover)}.psh-select-option.psh-disabled{opacity:var(--psh-opacity-disabled);cursor:not-allowed}.psh-select-option i{flex-shrink:0;line-height:1.4}.psh-select-option-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:.125rem}.psh-select-option-label{min-width:0}.psh-select-option-description{font-size:.75rem;color:var(--psh-text-color-secondary)}.psh-select-error-message,.psh-select-success-message,.psh-select-hint{font-size:.875rem}.psh-select-error-message{color:var(--psh-danger-color)}.psh-select-success-message{color:var(--psh-success-color)}.psh-select-hint{color:var(--psh-text-color-secondary)}:host.psh-small .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-sm);font-size:var(--psh-font-size-sm)}:host.psh-large .psh-select-trigger{text-overflow:ellipsis;height:var(--psh-control-height-lg);font-size:var(--psh-font-size-lg)}@keyframes spin{to{transform:rotate(360deg)}}\n"] }]
8280
8289
  }], ctorParameters: () => [], propDecorators: { panelTpl: [{ type: i0.ViewChild, args: ['panelTpl', { isSignal: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], touch: [{ type: i0.Output, args: ["touch"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], appearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "appearance", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], optionTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionTemplate", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], multiplePlaceholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiplePlaceholder", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], success: [{ type: i0.Input, args: [{ isSignal: true, alias: "success", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], noResultsTextInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "noResultsText", required: false }] }], ariaDescribedBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaDescribedBy", required: false }] }], ariaLabelledBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelledBy", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clearLabelInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearLabel", required: false }] }], maxSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxSelections", required: false }] }], minSelections: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSelections", required: false }] }], compareWith: [{ type: i0.Input, args: [{ isSignal: true, alias: "compareWith", required: false }] }], searchPlaceholderInput: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], searched: [{ type: i0.Output, args: ["searched"] }], scrolledToEnd: [{ type: i0.Output, args: ["scrolledToEnd"] }] } });
8281
8290
 
8282
8291
  class PshToastService {