@keenthemes/ktui 1.0.20 → 1.0.21

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.
Files changed (98) hide show
  1. package/dist/ktui.js +418 -144
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +139 -31
  5. package/examples/image-input/file-upload-example.html +189 -0
  6. package/examples/select/remote-data_.html +5 -0
  7. package/examples/select/test-optimizations.html +227 -0
  8. package/examples/select/test-remote-search.html +151 -0
  9. package/examples/sticky/README.md +158 -0
  10. package/examples/sticky/debug-sticky.html +144 -0
  11. package/examples/sticky/test-runner.html +175 -0
  12. package/examples/sticky/test-sticky-logic.js +369 -0
  13. package/examples/sticky/test-sticky-positioning.html +386 -0
  14. package/examples/toast/example.html +52 -0
  15. package/lib/cjs/components/component.js +5 -3
  16. package/lib/cjs/components/component.js.map +1 -1
  17. package/lib/cjs/components/datatable/datatable-sort.js +4 -0
  18. package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
  19. package/lib/cjs/components/datatable/datatable.js +9 -3
  20. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  21. package/lib/cjs/components/image-input/image-input.js +10 -2
  22. package/lib/cjs/components/image-input/image-input.js.map +1 -1
  23. package/lib/cjs/components/select/combobox.js +50 -20
  24. package/lib/cjs/components/select/combobox.js.map +1 -1
  25. package/lib/cjs/components/select/dropdown.js +4 -2
  26. package/lib/cjs/components/select/dropdown.js.map +1 -1
  27. package/lib/cjs/components/select/index.js.map +1 -1
  28. package/lib/cjs/components/select/option.js +2 -1
  29. package/lib/cjs/components/select/option.js.map +1 -1
  30. package/lib/cjs/components/select/remote.js +50 -50
  31. package/lib/cjs/components/select/remote.js.map +1 -1
  32. package/lib/cjs/components/select/search.js +7 -5
  33. package/lib/cjs/components/select/search.js.map +1 -1
  34. package/lib/cjs/components/select/select.js +199 -33
  35. package/lib/cjs/components/select/select.js.map +1 -1
  36. package/lib/cjs/components/select/tags.js +3 -1
  37. package/lib/cjs/components/select/tags.js.map +1 -1
  38. package/lib/cjs/components/select/templates.js.map +1 -1
  39. package/lib/cjs/components/select/utils.js +23 -10
  40. package/lib/cjs/components/select/utils.js.map +1 -1
  41. package/lib/cjs/components/sticky/sticky.js +52 -14
  42. package/lib/cjs/components/sticky/sticky.js.map +1 -1
  43. package/lib/esm/components/component.js +5 -3
  44. package/lib/esm/components/component.js.map +1 -1
  45. package/lib/esm/components/datatable/datatable-sort.js +4 -0
  46. package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
  47. package/lib/esm/components/datatable/datatable.js +9 -3
  48. package/lib/esm/components/datatable/datatable.js.map +1 -1
  49. package/lib/esm/components/image-input/image-input.js +10 -2
  50. package/lib/esm/components/image-input/image-input.js.map +1 -1
  51. package/lib/esm/components/select/combobox.js +50 -20
  52. package/lib/esm/components/select/combobox.js.map +1 -1
  53. package/lib/esm/components/select/dropdown.js +4 -2
  54. package/lib/esm/components/select/dropdown.js.map +1 -1
  55. package/lib/esm/components/select/index.js +1 -1
  56. package/lib/esm/components/select/index.js.map +1 -1
  57. package/lib/esm/components/select/option.js +2 -1
  58. package/lib/esm/components/select/option.js.map +1 -1
  59. package/lib/esm/components/select/remote.js +50 -50
  60. package/lib/esm/components/select/remote.js.map +1 -1
  61. package/lib/esm/components/select/search.js +8 -6
  62. package/lib/esm/components/select/search.js.map +1 -1
  63. package/lib/esm/components/select/select.js +199 -33
  64. package/lib/esm/components/select/select.js.map +1 -1
  65. package/lib/esm/components/select/tags.js +3 -1
  66. package/lib/esm/components/select/tags.js.map +1 -1
  67. package/lib/esm/components/select/templates.js.map +1 -1
  68. package/lib/esm/components/select/utils.js +23 -10
  69. package/lib/esm/components/select/utils.js.map +1 -1
  70. package/lib/esm/components/sticky/sticky.js +52 -14
  71. package/lib/esm/components/sticky/sticky.js.map +1 -1
  72. package/package.json +1 -1
  73. package/src/components/component.ts +12 -11
  74. package/src/components/datatable/datatable-sort.ts +6 -0
  75. package/src/components/datatable/datatable.ts +90 -81
  76. package/src/components/image-input/image-input.ts +11 -2
  77. package/src/components/image-input/types.ts +1 -0
  78. package/src/components/input/input-group.css +1 -1
  79. package/src/components/input/input.css +1 -1
  80. package/src/components/scrollable/scrollable.css +3 -3
  81. package/src/components/select/combobox.ts +84 -34
  82. package/src/components/select/dropdown.ts +20 -11
  83. package/src/components/select/index.ts +6 -1
  84. package/src/components/select/option.ts +7 -6
  85. package/src/components/select/remote.ts +51 -52
  86. package/src/components/select/search.ts +51 -45
  87. package/src/components/select/select.css +12 -11
  88. package/src/components/select/select.ts +371 -102
  89. package/src/components/select/tags.ts +9 -3
  90. package/src/components/select/templates.ts +1 -4
  91. package/src/components/select/utils.ts +55 -20
  92. package/src/components/select/variants.css +0 -1
  93. package/src/components/sticky/sticky.ts +47 -16
  94. package/src/components/sticky/types.ts +3 -0
  95. package/src/components/table/table.css +1 -1
  96. package/src/components/textarea/textarea.css +1 -1
  97. package/src/components/toast/toast.css +84 -47
  98. package/src/components/toast/types.ts +3 -0
@@ -499,7 +499,11 @@ export class KTDataTable<T extends KTDataTableDataInterface>
499
499
  // Set search value
500
500
  if (searchElement) {
501
501
  searchElement.value =
502
- search === undefined || search === null ? '' : typeof search === 'string' ? search : String(search);
502
+ search === undefined || search === null
503
+ ? ''
504
+ : typeof search === 'string'
505
+ ? search
506
+ : String(search);
503
507
  }
504
508
 
505
509
  if (searchElement) {
@@ -834,7 +838,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
834
838
  private _createUrl(
835
839
  pathOrUrl: string,
836
840
  baseUrl: string | null = window.location.origin,
837
- ) : URL {
841
+ ): URL {
838
842
  // Regular expression to check if the input is a full URL
839
843
  const isFullUrl = /^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(pathOrUrl);
840
844
 
@@ -988,10 +992,12 @@ export class KTDataTable<T extends KTDataTableDataInterface>
988
992
 
989
993
  if (typeof columnDef.render === 'function') {
990
994
  const result = columnDef.render.call(this, item[key], item, this);
991
- if (result instanceof HTMLElement || result instanceof DocumentFragment) {
995
+ if (
996
+ result instanceof HTMLElement ||
997
+ result instanceof DocumentFragment
998
+ ) {
992
999
  td.appendChild(result);
993
- }
994
- else if (typeof result === 'string') {
1000
+ } else if (typeof result === 'string') {
995
1001
  td.innerHTML = result as string;
996
1002
  }
997
1003
  } else {
@@ -1423,77 +1429,80 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1423
1429
  return id;
1424
1430
  }
1425
1431
 
1426
- /**
1427
- * Clean up all event listeners, handlers, and DOM nodes created by this instance.
1428
- * This method is called before re-rendering or when disposing the component.
1429
- */
1430
- private _dispose() {
1431
- // --- 1. Remove search input event listener (debounced) ---
1432
- const tableId: string = this._tableId();
1433
- const searchElement: HTMLInputElement | null =
1434
- document.querySelector<HTMLInputElement>(
1435
- `[data-kt-datatable-search="#${tableId}"]`,
1436
- );
1437
- if (searchElement && (searchElement as any)._debouncedSearch) {
1438
- searchElement.removeEventListener(
1439
- 'keyup',
1440
- (searchElement as any)._debouncedSearch,
1441
- );
1442
- delete (searchElement as any)._debouncedSearch;
1443
- }
1444
-
1445
- // --- 2. Remove page size dropdown event listener ---
1446
- if (this._sizeElement && this._sizeElement.onchange) {
1447
- this._sizeElement.onchange = null;
1448
- }
1449
-
1450
- // --- 3. Remove all pagination button event listeners ---
1451
- if (this._paginationElement) {
1452
- // Remove all child nodes (buttons) to ensure no lingering listeners
1453
- while (this._paginationElement.firstChild) {
1454
- this._paginationElement.removeChild(this._paginationElement.firstChild);
1455
- }
1456
- }
1457
-
1458
- // --- 4. Dispose of handler objects (checkbox, sort) ---
1459
- // KTDataTableCheckboxAPI does not have a dispose method, but we can remove header checkbox listener
1460
- if (this._checkbox && typeof (this._checkbox as any).dispose === 'function') {
1461
- (this._checkbox as any).dispose();
1462
- } else {
1463
- // Remove header checkbox event listener if possible
1464
- const headerCheckElement = this._element.querySelector<HTMLInputElement>(
1465
- this._config.attributes.check,
1466
- );
1467
- if (headerCheckElement) {
1468
- headerCheckElement.replaceWith(headerCheckElement.cloneNode(true));
1469
- }
1470
- }
1471
- // KTDataTableSortAPI does not have a dispose method, but we can remove th click listeners by replacing them
1472
- if (this._theadElement) {
1473
- const ths = this._theadElement.querySelectorAll('th');
1474
- ths.forEach((th) => {
1475
- th.replaceWith(th.cloneNode(true));
1476
- });
1477
- }
1478
-
1479
- // --- 5. Remove spinner DOM node if it exists ---
1480
- const spinner = this._element.querySelector<HTMLElement>(
1481
- this._config.attributes.spinner,
1482
- );
1483
- if (spinner && spinner.parentNode) {
1484
- spinner.parentNode.removeChild(spinner);
1485
- }
1486
- this._element.classList.remove(this._config.loadingClass);
1487
-
1488
- // --- 6. Remove instance reference from the DOM element ---
1489
- if ((this._element as any).instance) {
1490
- delete (this._element as any).instance;
1491
- }
1492
-
1493
- // --- 7. (Optional) Clear localStorage state ---
1494
- // Uncomment the following line if you want to clear state on dispose:
1495
- // this._deleteState();
1496
- }
1432
+ /**
1433
+ * Clean up all event listeners, handlers, and DOM nodes created by this instance.
1434
+ * This method is called before re-rendering or when disposing the component.
1435
+ */
1436
+ private _dispose() {
1437
+ // --- 1. Remove search input event listener (debounced) ---
1438
+ const tableId: string = this._tableId();
1439
+ const searchElement: HTMLInputElement | null =
1440
+ document.querySelector<HTMLInputElement>(
1441
+ `[data-kt-datatable-search="#${tableId}"]`,
1442
+ );
1443
+ if (searchElement && (searchElement as any)._debouncedSearch) {
1444
+ searchElement.removeEventListener(
1445
+ 'keyup',
1446
+ (searchElement as any)._debouncedSearch,
1447
+ );
1448
+ delete (searchElement as any)._debouncedSearch;
1449
+ }
1450
+
1451
+ // --- 2. Remove page size dropdown event listener ---
1452
+ if (this._sizeElement && this._sizeElement.onchange) {
1453
+ this._sizeElement.onchange = null;
1454
+ }
1455
+
1456
+ // --- 3. Remove all pagination button event listeners ---
1457
+ if (this._paginationElement) {
1458
+ // Remove all child nodes (buttons) to ensure no lingering listeners
1459
+ while (this._paginationElement.firstChild) {
1460
+ this._paginationElement.removeChild(this._paginationElement.firstChild);
1461
+ }
1462
+ }
1463
+
1464
+ // --- 4. Dispose of handler objects (checkbox, sort) ---
1465
+ // KTDataTableCheckboxAPI does not have a dispose method, but we can remove header checkbox listener
1466
+ if (
1467
+ this._checkbox &&
1468
+ typeof (this._checkbox as any).dispose === 'function'
1469
+ ) {
1470
+ (this._checkbox as any).dispose();
1471
+ } else {
1472
+ // Remove header checkbox event listener if possible
1473
+ const headerCheckElement = this._element.querySelector<HTMLInputElement>(
1474
+ this._config.attributes.check,
1475
+ );
1476
+ if (headerCheckElement) {
1477
+ headerCheckElement.replaceWith(headerCheckElement.cloneNode(true));
1478
+ }
1479
+ }
1480
+ // KTDataTableSortAPI does not have a dispose method, but we can remove th click listeners by replacing them
1481
+ if (this._theadElement) {
1482
+ const ths = this._theadElement.querySelectorAll('th');
1483
+ ths.forEach((th) => {
1484
+ th.replaceWith(th.cloneNode(true));
1485
+ });
1486
+ }
1487
+
1488
+ // --- 5. Remove spinner DOM node if it exists ---
1489
+ const spinner = this._element.querySelector<HTMLElement>(
1490
+ this._config.attributes.spinner,
1491
+ );
1492
+ if (spinner && spinner.parentNode) {
1493
+ spinner.parentNode.removeChild(spinner);
1494
+ }
1495
+ this._element.classList.remove(this._config.loadingClass);
1496
+
1497
+ // --- 6. Remove instance reference from the DOM element ---
1498
+ if ((this._element as any).instance) {
1499
+ delete (this._element as any).instance;
1500
+ }
1501
+
1502
+ // --- 7. (Optional) Clear localStorage state ---
1503
+ // Uncomment the following line if you want to clear state on dispose:
1504
+ // this._deleteState();
1505
+ }
1497
1506
 
1498
1507
  private _debounce(func: Function, wait: number) {
1499
1508
  let timeout: number | undefined;
@@ -1770,9 +1779,9 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1770
1779
  */
1771
1780
 
1772
1781
  export function initAllDataTables(): void {
1773
- if (typeof document !== 'undefined') {
1774
- KTDataTable.createInstances();
1775
- // Optionally assign to window for legacy support
1776
- window.KTDataTable = KTDataTable;
1777
- }
1782
+ if (typeof document !== 'undefined') {
1783
+ KTDataTable.createInstances();
1784
+ // Optionally assign to window for legacy support
1785
+ window.KTDataTable = KTDataTable;
1786
+ }
1778
1787
  }
@@ -26,6 +26,7 @@ export class KTImageInput extends KTComponent implements KTImageInputInterface {
26
26
  protected _previewElement: HTMLElement;
27
27
  protected _previewUrl: string = '';
28
28
  protected _lastMode: string;
29
+ protected _selectedFile: File | null = null;
29
30
 
30
31
  constructor(
31
32
  element: HTMLElement,
@@ -87,6 +88,7 @@ export class KTImageInput extends KTComponent implements KTImageInputInterface {
87
88
  };
88
89
 
89
90
  reader.readAsDataURL(this._inputElement.files[0]);
91
+ this._selectedFile = this._inputElement.files[0];
90
92
  this._inputElement.value = '';
91
93
  this._hiddenElement.value = '';
92
94
  this._lastMode = 'new';
@@ -125,6 +127,7 @@ export class KTImageInput extends KTComponent implements KTImageInputInterface {
125
127
 
126
128
  this._inputElement.value = '';
127
129
  this._hiddenElement.value = '';
130
+ this._selectedFile = null;
128
131
 
129
132
  this._lastMode = 'saved';
130
133
  } else if (this._lastMode == 'saved') {
@@ -138,6 +141,7 @@ export class KTImageInput extends KTComponent implements KTImageInputInterface {
138
141
 
139
142
  this._hiddenElement.value = '1';
140
143
  this._inputElement.value = '';
144
+ this._selectedFile = null;
141
145
 
142
146
  this._lastMode = 'placeholder';
143
147
  } else if (this._lastMode == 'placeholder') {
@@ -154,6 +158,7 @@ export class KTImageInput extends KTComponent implements KTImageInputInterface {
154
158
 
155
159
  this._inputElement.value = '';
156
160
  this._hiddenElement.value = '';
161
+ this._selectedFile = null;
157
162
 
158
163
  this._lastMode = 'saved';
159
164
  }
@@ -187,11 +192,11 @@ export class KTImageInput extends KTComponent implements KTImageInputInterface {
187
192
  }
188
193
 
189
194
  public isEmpty(): boolean {
190
- return this._inputElement.value.length === 0;
195
+ return this._selectedFile === null;
191
196
  }
192
197
 
193
198
  public isChanged(): boolean {
194
- return this._inputElement.value.length > 0;
199
+ return this._selectedFile !== null;
195
200
  }
196
201
 
197
202
  public remove(): void {
@@ -210,6 +215,10 @@ export class KTImageInput extends KTComponent implements KTImageInputInterface {
210
215
  return this._getPreviewUrl();
211
216
  }
212
217
 
218
+ public getSelectedFile(): File | null {
219
+ return this._selectedFile;
220
+ }
221
+
213
222
  public static getInstance(element: HTMLElement): KTImageInput {
214
223
  if (!element) return null;
215
224
 
@@ -9,4 +9,5 @@ export interface KTImageInputConfigInterface {
9
9
 
10
10
  export interface KTImageInputInterface {
11
11
  remove(): void;
12
+ getSelectedFile(): File | null;
12
13
  }
@@ -7,7 +7,7 @@
7
7
  /* Base input group styles */
8
8
  .kt-input-group {
9
9
  @apply flex items-stretch relative;
10
-
10
+
11
11
  .kt-input {
12
12
  @apply grow z-1;
13
13
  }
@@ -9,7 +9,7 @@
9
9
  .kt-input {
10
10
  @apply outline-0 block w-full bg-background border border-input shadow-xs shadow-[rgba(0,0,0,0.05)] transition-[color,box-shadow] text-foreground placeholder:text-muted-foreground;
11
11
  @apply focus-visible:ring-ring/30 focus-visible:border-ring focus-visible:outline-none focus-visible:ring-[3px];
12
- @apply disabled:cursor-not-allowed disabled:opacity-60;
12
+ @apply disabled:cursor-not-allowed disabled:opacity-60;
13
13
  @apply [&[readonly]]:bg-muted/80 [&[readonly]]:cursor-not-allowed [&[readonly]]:text-secondary-foreground/80;
14
14
  @apply file:h-full [&[type=file]]:py-0;
15
15
  @apply file:border-solid file:border-input file:bg-transparent file:font-medium file:not-italic file:text-foreground file:p-0 file:border-0 file:border-e;
@@ -7,7 +7,7 @@
7
7
  :root {
8
8
  --kt-scrollable-scrollbar-size: 5px;
9
9
  --kt-scrollable-thumb-color: var(--color-accent);
10
- }
10
+ }
11
11
 
12
12
  .kt-scrollable::-webkit-scrollbar {
13
13
  width: var(--kt-scrollable-scrollbar-size);
@@ -21,10 +21,10 @@
21
21
  .kt-scrollable::-webkit-scrollbar-thumb {
22
22
  background: var(--kt-scrollable-thumb-color);
23
23
  border-radius: var(--kt-scrollable-scrollbar-size);
24
- }
24
+ }
25
25
 
26
26
  /* Firefox */
27
- @-moz-document url-prefix() {
27
+ @-moz-document url-prefix() {
28
28
  .kt-scrollable {
29
29
  scrollbar-width: thin;
30
30
  scrollbar-color: var(--kt-scrollable-thumb-color) transparent;
@@ -26,9 +26,15 @@ export class KTSelectCombobox {
26
26
 
27
27
  const displayElement = select.getDisplayElement(); // KTSelect's main display element for combobox
28
28
 
29
- this._searchInputElement = displayElement.querySelector('input[data-kt-select-search]');
30
- this._clearButtonElement = displayElement.querySelector('[data-kt-select-clear-button]');
31
- this._valuesContainerElement = displayElement.querySelector('[data-kt-select-combobox-values]');
29
+ this._searchInputElement = displayElement.querySelector(
30
+ 'input[data-kt-select-search]',
31
+ );
32
+ this._clearButtonElement = displayElement.querySelector(
33
+ '[data-kt-select-clear-button]',
34
+ );
35
+ this._valuesContainerElement = displayElement.querySelector(
36
+ '[data-kt-select-combobox-values]',
37
+ );
32
38
 
33
39
  this._boundInputHandler = this._handleComboboxInput.bind(this);
34
40
  this._boundClearHandler = this._handleClearButtonClick.bind(this);
@@ -42,7 +48,7 @@ export class KTSelectCombobox {
42
48
  this.updateDisplay(this._select.getSelectedOptions());
43
49
  } else {
44
50
  // For tags or displayTemplate, the input should be clear for typing.
45
- this._searchInputElement.value = '';
51
+ this._searchInputElement.value = '';
46
52
  }
47
53
  this._toggleClearButtonVisibility(this._searchInputElement.value);
48
54
  // this._select.showAllOptions(); // showAllOptions might be too broad, filtering is managed by typing.
@@ -56,11 +62,18 @@ export class KTSelectCombobox {
56
62
  */
57
63
  private _attachEventListeners(): void {
58
64
  this._removeEventListeners();
59
- if (this._searchInputElement) { // Ensure element exists
60
- this._searchInputElement.addEventListener('input', this._boundInputHandler);
65
+ if (this._searchInputElement) {
66
+ // Ensure element exists
67
+ this._searchInputElement.addEventListener(
68
+ 'input',
69
+ this._boundInputHandler,
70
+ );
61
71
  }
62
72
  if (this._clearButtonElement) {
63
- this._clearButtonElement.addEventListener('click', this._boundClearHandler);
73
+ this._clearButtonElement.addEventListener(
74
+ 'click',
75
+ this._boundClearHandler,
76
+ );
64
77
  }
65
78
  }
66
79
 
@@ -69,10 +82,16 @@ export class KTSelectCombobox {
69
82
  */
70
83
  private _removeEventListeners(): void {
71
84
  if (this._searchInputElement) {
72
- this._searchInputElement.removeEventListener('input', this._boundInputHandler);
85
+ this._searchInputElement.removeEventListener(
86
+ 'input',
87
+ this._boundInputHandler,
88
+ );
73
89
  }
74
90
  if (this._clearButtonElement) {
75
- this._clearButtonElement.removeEventListener('click', this._boundClearHandler);
91
+ this._clearButtonElement.removeEventListener(
92
+ 'click',
93
+ this._boundClearHandler,
94
+ );
76
95
  }
77
96
  }
78
97
 
@@ -85,7 +104,8 @@ export class KTSelectCombobox {
85
104
 
86
105
  this._toggleClearButtonVisibility(query);
87
106
 
88
- if (!(this._select as any).isDropdownOpen()) { // Use public getter
107
+ if (!(this._select as any).isDropdownOpen()) {
108
+ // Use public getter
89
109
  this._select.openDropdown();
90
110
  }
91
111
  // For single select without displayTemplate, if user types, they are essentially clearing the previous selection text
@@ -127,7 +147,11 @@ export class KTSelectCombobox {
127
147
  if (!this._clearButtonElement) return;
128
148
  const hasSelectedItems = this._select.getSelectedOptions().length > 0;
129
149
 
130
- if (inputValue.length > 0 || (hasSelectedItems && (this._config.multiple || this._config.displayTemplate))) {
150
+ if (
151
+ inputValue.length > 0 ||
152
+ (hasSelectedItems &&
153
+ (this._config.multiple || this._config.displayTemplate))
154
+ ) {
131
155
  this._clearButtonElement.classList.remove('hidden');
132
156
  } else {
133
157
  this._clearButtonElement.classList.add('hidden');
@@ -138,7 +162,9 @@ export class KTSelectCombobox {
138
162
  * Filter options for combobox based on input query
139
163
  */
140
164
  private _filterOptionsForCombobox(query: string): void {
141
- const options = Array.from(this._select.getOptionsElement()) as HTMLElement[];
165
+ const options = Array.from(
166
+ this._select.getOptionsElement(),
167
+ ) as HTMLElement[];
142
168
  const config = this._select.getConfig();
143
169
  const dropdownElement = this._select.getDropdownElement();
144
170
  filterOptions(options, query, config, dropdownElement);
@@ -160,41 +186,65 @@ export class KTSelectCombobox {
160
186
  this._valuesContainerElement.innerHTML = '';
161
187
  }
162
188
 
163
- if (this._config.tags && this._valuesContainerElement) { // Combobox + Tags
164
- selectedOptions.forEach(value => {
189
+ if (this._config.tags && this._valuesContainerElement) {
190
+ // Combobox + Tags
191
+ selectedOptions.forEach((value) => {
165
192
  // Ensure value is properly escaped for querySelector
166
- const optionElement = this._select.getElement().querySelector(`option[value="${CSS.escape(value)}"]`) as HTMLOptionElement;
193
+ const optionElement = this._select
194
+ .getElement()
195
+ .querySelector(
196
+ `option[value="${CSS.escape(value)}"]`,
197
+ ) as HTMLOptionElement;
167
198
  if (optionElement) {
168
199
  const tagElement = defaultTemplates.tag(optionElement, this._config);
169
200
  this._valuesContainerElement.appendChild(tagElement);
170
201
  }
171
202
  });
172
203
  this._searchInputElement.value = ''; // Input field is for typing new searches
173
- this._searchInputElement.placeholder = selectedOptions.length > 0 ? '' : (this._config.placeholder || 'Select...');
174
-
175
- } else if (this._config.displayTemplate && this._valuesContainerElement) { // Combobox + DisplayTemplate (no tags)
176
- this._valuesContainerElement.innerHTML = this._select.renderDisplayTemplateForSelected(selectedOptions);
204
+ this._searchInputElement.placeholder =
205
+ selectedOptions.length > 0
206
+ ? ''
207
+ : this._config.placeholder || 'Select...';
208
+ } else if (this._config.displayTemplate && this._valuesContainerElement) {
209
+ // Combobox + DisplayTemplate (no tags)
210
+ this._valuesContainerElement.innerHTML =
211
+ this._select.renderDisplayTemplateForSelected(selectedOptions);
177
212
  this._searchInputElement.value = ''; // Input field is for typing new searches
178
- this._searchInputElement.placeholder = selectedOptions.length > 0 ? '' : (this._config.placeholder || 'Select...');
179
-
180
- } else if (this._config.multiple && this._valuesContainerElement) { // Combobox + Multiple (no tags, no display template)
213
+ this._searchInputElement.placeholder =
214
+ selectedOptions.length > 0
215
+ ? ''
216
+ : this._config.placeholder || 'Select...';
217
+ } else if (this._config.multiple && this._valuesContainerElement) {
218
+ // Combobox + Multiple (no tags, no display template)
181
219
  // For simplicity, join text. A proper tag implementation would be more complex here.
182
- this._valuesContainerElement.innerHTML = selectedOptions.map(value => {
183
- const optionEl = this._select.getElement().querySelector(`option[value="${CSS.escape(value)}"]`);
184
- return optionEl ? optionEl.textContent : '';
185
- }).join(', '); // Basic comma separation
220
+ this._valuesContainerElement.innerHTML = selectedOptions
221
+ .map((value) => {
222
+ const optionEl = this._select
223
+ .getElement()
224
+ .querySelector(`option[value="${CSS.escape(value)}"]`);
225
+ return optionEl ? optionEl.textContent : '';
226
+ })
227
+ .join(', '); // Basic comma separation
186
228
  this._searchInputElement.value = '';
187
- this._searchInputElement.placeholder = selectedOptions.length > 0 ? '' : (this._config.placeholder || 'Select...');
188
-
189
- } else if (!this._config.multiple && selectedOptions.length > 0) { // Single select combobox: display selected option's text in the input
229
+ this._searchInputElement.placeholder =
230
+ selectedOptions.length > 0
231
+ ? ''
232
+ : this._config.placeholder || 'Select...';
233
+ } else if (!this._config.multiple && selectedOptions.length > 0) {
234
+ // Single select combobox: display selected option's text in the input
190
235
  const selectedValue = selectedOptions[0];
191
- const optionElement = this._select.getElement().querySelector(`option[value="${CSS.escape(selectedValue)}"]`);
192
- this._searchInputElement.value = optionElement ? optionElement.textContent || '' : '';
236
+ const optionElement = this._select
237
+ .getElement()
238
+ .querySelector(`option[value="${CSS.escape(selectedValue)}"]`);
239
+ this._searchInputElement.value = optionElement
240
+ ? optionElement.textContent || ''
241
+ : '';
193
242
  // placeholder is implicitly handled by input value for single select
194
-
195
- } else { // No selection or not fitting above categories (e.g. single select, no items)
243
+ } else {
244
+ // No selection or not fitting above categories (e.g. single select, no items)
196
245
  this._searchInputElement.value = '';
197
- this._searchInputElement.placeholder = this._config.placeholder || 'Select...';
246
+ this._searchInputElement.placeholder =
247
+ this._config.placeholder || 'Select...';
198
248
  // _valuesContainerElement is already cleared if it exists
199
249
  }
200
250
  this._toggleClearButtonVisibility(this._searchInputElement.value);
@@ -106,9 +106,7 @@ export class KTSelectDropdown extends KTComponent {
106
106
 
107
107
  if (this._config.disabled) {
108
108
  if (this._config.debug)
109
- console.log(
110
- 'KTSelectDropdown._handleToggleClick: select is disabled',
111
- );
109
+ console.log('KTSelectDropdown._handleToggleClick: select is disabled');
112
110
  return;
113
111
  }
114
112
 
@@ -251,9 +249,7 @@ export class KTSelectDropdown extends KTComponent {
251
249
  public open(): void {
252
250
  if (this._config.disabled) {
253
251
  if (this._config.debug)
254
- console.log(
255
- 'KTSelectDropdown.open: select is disabled, not opening',
256
- );
252
+ console.log('KTSelectDropdown.open: select is disabled, not opening');
257
253
  return;
258
254
  }
259
255
  if (this._isOpen || this._isTransitioning) return;
@@ -279,17 +275,26 @@ export class KTSelectDropdown extends KTComponent {
279
275
  }
280
276
 
281
277
  // Consider the dropdown's current z-index if it's already set and higher
282
- const currentDropdownZIndexStr = KTDom.getCssProp(this._dropdownElement, 'z-index');
278
+ const currentDropdownZIndexStr = KTDom.getCssProp(
279
+ this._dropdownElement,
280
+ 'z-index',
281
+ );
283
282
  if (currentDropdownZIndexStr && currentDropdownZIndexStr !== 'auto') {
284
283
  const currentDropdownZIndex = parseInt(currentDropdownZIndexStr);
285
- if (!isNaN(currentDropdownZIndex) && currentDropdownZIndex > (zIndexToApply || 0)) {
284
+ if (
285
+ !isNaN(currentDropdownZIndex) &&
286
+ currentDropdownZIndex > (zIndexToApply || 0)
287
+ ) {
286
288
  zIndexToApply = currentDropdownZIndex;
287
289
  }
288
290
  }
289
291
 
290
292
  // Ensure dropdown is above elements within its original toggle's parent context
291
293
  const toggleParentContextZindex = KTDom.getHighestZindex(this._element); // _element is the select wrapper
292
- if (toggleParentContextZindex !== null && toggleParentContextZindex >= (zIndexToApply || 0)) {
294
+ if (
295
+ toggleParentContextZindex !== null &&
296
+ toggleParentContextZindex >= (zIndexToApply || 0)
297
+ ) {
293
298
  zIndexToApply = toggleParentContextZindex + 1;
294
299
  }
295
300
 
@@ -379,7 +384,9 @@ export class KTSelectDropdown extends KTComponent {
379
384
 
380
385
  KTDom.transitionEnd(this._dropdownElement, completeTransition);
381
386
 
382
- if (KTDom.getCssProp(this._dropdownElement, 'transition-duration') === '0s') {
387
+ if (
388
+ KTDom.getCssProp(this._dropdownElement, 'transition-duration') === '0s'
389
+ ) {
383
390
  completeTransition();
384
391
  }
385
392
  }
@@ -422,7 +429,9 @@ export class KTSelectDropdown extends KTComponent {
422
429
  private _resolveDropdownContainer(): HTMLElement | null {
423
430
  const containerSelector = this._config.dropdownContainer;
424
431
  if (containerSelector && containerSelector !== 'body') {
425
- const containerElement = document.querySelector(containerSelector) as HTMLElement | null;
432
+ const containerElement = document.querySelector(
433
+ containerSelector,
434
+ ) as HTMLElement | null;
426
435
  if (!containerElement && this._config.debug) {
427
436
  console.warn(
428
437
  `KTSelectDropdown: dropdownContainer selector "${containerSelector}" not found. Dropdown will remain in its default position.`,
@@ -9,5 +9,10 @@ export { KTSelectCombobox } from './combobox';
9
9
  export { KTSelectSearch } from './search';
10
10
  export { KTSelectTags } from './tags';
11
11
  export { KTSelectDropdown } from './dropdown';
12
- export { filterOptions, FocusManager, EventManager, TypeToSearchBuffer } from './utils';
12
+ export {
13
+ filterOptions,
14
+ FocusManager,
15
+ EventManager,
16
+ TypeToSearchBuffer,
17
+ } from './utils';
13
18
  export { KTSelectConfigInterface, KTSelectOption } from './config';
@@ -4,9 +4,7 @@
4
4
  */
5
5
 
6
6
  import KTComponent from '../component';
7
- import {
8
- KTSelectConfigInterface,
9
- } from './config';
7
+ import { KTSelectConfigInterface } from './config';
10
8
  import { defaultTemplates } from './templates';
11
9
 
12
10
  export class KTSelectOption extends KTComponent {
@@ -15,7 +13,7 @@ export class KTSelectOption extends KTComponent {
15
13
  protected override readonly _config: KTSelectConfigInterface; // Holds option-specific data from data-kt-*
16
14
  private _globalConfig: KTSelectConfigInterface; // Main select's config
17
15
 
18
- constructor(element: HTMLElement, config?: KTSelectConfigInterface,) {
16
+ constructor(element: HTMLElement, config?: KTSelectConfigInterface) {
19
17
  super();
20
18
 
21
19
  // Always initialize a new option instance
@@ -30,13 +28,16 @@ export class KTSelectOption extends KTComponent {
30
28
  // Ensure optionsConfig is initialized
31
29
  if (this._globalConfig) {
32
30
  this._globalConfig.optionsConfig = this._globalConfig.optionsConfig || {};
33
- this._globalConfig.optionsConfig[(element as HTMLInputElement).value] = this._config;
31
+ this._globalConfig.optionsConfig[(element as HTMLInputElement).value] =
32
+ this._config;
34
33
  // console.log('[KTSelectOption] Populating _globalConfig.optionsConfig for value', (element as HTMLInputElement).value, 'with:', JSON.parse(JSON.stringify(this._config)));
35
34
  // console.log('[KTSelectOption] _globalConfig.optionsConfig is now:', JSON.parse(JSON.stringify(this._globalConfig.optionsConfig)));
36
35
  } else {
37
36
  // Handle case where _globalConfig might be undefined, though constructor expects it.
38
37
  // This might indicate a need to ensure config is always passed or has a default.
39
- console.warn('KTSelectOption: _globalConfig is undefined during constructor.');
38
+ console.warn(
39
+ 'KTSelectOption: _globalConfig is undefined during constructor.',
40
+ );
40
41
  }
41
42
 
42
43
  // Don't store in KTData to avoid Singleton pattern issues