@m1z23r/ngx-ui 1.1.33 → 1.1.35

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 { inject, PLATFORM_ID, signal, Injectable, computed, InjectionToken, ApplicationRef, EnvironmentInjector, createComponent, Injector, input, output, ChangeDetectionStrategy, Component, ElementRef, HostListener, effect, Directive, model, Pipe, contentChildren, ViewChild, TemplateRef, contentChild, viewChild, afterRenderEffect, DestroyRef } from '@angular/core';
2
+ import { inject, PLATFORM_ID, signal, Injectable, computed, InjectionToken, ApplicationRef, EnvironmentInjector, createComponent, Injector, input, output, ChangeDetectionStrategy, Component, ElementRef, HostListener, effect, Directive, model, Pipe, contentChildren, TemplateRef, contentChild, ViewChild, viewChild, afterRenderEffect, DestroyRef } from '@angular/core';
3
3
  import { isPlatformBrowser, NgTemplateOutlet, NgComponentOutlet, DOCUMENT, DecimalPipe } from '@angular/common';
4
4
  import * as i1 from '@angular/forms';
5
5
  import { FormsModule } from '@angular/forms';
@@ -1366,6 +1366,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
1366
1366
  args: [{ selector: 'ui-option', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-option\"\n [class.ui-option--selected]=\"selected()\"\n [class.ui-option--disabled]=\"disabled()\"\n [class.ui-option--focused]=\"focused()\"\n [class.ui-option--deletable]=\"deletable()\"\n [attr.role]=\"'option'\"\n [attr.aria-selected]=\"selected()\"\n [attr.aria-disabled]=\"disabled()\"\n>\n @if (multiple() && selected()) {\n <svg class=\"ui-option__check\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n }\n <span class=\"ui-option__content\">\n <ng-content />\n </span>\n @if (deletable()) {\n <button\n type=\"button\"\n class=\"ui-option__delete\"\n (click)=\"onDelete($event)\"\n aria-label=\"Delete option\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n }\n</div>\n", styles: [":host{display:block}.ui-option{display:flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-sm) var(--ui-spacing-md);cursor:pointer;transition:background-color var(--ui-transition-fast);-webkit-user-select:none;user-select:none}.ui-option:hover:not(.ui-option--disabled){background-color:var(--ui-option-hover-bg, var(--ui-bg-hover))}.ui-option--focused:not(.ui-option--disabled){background-color:var(--ui-option-hover-bg, var(--ui-bg-hover))}.ui-option--selected{background-color:var(--ui-option-selected-bg, color-mix(in srgb, var(--ui-primary) 10%, transparent));color:var(--ui-primary)}.ui-option--selected:hover:not(.ui-option--disabled){background-color:var(--ui-option-selected-bg, color-mix(in srgb, var(--ui-primary) 15%, transparent))}.ui-option--disabled{opacity:.5;cursor:not-allowed}.ui-option__check{flex-shrink:0;color:var(--ui-primary)}.ui-option__content{flex:1;min-width:0}.ui-option__delete{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:var(--ui-radius-sm);background:transparent;color:var(--ui-text-muted);cursor:pointer;opacity:0;transition:opacity var(--ui-transition-fast),background-color var(--ui-transition-fast),color var(--ui-transition-fast)}.ui-option:hover .ui-option__delete,.ui-option--focused .ui-option__delete{opacity:1}.ui-option__delete:hover{background-color:var(--ui-danger);color:#fff}.ui-option__delete:focus{outline:none;opacity:1}\n"] }]
1367
1367
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], deleteClicked: [{ type: i0.Output, args: ["deleteClicked"] }] } });
1368
1368
 
1369
+ class OptionTemplateDirective {
1370
+ templateRef = inject((TemplateRef));
1371
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OptionTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1372
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: OptionTemplateDirective, isStandalone: true, selector: "[uiOptionTemplate]", ngImport: i0 });
1373
+ }
1374
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OptionTemplateDirective, decorators: [{
1375
+ type: Directive,
1376
+ args: [{
1377
+ selector: '[uiOptionTemplate]',
1378
+ standalone: true,
1379
+ }]
1380
+ }] });
1381
+
1369
1382
  class SelectComponent {
1370
1383
  // Inputs
1371
1384
  variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : []));
@@ -1381,6 +1394,10 @@ class SelectComponent {
1381
1394
  creatable = input(false, ...(ngDevMode ? [{ debugName: "creatable" }] : []));
1382
1395
  deletable = input(false, ...(ngDevMode ? [{ debugName: "deletable" }] : []));
1383
1396
  selectable = input(true, ...(ngDevMode ? [{ debugName: "selectable" }] : []));
1397
+ // Async search inputs
1398
+ asyncSearch = input(null, ...(ngDevMode ? [{ debugName: "asyncSearch" }] : []));
1399
+ debounceTime = input(300, ...(ngDevMode ? [{ debugName: "debounceTime" }] : []));
1400
+ minSearchLength = input(0, ...(ngDevMode ? [{ debugName: "minSearchLength" }] : []));
1384
1401
  // Two-way binding
1385
1402
  value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : []));
1386
1403
  // Outputs
@@ -1390,6 +1407,7 @@ class SelectComponent {
1390
1407
  deleted = output();
1391
1408
  // Content children
1392
1409
  options = contentChildren(OptionComponent, ...(ngDevMode ? [{ debugName: "options" }] : []));
1410
+ optionTemplate = contentChild(OptionTemplateDirective, ...(ngDevMode ? [{ debugName: "optionTemplate" }] : []));
1393
1411
  // View children for dropdown portal
1394
1412
  triggerRef;
1395
1413
  dropdownRef;
@@ -1398,6 +1416,12 @@ class SelectComponent {
1398
1416
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
1399
1417
  searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : []));
1400
1418
  focusedIndex = signal(-1, ...(ngDevMode ? [{ debugName: "focusedIndex" }] : []));
1419
+ // Async state
1420
+ asyncLoading = signal(false, ...(ngDevMode ? [{ debugName: "asyncLoading" }] : []));
1421
+ asyncOptions = signal([], ...(ngDevMode ? [{ debugName: "asyncOptions" }] : []));
1422
+ asyncError = signal(null, ...(ngDevMode ? [{ debugName: "asyncError" }] : []));
1423
+ asyncSearchAbortController = null;
1424
+ debounceTimer = null;
1401
1425
  elementRef = inject(ElementRef);
1402
1426
  positionCleanup = null;
1403
1427
  initializedOptions = new WeakSet();
@@ -1467,6 +1491,7 @@ class SelectComponent {
1467
1491
  document.body.removeChild(dropdown);
1468
1492
  }
1469
1493
  this.removePositionListeners();
1494
+ this.cancelAsyncSearch();
1470
1495
  }
1471
1496
  triggerClasses = computed(() => {
1472
1497
  return `ui-select__trigger--${this.variant()} ui-select__trigger--${this.size()}`;
@@ -1481,10 +1506,17 @@ class SelectComponent {
1481
1506
  displayValue = computed(() => {
1482
1507
  const val = this.value();
1483
1508
  const opts = this.options();
1509
+ const asyncOpts = this.asyncOptions();
1510
+ const isAsync = this.isAsyncMode();
1484
1511
  if (this.multiple() && Array.isArray(val)) {
1485
1512
  if (val.length === 0)
1486
1513
  return '';
1487
1514
  const labels = val.map((v) => {
1515
+ if (isAsync) {
1516
+ const asyncOpt = asyncOpts.find((o) => o.value === v);
1517
+ if (asyncOpt)
1518
+ return asyncOpt.label;
1519
+ }
1488
1520
  const opt = opts.find((o) => o.value() === v);
1489
1521
  return opt?.getLabel() || String(v);
1490
1522
  });
@@ -1492,6 +1524,11 @@ class SelectComponent {
1492
1524
  }
1493
1525
  if (val === null || val === undefined)
1494
1526
  return '';
1527
+ if (isAsync) {
1528
+ const asyncOpt = asyncOpts.find((o) => o.value === val);
1529
+ if (asyncOpt)
1530
+ return asyncOpt.label;
1531
+ }
1495
1532
  const opt = opts.find((o) => o.value() === val);
1496
1533
  return opt?.getLabel() || String(val);
1497
1534
  }, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
@@ -1505,7 +1542,11 @@ class SelectComponent {
1505
1542
  }
1506
1543
  return this.displayValue() || this.placeholder();
1507
1544
  }, ...(ngDevMode ? [{ debugName: "inputPlaceholder" }] : []));
1545
+ isAsyncMode = computed(() => this.asyncSearch() !== null, ...(ngDevMode ? [{ debugName: "isAsyncMode" }] : []));
1508
1546
  visibleOptions = computed(() => {
1547
+ // In async mode, don't filter content children - they're not used
1548
+ if (this.isAsyncMode())
1549
+ return [];
1509
1550
  const query = this.searchQuery().toLowerCase().trim();
1510
1551
  const opts = this.options();
1511
1552
  if (!query)
@@ -1515,12 +1556,26 @@ class SelectComponent {
1515
1556
  return label.includes(query);
1516
1557
  });
1517
1558
  }, ...(ngDevMode ? [{ debugName: "visibleOptions" }] : []));
1559
+ visibleAsyncOptions = computed(() => {
1560
+ if (!this.isAsyncMode())
1561
+ return [];
1562
+ return this.asyncOptions();
1563
+ }, ...(ngDevMode ? [{ debugName: "visibleAsyncOptions" }] : []));
1518
1564
  exactMatchExists = computed(() => {
1519
1565
  const query = this.searchQuery().toLowerCase().trim();
1520
1566
  if (!query)
1521
1567
  return true;
1568
+ if (this.isAsyncMode()) {
1569
+ return this.asyncOptions().some((opt) => opt.label.toLowerCase() === query);
1570
+ }
1522
1571
  return this.options().some((opt) => opt.getLabel().toLowerCase() === query);
1523
1572
  }, ...(ngDevMode ? [{ debugName: "exactMatchExists" }] : []));
1573
+ totalVisibleCount = computed(() => {
1574
+ if (this.isAsyncMode()) {
1575
+ return this.visibleAsyncOptions().length;
1576
+ }
1577
+ return this.visibleOptions().length;
1578
+ }, ...(ngDevMode ? [{ debugName: "totalVisibleCount" }] : []));
1524
1579
  onDocumentClick(event) {
1525
1580
  const target = event.target;
1526
1581
  if (!this.elementRef.nativeElement.contains(target) &&
@@ -1575,6 +1630,21 @@ class SelectComponent {
1575
1630
  this.searchQuery.set('');
1576
1631
  this.focusedIndex.set(-1);
1577
1632
  this.closed.emit();
1633
+ // Clean up async state
1634
+ this.cancelAsyncSearch();
1635
+ this.asyncLoading.set(false);
1636
+ this.asyncError.set(null);
1637
+ // Keep asyncOptions so displayValue still works after selection
1638
+ }
1639
+ cancelAsyncSearch() {
1640
+ if (this.debounceTimer) {
1641
+ clearTimeout(this.debounceTimer);
1642
+ this.debounceTimer = null;
1643
+ }
1644
+ if (this.asyncSearchAbortController) {
1645
+ this.asyncSearchAbortController.abort();
1646
+ this.asyncSearchAbortController = null;
1647
+ }
1578
1648
  }
1579
1649
  selectOption(option, event) {
1580
1650
  event?.stopPropagation();
@@ -1617,6 +1687,44 @@ class SelectComponent {
1617
1687
  this.value.set(null);
1618
1688
  }
1619
1689
  }
1690
+ selectAsyncOption(option, event) {
1691
+ event?.stopPropagation();
1692
+ if (option.disabled)
1693
+ return;
1694
+ if (!this.selectable())
1695
+ return;
1696
+ const optionValue = option.value;
1697
+ if (this.multiple()) {
1698
+ const currentValue = this.value() || [];
1699
+ const index = currentValue.indexOf(optionValue);
1700
+ let newValue;
1701
+ if (index === -1) {
1702
+ newValue = [...currentValue, optionValue];
1703
+ }
1704
+ else {
1705
+ newValue = currentValue.filter((_, i) => i !== index);
1706
+ }
1707
+ this.value.set(newValue);
1708
+ // In multiple+searchable mode, clear search and refocus input
1709
+ if (this.searchable()) {
1710
+ this.searchQuery.set('');
1711
+ this.focusedIndex.set(-1);
1712
+ this.asyncOptions.set([]);
1713
+ setTimeout(() => this.searchInputRef?.nativeElement?.focus());
1714
+ }
1715
+ }
1716
+ else {
1717
+ this.value.set(optionValue);
1718
+ this.close();
1719
+ }
1720
+ }
1721
+ isAsyncOptionSelected(option) {
1722
+ const val = this.value();
1723
+ if (this.multiple() && Array.isArray(val)) {
1724
+ return val.includes(option.value);
1725
+ }
1726
+ return val === option.value;
1727
+ }
1620
1728
  deleteOption(optionValue) {
1621
1729
  // Remove from selection if selected
1622
1730
  if (this.multiple()) {
@@ -1636,10 +1744,7 @@ class SelectComponent {
1636
1744
  case ' ':
1637
1745
  event.preventDefault();
1638
1746
  if (this.isOpen()) {
1639
- const focused = this.visibleOptions()[this.focusedIndex()];
1640
- if (focused) {
1641
- this.selectOption(focused);
1642
- }
1747
+ this.selectFocusedOption();
1643
1748
  }
1644
1749
  else {
1645
1750
  this.open();
@@ -1692,13 +1797,24 @@ class SelectComponent {
1692
1797
  case 'Enter':
1693
1798
  event.preventDefault();
1694
1799
  if (this.isOpen()) {
1695
- const visible = this.visibleOptions();
1696
- const focused = visible[this.focusedIndex()];
1697
- if (focused) {
1698
- this.selectOption(focused);
1800
+ const focusedIdx = this.focusedIndex();
1801
+ if (focusedIdx >= 0) {
1802
+ this.selectFocusedOption();
1699
1803
  }
1700
- else if (visible.length === 1) {
1701
- this.selectOption(visible[0]);
1804
+ else if (this.totalVisibleCount() === 1) {
1805
+ // Auto-select single visible option
1806
+ if (this.isAsyncMode()) {
1807
+ const asyncOpts = this.visibleAsyncOptions();
1808
+ if (asyncOpts.length === 1) {
1809
+ this.selectAsyncOption(asyncOpts[0]);
1810
+ }
1811
+ }
1812
+ else {
1813
+ const visible = this.visibleOptions();
1814
+ if (visible.length === 1) {
1815
+ this.selectOption(visible[0]);
1816
+ }
1817
+ }
1702
1818
  }
1703
1819
  else if (this.creatable() && this.searchQuery().trim() && !this.exactMatchExists()) {
1704
1820
  this.handleCreate();
@@ -1717,18 +1833,95 @@ class SelectComponent {
1717
1833
  break;
1718
1834
  }
1719
1835
  }
1836
+ selectFocusedOption() {
1837
+ const focusedIdx = this.focusedIndex();
1838
+ if (focusedIdx < 0)
1839
+ return;
1840
+ if (this.isAsyncMode()) {
1841
+ const asyncOpts = this.visibleAsyncOptions();
1842
+ const focused = asyncOpts[focusedIdx];
1843
+ if (focused) {
1844
+ this.selectAsyncOption(focused);
1845
+ }
1846
+ }
1847
+ else {
1848
+ const focused = this.visibleOptions()[focusedIdx];
1849
+ if (focused) {
1850
+ this.selectOption(focused);
1851
+ }
1852
+ }
1853
+ }
1720
1854
  onSearchInput(value) {
1721
1855
  this.searchQuery.set(value);
1722
- // Auto-highlight when exactly one option is visible
1723
- const visible = this.visibleOptions();
1724
- this.focusedIndex.set(visible.length === 1 ? 0 : -1);
1725
1856
  if (!this.isOpen()) {
1726
- // Open without focus/select since user is already typing
1727
1857
  this.isOpen.set(true);
1728
1858
  this.focusedIndex.set(-1);
1729
1859
  this.opened.emit();
1730
1860
  this.portalDropdown();
1731
1861
  }
1862
+ if (this.isAsyncMode()) {
1863
+ this.triggerAsyncSearch(value);
1864
+ }
1865
+ else {
1866
+ // Auto-highlight when exactly one option is visible
1867
+ const visible = this.visibleOptions();
1868
+ this.focusedIndex.set(visible.length === 1 ? 0 : -1);
1869
+ }
1870
+ }
1871
+ triggerAsyncSearch(query) {
1872
+ // Clear previous debounce timer
1873
+ if (this.debounceTimer) {
1874
+ clearTimeout(this.debounceTimer);
1875
+ this.debounceTimer = null;
1876
+ }
1877
+ // Cancel previous request
1878
+ if (this.asyncSearchAbortController) {
1879
+ this.asyncSearchAbortController.abort();
1880
+ this.asyncSearchAbortController = null;
1881
+ }
1882
+ const trimmedQuery = query.trim();
1883
+ // Check minimum search length
1884
+ if (trimmedQuery.length < this.minSearchLength()) {
1885
+ this.asyncOptions.set([]);
1886
+ this.asyncLoading.set(false);
1887
+ this.asyncError.set(null);
1888
+ this.focusedIndex.set(-1);
1889
+ return;
1890
+ }
1891
+ // Set loading state immediately for visual feedback
1892
+ this.asyncLoading.set(true);
1893
+ this.asyncError.set(null);
1894
+ // Debounce the actual search
1895
+ this.debounceTimer = setTimeout(() => {
1896
+ this.executeAsyncSearch(trimmedQuery);
1897
+ }, this.debounceTime());
1898
+ }
1899
+ async executeAsyncSearch(query) {
1900
+ const searchFn = this.asyncSearch();
1901
+ if (!searchFn)
1902
+ return;
1903
+ this.asyncSearchAbortController = new AbortController();
1904
+ const signal = this.asyncSearchAbortController.signal;
1905
+ try {
1906
+ const results = await searchFn(query);
1907
+ // Check if request was aborted
1908
+ if (signal.aborted)
1909
+ return;
1910
+ this.asyncOptions.set(results);
1911
+ this.asyncLoading.set(false);
1912
+ this.asyncError.set(null);
1913
+ // Auto-highlight first option if results exist
1914
+ this.focusedIndex.set(results.length > 0 ? 0 : -1);
1915
+ }
1916
+ catch (error) {
1917
+ // Ignore abort errors
1918
+ if (signal.aborted)
1919
+ return;
1920
+ this.asyncOptions.set([]);
1921
+ this.asyncLoading.set(false);
1922
+ this.asyncError.set(error instanceof Error ? error.message : 'Search failed');
1923
+ this.focusedIndex.set(-1);
1924
+ }
1732
1925
  }
1733
1926
  handleCreate() {
1734
1927
  const query = this.searchQuery().trim();
@@ -1739,27 +1932,53 @@ class SelectComponent {
1739
1932
  this.close();
1740
1933
  }
1741
1934
  focusNext() {
1742
- const opts = this.visibleOptions();
1743
1935
  const current = this.focusedIndex();
1744
- let next = current + 1;
1745
- while (next < opts.length && opts[next].disabled()) {
1746
- next++;
1936
+ if (this.isAsyncMode()) {
1937
+ const opts = this.visibleAsyncOptions();
1938
+ let next = current + 1;
1939
+ while (next < opts.length && opts[next].disabled) {
1940
+ next++;
1941
+ }
1942
+ if (next < opts.length) {
1943
+ this.focusedIndex.set(next);
1944
+ this.scrollToFocusedAsync(next);
1945
+ }
1747
1946
  }
1748
- if (next < opts.length) {
1749
- this.focusedIndex.set(next);
1750
- this.scrollToFocused();
1947
+ else {
1948
+ const opts = this.visibleOptions();
1949
+ let next = current + 1;
1950
+ while (next < opts.length && opts[next].disabled()) {
1951
+ next++;
1952
+ }
1953
+ if (next < opts.length) {
1954
+ this.focusedIndex.set(next);
1955
+ this.scrollToFocused();
1956
+ }
1751
1957
  }
1752
1958
  }
1753
1959
  focusPrevious() {
1754
- const opts = this.visibleOptions();
1755
1960
  const current = this.focusedIndex();
1756
- let prev = current - 1;
1757
- while (prev >= 0 && opts[prev].disabled()) {
1758
- prev--;
1961
+ if (this.isAsyncMode()) {
1962
+ const opts = this.visibleAsyncOptions();
1963
+ let prev = current - 1;
1964
+ while (prev >= 0 && opts[prev].disabled) {
1965
+ prev--;
1966
+ }
1967
+ if (prev >= 0) {
1968
+ this.focusedIndex.set(prev);
1969
+ this.scrollToFocusedAsync(prev);
1970
+ }
1759
1971
  }
1760
- if (prev >= 0) {
1761
- this.focusedIndex.set(prev);
1762
- this.scrollToFocused();
1972
+ else {
1973
+ const opts = this.visibleOptions();
1974
+ let prev = current - 1;
1975
+ while (prev >= 0 && opts[prev].disabled()) {
1976
+ prev--;
1977
+ }
1978
+ if (prev >= 0) {
1979
+ this.focusedIndex.set(prev);
1980
+ this.scrollToFocused();
1981
+ }
1763
1982
  }
1764
1983
  }
1765
1984
  scrollToFocused() {
@@ -1768,6 +1987,16 @@ class SelectComponent {
1768
1987
  focused.elementRef.nativeElement.scrollIntoView({ block: 'nearest' });
1769
1988
  }
1770
1989
  }
1990
+ scrollToFocusedAsync(index) {
1991
+ const dropdown = this.dropdownRef?.nativeElement;
1992
+ if (!dropdown)
1993
+ return;
1994
+ const optionElements = dropdown.querySelectorAll('.ui-async-option');
1995
+ const focusedElement = optionElements[index];
1996
+ if (focusedElement) {
1997
+ focusedElement.scrollIntoView({ block: 'nearest' });
1998
+ }
1999
+ }
1771
2000
  portalDropdown() {
1772
2001
  const dropdown = this.dropdownRef?.nativeElement;
1773
2002
  if (!dropdown)
@@ -1793,7 +2022,6 @@ class SelectComponent {
1793
2022
  dropdown.style.left = '';
1794
2023
  dropdown.style.bottom = '';
1795
2024
  dropdown.style.width = '';
1796
- dropdown.style.minWidth = '';
1797
2025
  dropdown.style.zIndex = '';
1798
2026
  dropdown.style.margin = '';
1799
2027
  this.removePositionListeners();
@@ -1810,7 +2038,7 @@ class SelectComponent {
1810
2038
  const spaceAbove = triggerRect.top;
1811
2039
  const openAbove = spaceBelow < dropdownHeight + gap && spaceAbove > spaceBelow;
1812
2040
  dropdown.style.position = 'fixed';
1813
- dropdown.style.minWidth = `${triggerRect.width}px`;
2041
+ dropdown.style.width = `${triggerRect.width}px`;
1814
2042
  dropdown.style.left = `${triggerRect.left}px`;
1815
2043
  dropdown.style.zIndex = '99999';
1816
2044
  dropdown.style.margin = '0';
@@ -1841,12 +2069,12 @@ class SelectComponent {
1841
2069
  this.positionCleanup = null;
1842
2070
  }
1843
2071
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SelectComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1844
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: SelectComponent, isStandalone: true, selector: "ui-select", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, creatable: { classPropertyName: "creatable", publicName: "creatable", isSignal: true, isRequired: false, transformFunction: null }, deletable: { classPropertyName: "deletable", publicName: "deletable", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", opened: "opened", closed: "closed", created: "created", deleted: "deleted" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, queries: [{ propertyName: "options", predicate: OptionComponent, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerRef"], descendants: true, static: true }, { propertyName: "dropdownRef", first: true, predicate: ["dropdownRef"], descendants: true, static: true }, { propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true }], ngImport: i0, template: "<div\n class=\"ui-select-wrapper\"\n [class.ui-select-wrapper--error]=\"error()\"\n [class.ui-select-wrapper--disabled]=\"disabled()\"\n [class.ui-select-wrapper--open]=\"isOpen()\"\n>\n @if (label()) {\n <label class=\"ui-select__label\">\n {{ label() }}\n </label>\n }\n\n <div\n #triggerRef\n class=\"ui-select__trigger\"\n [class]=\"triggerClasses()\"\n [attr.role]=\"'combobox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"searchable() ? -1 : (disabled() ? -1 : 0)\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n @if (searchable()) {\n <input\n #searchInput\n type=\"text\"\n class=\"ui-select__input\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isOpen() ? searchQuery() : (selectable() ? displayValue() : '')\"\n [disabled]=\"disabled()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n (keydown)=\"handleSearchInputKeydown($event)\"\n (focus)=\"toggle()\"\n autocomplete=\"off\"\n />\n } @else {\n <span class=\"ui-select__value\">\n @if (displayValue()) {\n {{ displayValue() }}\n } @else {\n <span class=\"ui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n }\n\n <div class=\"ui-select__icons\">\n @if (clearable() && hasValue() && !disabled()) {\n <button\n type=\"button\"\n class=\"ui-select__clear\"\n (click)=\"clear($event)\"\n aria-label=\"Clear selection\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n }\n <svg\n class=\"ui-select__arrow\"\n [class.ui-select__arrow--open]=\"isOpen()\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n\n <div\n #dropdownRef\n class=\"ui-select__dropdown\"\n [class.ui-select__dropdown--open]=\"isOpen()\"\n [attr.role]=\"'listbox'\"\n [attr.aria-multiselectable]=\"multiple()\"\n >\n <div class=\"ui-select__options\">\n <ng-content />\n @if (visibleOptions().length === 0 && !(creatable() && searchQuery().trim())) {\n <div class=\"ui-select__empty\">No options found</div>\n }\n </div>\n @if (creatable() && searchQuery().trim() && !exactMatchExists()) {\n <div\n class=\"ui-select__create\"\n (click)=\"handleCreate()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n Create \"{{ searchQuery().trim() }}\"\n </div>\n }\n </div>\n\n @if (error()) {\n <span class=\"ui-select__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-select__hint\">{{ hint() }}</span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.ui-select-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-select__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--ui-spacing-sm);width:100%;background-color:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);cursor:pointer;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast)}.ui-select__trigger:hover:not([aria-disabled=true]){border-color:var(--ui-border-hover)}.ui-select__trigger:focus{outline:none;border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-select__trigger[aria-disabled=true]{background-color:var(--ui-bg-secondary);color:var(--ui-text-disabled);cursor:not-allowed}.ui-select__trigger--sm{padding:var(--ui-spacing-xs) var(--ui-spacing-sm);font-size:var(--ui-font-sm)}.ui-select__trigger--md{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-md)}.ui-select__trigger--lg{padding:var(--ui-spacing-md) var(--ui-spacing-lg);font-size:var(--ui-font-lg)}.ui-select__trigger--outlined{background-color:transparent}.ui-select__trigger--filled{background-color:var(--ui-bg-secondary);border-color:transparent}.ui-select__trigger--filled:hover:not([aria-disabled=true]){background-color:var(--ui-bg-tertiary)}.ui-select__trigger--filled:focus{border-color:var(--ui-border-focus)}.ui-select__value{flex:1;min-width:0;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__placeholder{color:var(--ui-text-muted)}.ui-select__icons{display:flex;align-items:center;gap:var(--ui-spacing-xs);flex-shrink:0}.ui-select__clear{display:flex;align-items:center;justify-content:center;padding:2px;background:none;border:none;cursor:pointer;color:var(--ui-text-muted);border-radius:var(--ui-radius-sm);transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-select__clear:hover{color:var(--ui-text);background-color:var(--ui-bg-hover)}.ui-select__arrow{color:var(--ui-text-muted);transition:transform var(--ui-transition-fast)}.ui-select__arrow--open{transform:rotate(180deg)}.ui-select__dropdown{position:absolute;top:100%;left:0;right:0;z-index:1000;margin-top:var(--ui-spacing-xs);background-color:var(--ui-dropdown-bg, var(--ui-bg));border:1px solid var(--ui-dropdown-border, var(--ui-border));border-radius:var(--ui-dropdown-radius, var(--ui-radius-md));box-shadow:var(--ui-dropdown-shadow, var(--ui-shadow-lg));overflow:hidden;display:none;opacity:0;transform:translateY(-8px);transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast)}.ui-select__dropdown--open{display:block;opacity:1;transform:translateY(0)}.ui-select__input{flex:1;min-width:0;background:none;border:none;outline:none;font:inherit;color:inherit;padding:0;text-align:left;text-overflow:ellipsis;cursor:pointer}.ui-select__input::placeholder{color:var(--ui-text-muted)}.ui-select__input:focus{cursor:text}.ui-select__input:disabled{cursor:not-allowed}.ui-select__create{display:flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-sm);color:var(--ui-primary);cursor:pointer;border-top:1px solid var(--ui-border);transition:background-color var(--ui-transition-fast)}.ui-select__create:hover{background-color:var(--ui-bg-hover)}.ui-select__options{max-height:var(--ui-dropdown-max-height, 300px);overflow-y:auto}.ui-select__empty{padding:var(--ui-spacing-md);text-align:center;color:var(--ui-text-muted);font-size:var(--ui-font-sm)}.ui-select-wrapper--error .ui-select__trigger{border-color:var(--ui-danger)}.ui-select-wrapper--error .ui-select__trigger:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-select__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-select__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2072
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: SelectComponent, isStandalone: true, selector: "ui-select", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "multiple", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, clearable: { classPropertyName: "clearable", publicName: "clearable", isSignal: true, isRequired: false, transformFunction: null }, creatable: { classPropertyName: "creatable", publicName: "creatable", isSignal: true, isRequired: false, transformFunction: null }, deletable: { classPropertyName: "deletable", publicName: "deletable", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, asyncSearch: { classPropertyName: "asyncSearch", publicName: "asyncSearch", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null }, minSearchLength: { classPropertyName: "minSearchLength", publicName: "minSearchLength", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", opened: "opened", closed: "closed", created: "created", deleted: "deleted" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, queries: [{ propertyName: "options", predicate: OptionComponent, isSignal: true }, { propertyName: "optionTemplate", first: true, predicate: OptionTemplateDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: ["triggerRef"], descendants: true, static: true }, { propertyName: "dropdownRef", first: true, predicate: ["dropdownRef"], descendants: true, static: true }, { propertyName: "searchInputRef", first: true, predicate: ["searchInput"], descendants: true }], ngImport: i0, template: "<div\n class=\"ui-select-wrapper\"\n [class.ui-select-wrapper--error]=\"error()\"\n [class.ui-select-wrapper--disabled]=\"disabled()\"\n [class.ui-select-wrapper--open]=\"isOpen()\"\n>\n @if (label()) {\n <label class=\"ui-select__label\">\n {{ label() }}\n </label>\n }\n\n <div\n #triggerRef\n class=\"ui-select__trigger\"\n [class]=\"triggerClasses()\"\n [attr.role]=\"'combobox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"searchable() ? -1 : (disabled() ? -1 : 0)\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n @if (searchable()) {\n <input\n #searchInput\n type=\"text\"\n class=\"ui-select__input\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isOpen() ? searchQuery() : (selectable() ? displayValue() : '')\"\n [disabled]=\"disabled()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n (keydown)=\"handleSearchInputKeydown($event)\"\n (focus)=\"toggle()\"\n autocomplete=\"off\"\n />\n } @else {\n <span class=\"ui-select__value\">\n @if (displayValue()) {\n {{ displayValue() }}\n } @else {\n <span class=\"ui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n }\n\n <div class=\"ui-select__icons\">\n @if (clearable() && hasValue() && !disabled()) {\n <button\n type=\"button\"\n class=\"ui-select__clear\"\n (click)=\"clear($event)\"\n aria-label=\"Clear selection\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n }\n <svg\n class=\"ui-select__arrow\"\n [class.ui-select__arrow--open]=\"isOpen()\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n\n <div\n #dropdownRef\n class=\"ui-select__dropdown\"\n [class.ui-select__dropdown--open]=\"isOpen()\"\n [attr.role]=\"'listbox'\"\n [attr.aria-multiselectable]=\"multiple()\"\n >\n <div class=\"ui-select__options\">\n @if (isAsyncMode()) {\n <!-- Async mode: render options from asyncSearch results -->\n @if (asyncLoading()) {\n <div class=\"ui-select__loading\">\n <svg class=\"ui-select__spinner\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke-opacity=\"0.25\"></circle>\n <path d=\"M12 2a10 10 0 0 1 10 10\" stroke-linecap=\"round\"></path>\n </svg>\n <span>Searching...</span>\n </div>\n } @else if (asyncError()) {\n <div class=\"ui-select__error-message\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line>\n </svg>\n <span>{{ asyncError() }}</span>\n </div>\n } @else {\n @for (option of visibleAsyncOptions(); track option.value; let i = $index) {\n <div\n class=\"ui-async-option\"\n [class.ui-async-option--selected]=\"isAsyncOptionSelected(option)\"\n [class.ui-async-option--disabled]=\"option.disabled\"\n [class.ui-async-option--focused]=\"focusedIndex() === i\"\n [attr.role]=\"'option'\"\n [attr.aria-selected]=\"isAsyncOptionSelected(option)\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"selectAsyncOption(option, $event)\"\n >\n @if (multiple() && isAsyncOptionSelected(option)) {\n <svg class=\"ui-async-option__check\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n }\n <span class=\"ui-async-option__content\">\n @if (optionTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.templateRef; context: { $implicit: option.value, option: option.value, selected: isAsyncOptionSelected(option), disabled: !!option.disabled }\"></ng-container>\n } @else {\n {{ option.label }}\n }\n </span>\n </div>\n }\n @if (visibleAsyncOptions().length === 0 && searchQuery().trim().length >= minSearchLength()) {\n <div class=\"ui-select__empty\">No results found</div>\n }\n @if (searchQuery().trim().length < minSearchLength() && minSearchLength() > 0) {\n <div class=\"ui-select__empty\">Type at least {{ minSearchLength() }} characters to search</div>\n }\n }\n } @else {\n <!-- Static mode: render content children -->\n <ng-content />\n @if (visibleOptions().length === 0 && !(creatable() && searchQuery().trim())) {\n <div class=\"ui-select__empty\">No options found</div>\n }\n }\n </div>\n @if (creatable() && searchQuery().trim() && !exactMatchExists()) {\n <div\n class=\"ui-select__create\"\n (click)=\"handleCreate()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n Create \"{{ searchQuery().trim() }}\"\n </div>\n }\n </div>\n\n @if (error()) {\n <span class=\"ui-select__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-select__hint\">{{ hint() }}</span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.ui-select-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-select__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--ui-spacing-sm);width:100%;background-color:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);cursor:pointer;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast)}.ui-select__trigger:hover:not([aria-disabled=true]){border-color:var(--ui-border-hover)}.ui-select__trigger:focus{outline:none;border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-select__trigger[aria-disabled=true]{background-color:var(--ui-bg-secondary);color:var(--ui-text-disabled);cursor:not-allowed}.ui-select__trigger--sm{padding:var(--ui-spacing-xs) var(--ui-spacing-sm);font-size:var(--ui-font-sm)}.ui-select__trigger--md{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-md)}.ui-select__trigger--lg{padding:var(--ui-spacing-md) var(--ui-spacing-lg);font-size:var(--ui-font-lg)}.ui-select__trigger--outlined{background-color:transparent}.ui-select__trigger--filled{background-color:var(--ui-bg-secondary);border-color:transparent}.ui-select__trigger--filled:hover:not([aria-disabled=true]){background-color:var(--ui-bg-tertiary)}.ui-select__trigger--filled:focus{border-color:var(--ui-border-focus)}.ui-select__value{flex:1;min-width:0;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__placeholder{color:var(--ui-text-muted)}.ui-select__icons{display:flex;align-items:center;gap:var(--ui-spacing-xs);flex-shrink:0}.ui-select__clear{display:flex;align-items:center;justify-content:center;padding:2px;background:none;border:none;cursor:pointer;color:var(--ui-text-muted);border-radius:var(--ui-radius-sm);transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-select__clear:hover{color:var(--ui-text);background-color:var(--ui-bg-hover)}.ui-select__arrow{color:var(--ui-text-muted);transition:transform var(--ui-transition-fast)}.ui-select__arrow--open{transform:rotate(180deg)}.ui-select__dropdown{position:absolute;top:100%;left:0;right:0;z-index:1000;margin-top:var(--ui-spacing-xs);background-color:var(--ui-dropdown-bg, var(--ui-bg));border:1px solid var(--ui-dropdown-border, var(--ui-border));border-radius:var(--ui-dropdown-radius, var(--ui-radius-md));box-shadow:var(--ui-dropdown-shadow, var(--ui-shadow-lg));overflow:hidden;display:none;opacity:0;transform:translateY(-8px);transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast);box-sizing:border-box}.ui-select__dropdown--open{display:block;opacity:1;transform:translateY(0)}.ui-select__input{flex:1;min-width:0;background:none;border:none;outline:none;font:inherit;color:inherit;padding:0;text-align:left;text-overflow:ellipsis;cursor:pointer}.ui-select__input::placeholder{color:var(--ui-text-muted)}.ui-select__input:focus{cursor:text}.ui-select__input:disabled{cursor:not-allowed}.ui-select__create{display:flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-sm);color:var(--ui-primary);cursor:pointer;border-top:1px solid var(--ui-border);transition:background-color var(--ui-transition-fast)}.ui-select__create:hover{background-color:var(--ui-bg-hover)}.ui-select__options{max-height:var(--ui-dropdown-max-height, 300px);overflow-y:auto}.ui-select__empty{padding:var(--ui-spacing-md);text-align:center;color:var(--ui-text-muted);font-size:var(--ui-font-sm)}.ui-select-wrapper--error .ui-select__trigger{border-color:var(--ui-danger)}.ui-select-wrapper--error .ui-select__trigger:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-select__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-select__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-async-option{display:flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-sm) var(--ui-spacing-md);cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-async-option:hover:not(.ui-async-option--disabled){background-color:var(--ui-bg-hover)}.ui-async-option--selected{background-color:color-mix(in srgb,var(--ui-primary) 10%,transparent)}.ui-async-option--selected:hover:not(.ui-async-option--disabled){background-color:color-mix(in srgb,var(--ui-primary) 15%,transparent)}.ui-async-option--focused{background-color:var(--ui-bg-hover);outline:none}.ui-async-option--focused.ui-async-option--selected{background-color:color-mix(in srgb,var(--ui-primary) 15%,transparent)}.ui-async-option--disabled{opacity:.5;cursor:not-allowed}.ui-async-option__check{flex-shrink:0;color:var(--ui-primary)}.ui-async-option__content{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__loading{display:flex;align-items:center;justify-content:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-lg) var(--ui-spacing-md);color:var(--ui-text-muted);font-size:var(--ui-font-sm)}.ui-select__spinner{animation:ui-select-spin 1s linear infinite}@keyframes ui-select-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ui-select__error-message{display:flex;align-items:center;justify-content:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-md);color:var(--ui-danger);font-size:var(--ui-font-sm)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1845
2073
  }
1846
2074
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: SelectComponent, decorators: [{
1847
2075
  type: Component,
1848
- args: [{ selector: 'ui-select', standalone: true, imports: [FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-select-wrapper\"\n [class.ui-select-wrapper--error]=\"error()\"\n [class.ui-select-wrapper--disabled]=\"disabled()\"\n [class.ui-select-wrapper--open]=\"isOpen()\"\n>\n @if (label()) {\n <label class=\"ui-select__label\">\n {{ label() }}\n </label>\n }\n\n <div\n #triggerRef\n class=\"ui-select__trigger\"\n [class]=\"triggerClasses()\"\n [attr.role]=\"'combobox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"searchable() ? -1 : (disabled() ? -1 : 0)\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n @if (searchable()) {\n <input\n #searchInput\n type=\"text\"\n class=\"ui-select__input\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isOpen() ? searchQuery() : (selectable() ? displayValue() : '')\"\n [disabled]=\"disabled()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n (keydown)=\"handleSearchInputKeydown($event)\"\n (focus)=\"toggle()\"\n autocomplete=\"off\"\n />\n } @else {\n <span class=\"ui-select__value\">\n @if (displayValue()) {\n {{ displayValue() }}\n } @else {\n <span class=\"ui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n }\n\n <div class=\"ui-select__icons\">\n @if (clearable() && hasValue() && !disabled()) {\n <button\n type=\"button\"\n class=\"ui-select__clear\"\n (click)=\"clear($event)\"\n aria-label=\"Clear selection\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n }\n <svg\n class=\"ui-select__arrow\"\n [class.ui-select__arrow--open]=\"isOpen()\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n\n <div\n #dropdownRef\n class=\"ui-select__dropdown\"\n [class.ui-select__dropdown--open]=\"isOpen()\"\n [attr.role]=\"'listbox'\"\n [attr.aria-multiselectable]=\"multiple()\"\n >\n <div class=\"ui-select__options\">\n <ng-content />\n @if (visibleOptions().length === 0 && !(creatable() && searchQuery().trim())) {\n <div class=\"ui-select__empty\">No options found</div>\n }\n </div>\n @if (creatable() && searchQuery().trim() && !exactMatchExists()) {\n <div\n class=\"ui-select__create\"\n (click)=\"handleCreate()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n Create \"{{ searchQuery().trim() }}\"\n </div>\n }\n </div>\n\n @if (error()) {\n <span class=\"ui-select__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-select__hint\">{{ hint() }}</span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.ui-select-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-select__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--ui-spacing-sm);width:100%;background-color:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);cursor:pointer;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast)}.ui-select__trigger:hover:not([aria-disabled=true]){border-color:var(--ui-border-hover)}.ui-select__trigger:focus{outline:none;border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-select__trigger[aria-disabled=true]{background-color:var(--ui-bg-secondary);color:var(--ui-text-disabled);cursor:not-allowed}.ui-select__trigger--sm{padding:var(--ui-spacing-xs) var(--ui-spacing-sm);font-size:var(--ui-font-sm)}.ui-select__trigger--md{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-md)}.ui-select__trigger--lg{padding:var(--ui-spacing-md) var(--ui-spacing-lg);font-size:var(--ui-font-lg)}.ui-select__trigger--outlined{background-color:transparent}.ui-select__trigger--filled{background-color:var(--ui-bg-secondary);border-color:transparent}.ui-select__trigger--filled:hover:not([aria-disabled=true]){background-color:var(--ui-bg-tertiary)}.ui-select__trigger--filled:focus{border-color:var(--ui-border-focus)}.ui-select__value{flex:1;min-width:0;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__placeholder{color:var(--ui-text-muted)}.ui-select__icons{display:flex;align-items:center;gap:var(--ui-spacing-xs);flex-shrink:0}.ui-select__clear{display:flex;align-items:center;justify-content:center;padding:2px;background:none;border:none;cursor:pointer;color:var(--ui-text-muted);border-radius:var(--ui-radius-sm);transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-select__clear:hover{color:var(--ui-text);background-color:var(--ui-bg-hover)}.ui-select__arrow{color:var(--ui-text-muted);transition:transform var(--ui-transition-fast)}.ui-select__arrow--open{transform:rotate(180deg)}.ui-select__dropdown{position:absolute;top:100%;left:0;right:0;z-index:1000;margin-top:var(--ui-spacing-xs);background-color:var(--ui-dropdown-bg, var(--ui-bg));border:1px solid var(--ui-dropdown-border, var(--ui-border));border-radius:var(--ui-dropdown-radius, var(--ui-radius-md));box-shadow:var(--ui-dropdown-shadow, var(--ui-shadow-lg));overflow:hidden;display:none;opacity:0;transform:translateY(-8px);transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast)}.ui-select__dropdown--open{display:block;opacity:1;transform:translateY(0)}.ui-select__input{flex:1;min-width:0;background:none;border:none;outline:none;font:inherit;color:inherit;padding:0;text-align:left;text-overflow:ellipsis;cursor:pointer}.ui-select__input::placeholder{color:var(--ui-text-muted)}.ui-select__input:focus{cursor:text}.ui-select__input:disabled{cursor:not-allowed}.ui-select__create{display:flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-sm);color:var(--ui-primary);cursor:pointer;border-top:1px solid var(--ui-border);transition:background-color var(--ui-transition-fast)}.ui-select__create:hover{background-color:var(--ui-bg-hover)}.ui-select__options{max-height:var(--ui-dropdown-max-height, 300px);overflow-y:auto}.ui-select__empty{padding:var(--ui-spacing-md);text-align:center;color:var(--ui-text-muted);font-size:var(--ui-font-sm)}.ui-select-wrapper--error .ui-select__trigger{border-color:var(--ui-danger)}.ui-select-wrapper--error .ui-select__trigger:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-select__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-select__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}\n"] }]
1849
- }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], creatable: [{ type: i0.Input, args: [{ isSignal: true, alias: "creatable", required: false }] }], deletable: [{ type: i0.Input, args: [{ isSignal: true, alias: "deletable", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], created: [{ type: i0.Output, args: ["created"] }], deleted: [{ type: i0.Output, args: ["deleted"] }], options: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => OptionComponent), { isSignal: true }] }], triggerRef: [{
2076
+ args: [{ selector: 'ui-select', standalone: true, imports: [FormsModule, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-select-wrapper\"\n [class.ui-select-wrapper--error]=\"error()\"\n [class.ui-select-wrapper--disabled]=\"disabled()\"\n [class.ui-select-wrapper--open]=\"isOpen()\"\n>\n @if (label()) {\n <label class=\"ui-select__label\">\n {{ label() }}\n </label>\n }\n\n <div\n #triggerRef\n class=\"ui-select__trigger\"\n [class]=\"triggerClasses()\"\n [attr.role]=\"'combobox'\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-haspopup]=\"'listbox'\"\n [attr.aria-disabled]=\"disabled()\"\n [attr.tabindex]=\"searchable() ? -1 : (disabled() ? -1 : 0)\"\n (click)=\"toggle()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n >\n @if (searchable()) {\n <input\n #searchInput\n type=\"text\"\n class=\"ui-select__input\"\n [placeholder]=\"inputPlaceholder()\"\n [value]=\"isOpen() ? searchQuery() : (selectable() ? displayValue() : '')\"\n [disabled]=\"disabled()\"\n (input)=\"onSearchInput($any($event.target).value)\"\n (keydown)=\"handleSearchInputKeydown($event)\"\n (focus)=\"toggle()\"\n autocomplete=\"off\"\n />\n } @else {\n <span class=\"ui-select__value\">\n @if (displayValue()) {\n {{ displayValue() }}\n } @else {\n <span class=\"ui-select__placeholder\">{{ placeholder() }}</span>\n }\n </span>\n }\n\n <div class=\"ui-select__icons\">\n @if (clearable() && hasValue() && !disabled()) {\n <button\n type=\"button\"\n class=\"ui-select__clear\"\n (click)=\"clear($event)\"\n aria-label=\"Clear selection\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n }\n <svg\n class=\"ui-select__arrow\"\n [class.ui-select__arrow--open]=\"isOpen()\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <polyline points=\"6 9 12 15 18 9\"></polyline>\n </svg>\n </div>\n </div>\n\n <div\n #dropdownRef\n class=\"ui-select__dropdown\"\n [class.ui-select__dropdown--open]=\"isOpen()\"\n [attr.role]=\"'listbox'\"\n [attr.aria-multiselectable]=\"multiple()\"\n >\n <div class=\"ui-select__options\">\n @if (isAsyncMode()) {\n <!-- Async mode: render options from asyncSearch results -->\n @if (asyncLoading()) {\n <div class=\"ui-select__loading\">\n <svg class=\"ui-select__spinner\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" stroke-opacity=\"0.25\"></circle>\n <path d=\"M12 2a10 10 0 0 1 10 10\" stroke-linecap=\"round\"></path>\n </svg>\n <span>Searching...</span>\n </div>\n } @else if (asyncError()) {\n <div class=\"ui-select__error-message\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"></circle>\n <line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"></line>\n <line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"></line>\n </svg>\n <span>{{ asyncError() }}</span>\n </div>\n } @else {\n @for (option of visibleAsyncOptions(); track option.value; let i = $index) {\n <div\n class=\"ui-async-option\"\n [class.ui-async-option--selected]=\"isAsyncOptionSelected(option)\"\n [class.ui-async-option--disabled]=\"option.disabled\"\n [class.ui-async-option--focused]=\"focusedIndex() === i\"\n [attr.role]=\"'option'\"\n [attr.aria-selected]=\"isAsyncOptionSelected(option)\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"selectAsyncOption(option, $event)\"\n >\n @if (multiple() && isAsyncOptionSelected(option)) {\n <svg class=\"ui-async-option__check\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <polyline points=\"20 6 9 17 4 12\"></polyline>\n </svg>\n }\n <span class=\"ui-async-option__content\">\n @if (optionTemplate(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl.templateRef; context: { $implicit: option.value, option: option.value, selected: isAsyncOptionSelected(option), disabled: !!option.disabled }\"></ng-container>\n } @else {\n {{ option.label }}\n }\n </span>\n </div>\n }\n @if (visibleAsyncOptions().length === 0 && searchQuery().trim().length >= minSearchLength()) {\n <div class=\"ui-select__empty\">No results found</div>\n }\n @if (searchQuery().trim().length < minSearchLength() && minSearchLength() > 0) {\n <div class=\"ui-select__empty\">Type at least {{ minSearchLength() }} characters to search</div>\n }\n }\n } @else {\n <!-- Static mode: render content children -->\n <ng-content />\n @if (visibleOptions().length === 0 && !(creatable() && searchQuery().trim())) {\n <div class=\"ui-select__empty\">No options found</div>\n }\n }\n </div>\n @if (creatable() && searchQuery().trim() && !exactMatchExists()) {\n <div\n class=\"ui-select__create\"\n (click)=\"handleCreate()\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n Create \"{{ searchQuery().trim() }}\"\n </div>\n }\n </div>\n\n @if (error()) {\n <span class=\"ui-select__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-select__hint\">{{ hint() }}</span>\n }\n</div>\n", styles: [":host{display:block;position:relative}.ui-select-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-select__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-select__trigger{display:flex;align-items:center;justify-content:space-between;gap:var(--ui-spacing-sm);width:100%;background-color:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);cursor:pointer;transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast)}.ui-select__trigger:hover:not([aria-disabled=true]){border-color:var(--ui-border-hover)}.ui-select__trigger:focus{outline:none;border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-select__trigger[aria-disabled=true]{background-color:var(--ui-bg-secondary);color:var(--ui-text-disabled);cursor:not-allowed}.ui-select__trigger--sm{padding:var(--ui-spacing-xs) var(--ui-spacing-sm);font-size:var(--ui-font-sm)}.ui-select__trigger--md{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-md)}.ui-select__trigger--lg{padding:var(--ui-spacing-md) var(--ui-spacing-lg);font-size:var(--ui-font-lg)}.ui-select__trigger--outlined{background-color:transparent}.ui-select__trigger--filled{background-color:var(--ui-bg-secondary);border-color:transparent}.ui-select__trigger--filled:hover:not([aria-disabled=true]){background-color:var(--ui-bg-tertiary)}.ui-select__trigger--filled:focus{border-color:var(--ui-border-focus)}.ui-select__value{flex:1;min-width:0;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__placeholder{color:var(--ui-text-muted)}.ui-select__icons{display:flex;align-items:center;gap:var(--ui-spacing-xs);flex-shrink:0}.ui-select__clear{display:flex;align-items:center;justify-content:center;padding:2px;background:none;border:none;cursor:pointer;color:var(--ui-text-muted);border-radius:var(--ui-radius-sm);transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-select__clear:hover{color:var(--ui-text);background-color:var(--ui-bg-hover)}.ui-select__arrow{color:var(--ui-text-muted);transition:transform var(--ui-transition-fast)}.ui-select__arrow--open{transform:rotate(180deg)}.ui-select__dropdown{position:absolute;top:100%;left:0;right:0;z-index:1000;margin-top:var(--ui-spacing-xs);background-color:var(--ui-dropdown-bg, var(--ui-bg));border:1px solid var(--ui-dropdown-border, var(--ui-border));border-radius:var(--ui-dropdown-radius, var(--ui-radius-md));box-shadow:var(--ui-dropdown-shadow, var(--ui-shadow-lg));overflow:hidden;display:none;opacity:0;transform:translateY(-8px);transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast);box-sizing:border-box}.ui-select__dropdown--open{display:block;opacity:1;transform:translateY(0)}.ui-select__input{flex:1;min-width:0;background:none;border:none;outline:none;font:inherit;color:inherit;padding:0;text-align:left;text-overflow:ellipsis;cursor:pointer}.ui-select__input::placeholder{color:var(--ui-text-muted)}.ui-select__input:focus{cursor:text}.ui-select__input:disabled{cursor:not-allowed}.ui-select__create{display:flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-size:var(--ui-font-sm);color:var(--ui-primary);cursor:pointer;border-top:1px solid var(--ui-border);transition:background-color var(--ui-transition-fast)}.ui-select__create:hover{background-color:var(--ui-bg-hover)}.ui-select__options{max-height:var(--ui-dropdown-max-height, 300px);overflow-y:auto}.ui-select__empty{padding:var(--ui-spacing-md);text-align:center;color:var(--ui-text-muted);font-size:var(--ui-font-sm)}.ui-select-wrapper--error .ui-select__trigger{border-color:var(--ui-danger)}.ui-select-wrapper--error .ui-select__trigger:focus{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-select__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-select__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-async-option{display:flex;align-items:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-sm) var(--ui-spacing-md);cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-async-option:hover:not(.ui-async-option--disabled){background-color:var(--ui-bg-hover)}.ui-async-option--selected{background-color:color-mix(in srgb,var(--ui-primary) 10%,transparent)}.ui-async-option--selected:hover:not(.ui-async-option--disabled){background-color:color-mix(in srgb,var(--ui-primary) 15%,transparent)}.ui-async-option--focused{background-color:var(--ui-bg-hover);outline:none}.ui-async-option--focused.ui-async-option--selected{background-color:color-mix(in srgb,var(--ui-primary) 15%,transparent)}.ui-async-option--disabled{opacity:.5;cursor:not-allowed}.ui-async-option__check{flex-shrink:0;color:var(--ui-primary)}.ui-async-option__content{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-select__loading{display:flex;align-items:center;justify-content:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-lg) var(--ui-spacing-md);color:var(--ui-text-muted);font-size:var(--ui-font-sm)}.ui-select__spinner{animation:ui-select-spin 1s linear infinite}@keyframes ui-select-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ui-select__error-message{display:flex;align-items:center;justify-content:center;gap:var(--ui-spacing-sm);padding:var(--ui-spacing-md);color:var(--ui-danger);font-size:var(--ui-font-sm)}\n"] }]
2077
+ }], ctorParameters: () => [], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], multiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiple", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], clearable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clearable", required: false }] }], creatable: [{ type: i0.Input, args: [{ isSignal: true, alias: "creatable", required: false }] }], deletable: [{ type: i0.Input, args: [{ isSignal: true, alias: "deletable", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], asyncSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "asyncSearch", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }], minSearchLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minSearchLength", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], opened: [{ type: i0.Output, args: ["opened"] }], closed: [{ type: i0.Output, args: ["closed"] }], created: [{ type: i0.Output, args: ["created"] }], deleted: [{ type: i0.Output, args: ["deleted"] }], options: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => OptionComponent), { isSignal: true }] }], optionTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => OptionTemplateDirective), { isSignal: true }] }], triggerRef: [{
1850
2078
  type: ViewChild,
1851
2079
  args: ['triggerRef', { static: true }]
1852
2080
  }], dropdownRef: [{
@@ -1860,19 +2088,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
1860
2088
  args: ['document:click', ['$event']]
1861
2089
  }] } });
1862
2090
 
1863
- class OptionTemplateDirective {
1864
- templateRef = inject((TemplateRef));
1865
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OptionTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1866
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: OptionTemplateDirective, isStandalone: true, selector: "[uiOptionTemplate]", ngImport: i0 });
1867
- }
1868
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: OptionTemplateDirective, decorators: [{
1869
- type: Directive,
1870
- args: [{
1871
- selector: '[uiOptionTemplate]',
1872
- standalone: true,
1873
- }]
1874
- }] });
1875
-
1876
2091
  class DropdownTriggerDirective {
1877
2092
  elementRef = inject(ElementRef);
1878
2093
  toggleDropdown = output();
@@ -6001,6 +6216,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
6001
6216
  standalone: true,
6002
6217
  }]
6003
6218
  }] });
6219
+ /** Directive to mark suffix content (buttons, icons, etc.) */
6220
+ class TemplateInputSuffixDirective {
6221
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TemplateInputSuffixDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
6222
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.1", type: TemplateInputSuffixDirective, isStandalone: true, selector: "[uiTemplateInputSuffix]", ngImport: i0 });
6223
+ }
6224
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TemplateInputSuffixDirective, decorators: [{
6225
+ type: Directive,
6226
+ args: [{
6227
+ selector: '[uiTemplateInputSuffix]',
6228
+ standalone: true,
6229
+ }]
6230
+ }] });
6004
6231
  class TemplateInputComponent {
6005
6232
  renderer;
6006
6233
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
@@ -6026,6 +6253,12 @@ class TemplateInputComponent {
6026
6253
  variableHover = output();
6027
6254
  /** Custom popover template for variables. Receives VariablePopoverContext. */
6028
6255
  popoverTemplate = contentChild(VariablePopoverDirective, { ...(ngDevMode ? { debugName: "popoverTemplate" } : {}), read: TemplateRef });
6256
+ /** Detect if suffix content is projected */
6257
+ hasSuffix = contentChildren(TemplateInputSuffixDirective, ...(ngDevMode ? [{ debugName: "hasSuffix" }] : []));
6258
+ suffixRef = viewChild('suffixEl', ...(ngDevMode ? [{ debugName: "suffixRef" }] : []));
6259
+ /** Computed padding-right based on suffix width */
6260
+ suffixPadding = signal(0, ...(ngDevMode ? [{ debugName: "suffixPadding" }] : []));
6261
+ resizeObserver = null;
6029
6262
  static nextId = 0;
6030
6263
  generatedId = `ui-template-input-${++TemplateInputComponent.nextId}`;
6031
6264
  inputId = computed(() => this.id() || this.generatedId, ...(ngDevMode ? [{ debugName: "inputId" }] : []));
@@ -6059,6 +6292,29 @@ class TemplateInputComponent {
6059
6292
  this.renderer = renderer;
6060
6293
  this.injectStyles();
6061
6294
  }
6295
+ ngAfterViewInit() {
6296
+ this.observeSuffix();
6297
+ }
6298
+ observeSuffix() {
6299
+ const suffixEl = this.suffixRef()?.nativeElement;
6300
+ if (!suffixEl)
6301
+ return;
6302
+ this.updateSuffixPadding(suffixEl);
6303
+ this.resizeObserver = new ResizeObserver(() => {
6304
+ this.updateSuffixPadding(suffixEl);
6305
+ });
6306
+ this.resizeObserver.observe(suffixEl);
6307
+ }
6308
+ updateSuffixPadding(el) {
6309
+ const width = el.offsetWidth;
6310
+ if (width > 0) {
6311
+ // Add small gap between content and suffix
6312
+ this.suffixPadding.set(width + 8);
6313
+ }
6314
+ else {
6315
+ this.suffixPadding.set(0);
6316
+ }
6317
+ }
6062
6318
  highlightedHtml = computed(() => {
6063
6319
  const text = this.value();
6064
6320
  if (!text)
@@ -6298,14 +6554,19 @@ class TemplateInputComponent {
6298
6554
  this.removePositionListeners();
6299
6555
  this.isPortaled = false;
6300
6556
  }
6557
+ // Clean up ResizeObserver
6558
+ if (this.resizeObserver) {
6559
+ this.resizeObserver.disconnect();
6560
+ this.resizeObserver = null;
6561
+ }
6301
6562
  }
6302
6563
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TemplateInputComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
6303
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TemplateInputComponent, isStandalone: true, selector: "ui-template-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, variables: { classPropertyName: "variables", publicName: "variables", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { value: "valueChange", variables: "variablesChange", variableHover: "variableHover" }, queries: [{ propertyName: "popoverTemplate", first: true, predicate: VariablePopoverDirective, descendants: true, read: TemplateRef, isSignal: true }], viewQueries: [{ propertyName: "mirrorRef", first: true, predicate: ["mirror"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "popoverRef", first: true, predicate: ["popoverRef"], descendants: true, static: true }], ngImport: i0, template: "<div\n class=\"ui-template-input-wrapper\"\n [class.ui-template-input-wrapper--error]=\"error()\"\n [class.ui-template-input-wrapper--disabled]=\"disabled()\"\n>\n @if (label()) {\n <label class=\"ui-template-input__label\" [attr.for]=\"inputId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"ui-template-input__required\">*</span>\n }\n </label>\n }\n <div\n class=\"ui-template-input__container\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onContainerMouseLeave()\"\n >\n <div\n class=\"ui-template-input__mirror\"\n #mirror\n [innerHTML]=\"highlightedHtml()\"\n ></div>\n <input\n class=\"ui-template-input__input\"\n #inputEl\n [id]=\"inputId()\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [(ngModel)]=\"value\"\n (input)=\"onInput()\"\n (scroll)=\"syncScroll()\"\n (click)=\"syncScroll()\"\n (keydown)=\"onKeyDown()\"\n />\n </div>\n @if (error()) {\n <span class=\"ui-template-input__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-template-input__hint\">{{ hint() }}</span>\n }\n</div>\n\n<div\n #popoverRef\n class=\"ui-tmpl-popover\"\n [class.ui-tmpl-popover--open]=\"popoverVisible()\"\n [class.ui-tmpl-popover--above]=\"openAbove()\"\n [class.ui-tmpl-popover--below]=\"!openAbove()\"\n (mouseenter)=\"onPopoverMouseEnter()\"\n (mouseleave)=\"onPopoverMouseLeave()\"\n>\n @if (popoverVisible()) {\n @if (popoverTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate()!\"\n [ngTemplateOutletContext]=\"popoverContext()\"\n />\n } @else {\n <span class=\"ui-tmpl-popover__text\">{{ popoverText() }}</span>\n }\n }\n</div>\n", styles: [":host{display:block}.ui-template-input-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-template-input__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-template-input__required{color:var(--ui-danger);margin-left:2px}.ui-template-input__container{position:relative;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background-color:var(--ui-bg);transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);overflow:hidden}.ui-template-input__container:hover{border-color:var(--ui-border-hover)}.ui-template-input__container:focus-within{border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-template-input__mirror{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:var(--ui-text);white-space:pre;overflow:hidden;pointer-events:none}.ui-template-input__input{position:absolute;top:0;left:0;width:100%;height:100%;padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:transparent;caret-color:var(--ui-text);background:transparent;border:none;outline:none}.ui-template-input__input::placeholder{color:var(--ui-text-muted)}.ui-template-input__input:disabled{cursor:not-allowed}.ui-template-input-wrapper--disabled .ui-template-input__container{background-color:var(--ui-bg-secondary)}.ui-template-input-wrapper--disabled .ui-template-input__container:hover{border-color:var(--ui-border)}.ui-template-input-wrapper--disabled .ui-template-input__mirror{color:var(--ui-text-disabled)}.ui-template-input-wrapper--error .ui-template-input__container{border-color:var(--ui-danger)}.ui-template-input-wrapper--error .ui-template-input__container:focus-within{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-template-input__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-template-input__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tmpl-popover{display:none;line-height:1.5;background:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);opacity:0;transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast)}.ui-tmpl-popover--open{opacity:1}.ui-tmpl-popover--above{transform:translateY(4px)}.ui-tmpl-popover--above.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover--below{transform:translateY(-4px)}.ui-tmpl-popover--below.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover__text{display:block;padding:.375rem .625rem;font-size:var(--ui-font-sm);color:var(--ui-text);white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6564
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TemplateInputComponent, isStandalone: true, selector: "ui-template-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, variables: { classPropertyName: "variables", publicName: "variables", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { value: "valueChange", variables: "variablesChange", variableHover: "variableHover" }, queries: [{ propertyName: "popoverTemplate", first: true, predicate: VariablePopoverDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "hasSuffix", predicate: TemplateInputSuffixDirective, isSignal: true }], viewQueries: [{ propertyName: "suffixRef", first: true, predicate: ["suffixEl"], descendants: true, isSignal: true }, { propertyName: "mirrorRef", first: true, predicate: ["mirror"], descendants: true, isSignal: true }, { propertyName: "inputRef", first: true, predicate: ["inputEl"], descendants: true, isSignal: true }, { propertyName: "popoverRef", first: true, predicate: ["popoverRef"], descendants: true, static: true }], ngImport: i0, template: "<div\n class=\"ui-template-input-wrapper\"\n [class.ui-template-input-wrapper--error]=\"error()\"\n [class.ui-template-input-wrapper--disabled]=\"disabled()\"\n>\n @if (label()) {\n <label class=\"ui-template-input__label\" [attr.for]=\"inputId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"ui-template-input__required\">*</span>\n }\n </label>\n }\n <div\n class=\"ui-template-input__container\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onContainerMouseLeave()\"\n >\n <div\n class=\"ui-template-input__mirror\"\n #mirror\n [style.padding-right.px]=\"suffixPadding() || null\"\n [innerHTML]=\"highlightedHtml()\"\n ></div>\n <input\n class=\"ui-template-input__input\"\n #inputEl\n [id]=\"inputId()\"\n type=\"text\"\n [style.padding-right.px]=\"suffixPadding() || null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [(ngModel)]=\"value\"\n (input)=\"onInput()\"\n (scroll)=\"syncScroll()\"\n (click)=\"syncScroll()\"\n (keydown)=\"onKeyDown()\"\n />\n <div class=\"ui-template-input__suffix\" #suffixEl>\n <ng-content select=\"[uiTemplateInputSuffix]\" />\n </div>\n </div>\n @if (error()) {\n <span class=\"ui-template-input__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-template-input__hint\">{{ hint() }}</span>\n }\n</div>\n\n<div\n #popoverRef\n class=\"ui-tmpl-popover\"\n [class.ui-tmpl-popover--open]=\"popoverVisible()\"\n [class.ui-tmpl-popover--above]=\"openAbove()\"\n [class.ui-tmpl-popover--below]=\"!openAbove()\"\n (mouseenter)=\"onPopoverMouseEnter()\"\n (mouseleave)=\"onPopoverMouseLeave()\"\n>\n @if (popoverVisible()) {\n @if (popoverTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate()!\"\n [ngTemplateOutletContext]=\"popoverContext()\"\n />\n } @else {\n <span class=\"ui-tmpl-popover__text\">{{ popoverText() }}</span>\n }\n }\n</div>\n", styles: [":host{display:block}.ui-template-input-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-template-input__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-template-input__required{color:var(--ui-danger);margin-left:2px}.ui-template-input__container{position:relative;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background-color:var(--ui-bg);transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);overflow:hidden}.ui-template-input__container:hover{border-color:var(--ui-border-hover)}.ui-template-input__container:focus-within{border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-template-input__mirror{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:var(--ui-text);white-space:pre;overflow-x:auto;overflow-y:hidden;pointer-events:none;scrollbar-width:none;-ms-overflow-style:none}.ui-template-input__mirror::-webkit-scrollbar{display:none}.ui-template-input__input{position:absolute;top:0;left:0;width:100%;height:100%;padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:transparent;caret-color:var(--ui-text);background:transparent;border:none;outline:none}.ui-template-input__input::placeholder{color:var(--ui-text-muted)}.ui-template-input__input:disabled{cursor:not-allowed}.ui-template-input__suffix{position:absolute;top:0;right:0;bottom:0;display:flex;align-items:center;gap:var(--ui-spacing-xs);padding-right:var(--ui-spacing-sm);pointer-events:auto}.ui-template-input__suffix:empty{display:none}.ui-template-input-wrapper--disabled .ui-template-input__container{background-color:var(--ui-bg-secondary)}.ui-template-input-wrapper--disabled .ui-template-input__container:hover{border-color:var(--ui-border)}.ui-template-input-wrapper--disabled .ui-template-input__mirror{color:var(--ui-text-disabled)}.ui-template-input-wrapper--error .ui-template-input__container{border-color:var(--ui-danger)}.ui-template-input-wrapper--error .ui-template-input__container:focus-within{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-template-input__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-template-input__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tmpl-popover{display:none;line-height:1.5;background:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);opacity:0;transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast)}.ui-tmpl-popover--open{opacity:1}.ui-tmpl-popover--above{transform:translateY(4px)}.ui-tmpl-popover--above.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover--below{transform:translateY(-4px)}.ui-tmpl-popover--below.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover__text{display:block;padding:.375rem .625rem;font-size:var(--ui-font-sm);color:var(--ui-text);white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6304
6565
  }
6305
6566
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TemplateInputComponent, decorators: [{
6306
6567
  type: Component,
6307
- args: [{ selector: 'ui-template-input', standalone: true, imports: [FormsModule, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-template-input-wrapper\"\n [class.ui-template-input-wrapper--error]=\"error()\"\n [class.ui-template-input-wrapper--disabled]=\"disabled()\"\n>\n @if (label()) {\n <label class=\"ui-template-input__label\" [attr.for]=\"inputId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"ui-template-input__required\">*</span>\n }\n </label>\n }\n <div\n class=\"ui-template-input__container\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onContainerMouseLeave()\"\n >\n <div\n class=\"ui-template-input__mirror\"\n #mirror\n [innerHTML]=\"highlightedHtml()\"\n ></div>\n <input\n class=\"ui-template-input__input\"\n #inputEl\n [id]=\"inputId()\"\n type=\"text\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [(ngModel)]=\"value\"\n (input)=\"onInput()\"\n (scroll)=\"syncScroll()\"\n (click)=\"syncScroll()\"\n (keydown)=\"onKeyDown()\"\n />\n </div>\n @if (error()) {\n <span class=\"ui-template-input__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-template-input__hint\">{{ hint() }}</span>\n }\n</div>\n\n<div\n #popoverRef\n class=\"ui-tmpl-popover\"\n [class.ui-tmpl-popover--open]=\"popoverVisible()\"\n [class.ui-tmpl-popover--above]=\"openAbove()\"\n [class.ui-tmpl-popover--below]=\"!openAbove()\"\n (mouseenter)=\"onPopoverMouseEnter()\"\n (mouseleave)=\"onPopoverMouseLeave()\"\n>\n @if (popoverVisible()) {\n @if (popoverTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate()!\"\n [ngTemplateOutletContext]=\"popoverContext()\"\n />\n } @else {\n <span class=\"ui-tmpl-popover__text\">{{ popoverText() }}</span>\n }\n }\n</div>\n", styles: [":host{display:block}.ui-template-input-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-template-input__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-template-input__required{color:var(--ui-danger);margin-left:2px}.ui-template-input__container{position:relative;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background-color:var(--ui-bg);transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);overflow:hidden}.ui-template-input__container:hover{border-color:var(--ui-border-hover)}.ui-template-input__container:focus-within{border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-template-input__mirror{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:var(--ui-text);white-space:pre;overflow:hidden;pointer-events:none}.ui-template-input__input{position:absolute;top:0;left:0;width:100%;height:100%;padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:transparent;caret-color:var(--ui-text);background:transparent;border:none;outline:none}.ui-template-input__input::placeholder{color:var(--ui-text-muted)}.ui-template-input__input:disabled{cursor:not-allowed}.ui-template-input-wrapper--disabled .ui-template-input__container{background-color:var(--ui-bg-secondary)}.ui-template-input-wrapper--disabled .ui-template-input__container:hover{border-color:var(--ui-border)}.ui-template-input-wrapper--disabled .ui-template-input__mirror{color:var(--ui-text-disabled)}.ui-template-input-wrapper--error .ui-template-input__container{border-color:var(--ui-danger)}.ui-template-input-wrapper--error .ui-template-input__container:focus-within{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-template-input__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-template-input__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tmpl-popover{display:none;line-height:1.5;background:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);opacity:0;transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast)}.ui-tmpl-popover--open{opacity:1}.ui-tmpl-popover--above{transform:translateY(4px)}.ui-tmpl-popover--above.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover--below{transform:translateY(-4px)}.ui-tmpl-popover--below.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover__text{display:block;padding:.375rem .625rem;font-size:var(--ui-font-sm);color:var(--ui-text);white-space:nowrap}\n"] }]
6308
- }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }, { type: i0.Output, args: ["valueChange"] }], variables: [{ type: i0.Input, args: [{ isSignal: true, alias: "variables", required: true }] }, { type: i0.Output, args: ["variablesChange"] }], variableHover: [{ type: i0.Output, args: ["variableHover"] }], popoverTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => VariablePopoverDirective), { ...{ read: TemplateRef }, isSignal: true }] }], mirrorRef: [{ type: i0.ViewChild, args: ['mirror', { isSignal: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }], popoverRef: [{
6568
+ args: [{ selector: 'ui-template-input', standalone: true, imports: [FormsModule, NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-template-input-wrapper\"\n [class.ui-template-input-wrapper--error]=\"error()\"\n [class.ui-template-input-wrapper--disabled]=\"disabled()\"\n>\n @if (label()) {\n <label class=\"ui-template-input__label\" [attr.for]=\"inputId()\">\n {{ label() }}\n @if (required()) {\n <span class=\"ui-template-input__required\">*</span>\n }\n </label>\n }\n <div\n class=\"ui-template-input__container\"\n (mousemove)=\"onMouseMove($event)\"\n (mouseleave)=\"onContainerMouseLeave()\"\n >\n <div\n class=\"ui-template-input__mirror\"\n #mirror\n [style.padding-right.px]=\"suffixPadding() || null\"\n [innerHTML]=\"highlightedHtml()\"\n ></div>\n <input\n class=\"ui-template-input__input\"\n #inputEl\n [id]=\"inputId()\"\n type=\"text\"\n [style.padding-right.px]=\"suffixPadding() || null\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [(ngModel)]=\"value\"\n (input)=\"onInput()\"\n (scroll)=\"syncScroll()\"\n (click)=\"syncScroll()\"\n (keydown)=\"onKeyDown()\"\n />\n <div class=\"ui-template-input__suffix\" #suffixEl>\n <ng-content select=\"[uiTemplateInputSuffix]\" />\n </div>\n </div>\n @if (error()) {\n <span class=\"ui-template-input__error\">{{ error() }}</span>\n }\n @if (hint() && !error()) {\n <span class=\"ui-template-input__hint\">{{ hint() }}</span>\n }\n</div>\n\n<div\n #popoverRef\n class=\"ui-tmpl-popover\"\n [class.ui-tmpl-popover--open]=\"popoverVisible()\"\n [class.ui-tmpl-popover--above]=\"openAbove()\"\n [class.ui-tmpl-popover--below]=\"!openAbove()\"\n (mouseenter)=\"onPopoverMouseEnter()\"\n (mouseleave)=\"onPopoverMouseLeave()\"\n>\n @if (popoverVisible()) {\n @if (popoverTemplate()) {\n <ng-container\n [ngTemplateOutlet]=\"popoverTemplate()!\"\n [ngTemplateOutletContext]=\"popoverContext()\"\n />\n } @else {\n <span class=\"ui-tmpl-popover__text\">{{ popoverText() }}</span>\n }\n }\n</div>\n", styles: [":host{display:block}.ui-template-input-wrapper{display:flex;flex-direction:column;gap:var(--ui-spacing-xs)}.ui-template-input__label{font-size:var(--ui-font-sm);font-weight:500;color:var(--ui-text)}.ui-template-input__required{color:var(--ui-danger);margin-left:2px}.ui-template-input__container{position:relative;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background-color:var(--ui-bg);transition:border-color var(--ui-transition-fast),box-shadow var(--ui-transition-fast);overflow:hidden}.ui-template-input__container:hover{border-color:var(--ui-border-hover)}.ui-template-input__container:focus-within{border-color:var(--ui-border-focus);box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-primary) 20%,transparent)}.ui-template-input__mirror{padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:var(--ui-text);white-space:pre;overflow-x:auto;overflow-y:hidden;pointer-events:none;scrollbar-width:none;-ms-overflow-style:none}.ui-template-input__mirror::-webkit-scrollbar{display:none}.ui-template-input__input{position:absolute;top:0;left:0;width:100%;height:100%;padding:var(--ui-spacing-sm) var(--ui-spacing-md);font-family:inherit;font-size:var(--ui-font-md);color:transparent;caret-color:var(--ui-text);background:transparent;border:none;outline:none}.ui-template-input__input::placeholder{color:var(--ui-text-muted)}.ui-template-input__input:disabled{cursor:not-allowed}.ui-template-input__suffix{position:absolute;top:0;right:0;bottom:0;display:flex;align-items:center;gap:var(--ui-spacing-xs);padding-right:var(--ui-spacing-sm);pointer-events:auto}.ui-template-input__suffix:empty{display:none}.ui-template-input-wrapper--disabled .ui-template-input__container{background-color:var(--ui-bg-secondary)}.ui-template-input-wrapper--disabled .ui-template-input__container:hover{border-color:var(--ui-border)}.ui-template-input-wrapper--disabled .ui-template-input__mirror{color:var(--ui-text-disabled)}.ui-template-input-wrapper--error .ui-template-input__container{border-color:var(--ui-danger)}.ui-template-input-wrapper--error .ui-template-input__container:focus-within{box-shadow:0 0 0 3px color-mix(in srgb,var(--ui-danger) 20%,transparent)}.ui-template-input__error{font-size:var(--ui-font-sm);color:var(--ui-danger)}.ui-template-input__hint{font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tmpl-popover{display:none;line-height:1.5;background:var(--ui-bg);border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);box-shadow:var(--ui-shadow-lg);opacity:0;transition:opacity var(--ui-transition-fast),transform var(--ui-transition-fast)}.ui-tmpl-popover--open{opacity:1}.ui-tmpl-popover--above{transform:translateY(4px)}.ui-tmpl-popover--above.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover--below{transform:translateY(-4px)}.ui-tmpl-popover--below.ui-tmpl-popover--open{transform:translateY(0)}.ui-tmpl-popover__text{display:block;padding:.375rem .625rem;font-size:var(--ui-font-sm);color:var(--ui-text);white-space:nowrap}\n"] }]
6569
+ }], ctorParameters: () => [{ type: i0.Renderer2 }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }, { type: i0.Output, args: ["valueChange"] }], variables: [{ type: i0.Input, args: [{ isSignal: true, alias: "variables", required: true }] }, { type: i0.Output, args: ["variablesChange"] }], variableHover: [{ type: i0.Output, args: ["variableHover"] }], popoverTemplate: [{ type: i0.ContentChild, args: [i0.forwardRef(() => VariablePopoverDirective), { ...{ read: TemplateRef }, isSignal: true }] }], hasSuffix: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TemplateInputSuffixDirective), { isSignal: true }] }], suffixRef: [{ type: i0.ViewChild, args: ['suffixEl', { isSignal: true }] }], mirrorRef: [{ type: i0.ViewChild, args: ['mirror', { isSignal: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputEl', { isSignal: true }] }], popoverRef: [{
6309
6570
  type: ViewChild,
6310
6571
  args: ['popoverRef', { static: true }]
6311
6572
  }] } });
@@ -6319,5 +6580,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
6319
6580
  * Generated bundle index. Do not edit.
6320
6581
  */
6321
6582
 
6322
- export { AccordionComponent, AccordionHeaderDirective, AccordionItemComponent, AlertComponent, BadgeComponent, ButtonComponent, CardComponent, CellTemplateDirective, CellValuePipe, CheckboxComponent, ChipInputComponent, ChipTemplateDirective, CircularProgressComponent, ContentComponent, ContextMenuDirective, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DatetimepickerComponent, DialogRef, DialogService, DropdownComponent, DropdownDividerComponent, DropdownItemComponent, DropdownTriggerDirective, DynamicTabsComponent, FileChooserComponent, FilePreviewPipe, FileSizePipe, FooterComponent, InputComponent, LOADABLE, LoadingDirective, LoadingService, ModalComponent, NavbarComponent, OptionComponent, OptionTemplateDirective, PaginationComponent, ProgressComponent, RadioComponent, RadioGroupComponent, SelectComponent, ShellComponent, SidebarComponent, SidebarService, SidebarToggleComponent, SliderComponent, SpinnerComponent, SplitComponent, SplitPaneComponent, SwitchComponent, TAB_DATA, TAB_REF, TREE_HOST, TabActivePipe, TabComponent, TabIconDirective, TabRef, TableComponent, TabsComponent, TabsService, TemplateInputComponent, TextareaComponent, TimepickerComponent, ToastRef, ToastService, TooltipDirective, TreeComponent, TreeNodeComponent, Validators, VariablePopoverDirective };
6583
+ export { AccordionComponent, AccordionHeaderDirective, AccordionItemComponent, AlertComponent, BadgeComponent, ButtonComponent, CardComponent, CellTemplateDirective, CellValuePipe, CheckboxComponent, ChipInputComponent, ChipTemplateDirective, CircularProgressComponent, ContentComponent, ContextMenuDirective, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DatetimepickerComponent, DialogRef, DialogService, DropdownComponent, DropdownDividerComponent, DropdownItemComponent, DropdownTriggerDirective, DynamicTabsComponent, FileChooserComponent, FilePreviewPipe, FileSizePipe, FooterComponent, InputComponent, LOADABLE, LoadingDirective, LoadingService, ModalComponent, NavbarComponent, OptionComponent, OptionTemplateDirective, PaginationComponent, ProgressComponent, RadioComponent, RadioGroupComponent, SelectComponent, ShellComponent, SidebarComponent, SidebarService, SidebarToggleComponent, SliderComponent, SpinnerComponent, SplitComponent, SplitPaneComponent, SwitchComponent, TAB_DATA, TAB_REF, TREE_HOST, TabActivePipe, TabComponent, TabIconDirective, TabRef, TableComponent, TabsComponent, TabsService, TemplateInputComponent, TemplateInputSuffixDirective, TextareaComponent, TimepickerComponent, ToastRef, ToastService, TooltipDirective, TreeComponent, TreeNodeComponent, Validators, VariablePopoverDirective };
6323
6584
  //# sourceMappingURL=m1z23r-ngx-ui.mjs.map