@keenthemes/ktui 1.0.10 → 1.0.12

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 (139) hide show
  1. package/README.md +2 -2
  2. package/dist/ktui.js +1283 -1100
  3. package/dist/ktui.min.js +1 -1
  4. package/dist/ktui.min.js.map +1 -1
  5. package/examples/select/basic-usage.html +43 -0
  6. package/examples/select/combobox-icons.html +58 -0
  7. package/examples/select/combobox.html +46 -0
  8. package/examples/select/description.html +69 -0
  9. package/examples/select/disable-option.html +43 -0
  10. package/examples/select/disable-select.html +34 -0
  11. package/examples/select/icon-description.html +56 -0
  12. package/examples/select/icon-multiple.html +58 -0
  13. package/examples/select/icon.html +58 -0
  14. package/examples/select/max-selection.html +39 -0
  15. package/examples/select/modal.html +70 -0
  16. package/examples/select/multiple.html +42 -0
  17. package/examples/select/placeholder.html +43 -0
  18. package/examples/select/remote-data.html +32 -0
  19. package/examples/select/search.html +49 -0
  20. package/examples/select/tags-icons.html +58 -0
  21. package/examples/select/tags-selected.html +59 -0
  22. package/examples/select/tags.html +58 -0
  23. package/examples/select/template-customization.html +65 -0
  24. package/examples/select/test.html +94 -0
  25. package/examples/toast/example.html +427 -0
  26. package/lib/cjs/components/component.js +1 -1
  27. package/lib/cjs/components/component.js.map +1 -1
  28. package/lib/cjs/components/datatable/datatable.js +22 -6
  29. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  30. package/lib/cjs/components/modal/modal.js +0 -4
  31. package/lib/cjs/components/modal/modal.js.map +1 -1
  32. package/lib/cjs/components/select/combobox.js +38 -120
  33. package/lib/cjs/components/select/combobox.js.map +1 -1
  34. package/lib/cjs/components/select/config.js +4 -16
  35. package/lib/cjs/components/select/config.js.map +1 -1
  36. package/lib/cjs/components/select/dropdown.js +10 -49
  37. package/lib/cjs/components/select/dropdown.js.map +1 -1
  38. package/lib/cjs/components/select/index.js +2 -1
  39. package/lib/cjs/components/select/index.js.map +1 -1
  40. package/lib/cjs/components/select/option.js +21 -4
  41. package/lib/cjs/components/select/option.js.map +1 -1
  42. package/lib/cjs/components/select/remote.js +1 -37
  43. package/lib/cjs/components/select/remote.js.map +1 -1
  44. package/lib/cjs/components/select/search.js +11 -41
  45. package/lib/cjs/components/select/search.js.map +1 -1
  46. package/lib/cjs/components/select/select.js +213 -326
  47. package/lib/cjs/components/select/select.js.map +1 -1
  48. package/lib/cjs/components/select/tags.js +39 -31
  49. package/lib/cjs/components/select/tags.js.map +1 -1
  50. package/lib/cjs/components/select/templates.js +120 -179
  51. package/lib/cjs/components/select/templates.js.map +1 -1
  52. package/lib/cjs/components/select/types.js +0 -12
  53. package/lib/cjs/components/select/types.js.map +1 -1
  54. package/lib/cjs/components/select/utils.js +204 -257
  55. package/lib/cjs/components/select/utils.js.map +1 -1
  56. package/lib/cjs/components/toast/index.js +10 -0
  57. package/lib/cjs/components/toast/index.js.map +1 -0
  58. package/lib/cjs/components/toast/toast.js +543 -0
  59. package/lib/cjs/components/toast/toast.js.map +1 -0
  60. package/lib/cjs/components/toast/types.js +7 -0
  61. package/lib/cjs/components/toast/types.js.map +1 -0
  62. package/lib/cjs/helpers/dom.js +24 -0
  63. package/lib/cjs/helpers/dom.js.map +1 -1
  64. package/lib/cjs/index.js +5 -1
  65. package/lib/cjs/index.js.map +1 -1
  66. package/lib/esm/components/component.js +1 -1
  67. package/lib/esm/components/component.js.map +1 -1
  68. package/lib/esm/components/datatable/datatable.js +22 -6
  69. package/lib/esm/components/datatable/datatable.js.map +1 -1
  70. package/lib/esm/components/modal/modal.js +0 -4
  71. package/lib/esm/components/modal/modal.js.map +1 -1
  72. package/lib/esm/components/select/combobox.js +39 -121
  73. package/lib/esm/components/select/combobox.js.map +1 -1
  74. package/lib/esm/components/select/config.js +3 -15
  75. package/lib/esm/components/select/config.js.map +1 -1
  76. package/lib/esm/components/select/dropdown.js +10 -49
  77. package/lib/esm/components/select/dropdown.js.map +1 -1
  78. package/lib/esm/components/select/index.js +1 -1
  79. package/lib/esm/components/select/index.js.map +1 -1
  80. package/lib/esm/components/select/option.js +21 -4
  81. package/lib/esm/components/select/option.js.map +1 -1
  82. package/lib/esm/components/select/remote.js +1 -37
  83. package/lib/esm/components/select/remote.js.map +1 -1
  84. package/lib/esm/components/select/search.js +12 -42
  85. package/lib/esm/components/select/search.js.map +1 -1
  86. package/lib/esm/components/select/select.js +214 -327
  87. package/lib/esm/components/select/select.js.map +1 -1
  88. package/lib/esm/components/select/tags.js +39 -31
  89. package/lib/esm/components/select/tags.js.map +1 -1
  90. package/lib/esm/components/select/templates.js +119 -178
  91. package/lib/esm/components/select/templates.js.map +1 -1
  92. package/lib/esm/components/select/types.js +1 -11
  93. package/lib/esm/components/select/types.js.map +1 -1
  94. package/lib/esm/components/select/utils.js +201 -255
  95. package/lib/esm/components/select/utils.js.map +1 -1
  96. package/lib/esm/components/toast/index.js +6 -0
  97. package/lib/esm/components/toast/index.js.map +1 -0
  98. package/lib/esm/components/toast/toast.js +540 -0
  99. package/lib/esm/components/toast/toast.js.map +1 -0
  100. package/lib/esm/components/toast/types.js +6 -0
  101. package/lib/esm/components/toast/types.js.map +1 -0
  102. package/lib/esm/helpers/dom.js +24 -0
  103. package/lib/esm/helpers/dom.js.map +1 -1
  104. package/lib/esm/index.js +3 -0
  105. package/lib/esm/index.js.map +1 -1
  106. package/package.json +8 -6
  107. package/src/components/alert/alert.css +20 -2
  108. package/src/components/badge/badge.css +5 -0
  109. package/src/components/component.ts +4 -0
  110. package/src/components/datatable/datatable.ts +24 -16
  111. package/src/components/drawer/drawer.css +1 -1
  112. package/src/components/input/input.css +3 -1
  113. package/src/components/link/link.css +2 -2
  114. package/src/components/modal/modal.css +18 -2
  115. package/src/components/modal/modal.ts +0 -5
  116. package/src/components/select/combobox.ts +42 -149
  117. package/src/components/select/config.ts +38 -33
  118. package/src/components/select/dropdown.ts +8 -55
  119. package/src/components/select/index.ts +1 -1
  120. package/src/components/select/option.ts +28 -7
  121. package/src/components/select/remote.ts +2 -42
  122. package/src/components/select/search.ts +14 -54
  123. package/src/components/select/select.css +49 -0
  124. package/src/components/select/select.ts +231 -437
  125. package/src/components/select/tags.ts +40 -37
  126. package/src/components/select/templates.ts +166 -303
  127. package/src/components/select/types.ts +0 -10
  128. package/src/components/select/utils.ts +214 -304
  129. package/src/components/table/table.css +1 -1
  130. package/src/components/textarea/textarea.css +2 -1
  131. package/src/components/toast/index.ts +7 -0
  132. package/src/components/toast/toast.css +60 -0
  133. package/src/components/toast/toast.ts +605 -0
  134. package/src/components/toast/types.ts +169 -0
  135. package/src/helpers/dom.ts +30 -0
  136. package/src/index.ts +4 -0
  137. package/styles/main.css +3 -0
  138. package/styles/vars.css +138 -0
  139. package/styles.css +1 -0
@@ -47,9 +47,8 @@ import { KTSelectSearch } from './search';
47
47
  import { defaultTemplates } from './templates';
48
48
  import { KTSelectCombobox } from './combobox';
49
49
  import { KTSelectDropdown } from './dropdown';
50
- import { handleDropdownKeyNavigation, filterOptions, FocusManager, EventManager, } from './utils';
50
+ import { FocusManager, EventManager, renderTemplateString, TypeToSearchBuffer, } from './utils';
51
51
  import { KTSelectTags } from './tags';
52
- import { SelectMode } from './types';
53
52
  var KTSelect = /** @class */ (function (_super) {
54
53
  __extends(KTSelect, _super);
55
54
  /**
@@ -66,6 +65,7 @@ var KTSelect = /** @class */ (function (_super) {
66
65
  _this._tagsModule = null;
67
66
  _this._dropdownModule = null;
68
67
  _this._loadMoreIndicator = null;
68
+ _this._typeToSearchBuffer = new TypeToSearchBuffer();
69
69
  // Search debounce timeout
70
70
  _this._searchDebounceTimeout = null;
71
71
  // Store original options HTML for restoring after search
@@ -150,11 +150,6 @@ var KTSelect = /** @class */ (function (_super) {
150
150
  // Keep only the empty/placeholder option and remove the rest
151
151
  var options = Array.from(this._element.querySelectorAll('option:not([value=""])'));
152
152
  options.forEach(function (option) { return option.remove(); });
153
- // Ensure we have at least an empty option
154
- if (this._element.querySelectorAll('option').length === 0) {
155
- var emptyOption = defaultTemplates.emptyOption(__assign(__assign({}, this._config), { placeholder: this._config.placeholder }));
156
- this._element.appendChild(emptyOption);
157
- }
158
153
  };
159
154
  /**
160
155
  * Helper to show a dropdown message (error, loading, noResults)
@@ -162,7 +157,7 @@ var KTSelect = /** @class */ (function (_super) {
162
157
  KTSelect.prototype._showDropdownMessage = function (type, message) {
163
158
  if (!this._dropdownContentElement)
164
159
  return;
165
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
160
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
166
161
  if (!optionsContainer)
167
162
  return;
168
163
  switch (type) {
@@ -172,9 +167,9 @@ var KTSelect = /** @class */ (function (_super) {
172
167
  case 'loading':
173
168
  optionsContainer.innerHTML = defaultTemplates.loading(this._config, message || 'Loading...').outerHTML;
174
169
  break;
175
- case 'noResults':
170
+ case 'empty':
176
171
  optionsContainer.innerHTML = '';
177
- optionsContainer.appendChild(defaultTemplates.noResults(this._config));
172
+ optionsContainer.appendChild(defaultTemplates.empty(this._config));
178
173
  break;
179
174
  }
180
175
  };
@@ -193,14 +188,6 @@ var KTSelect = /** @class */ (function (_super) {
193
188
  * @param message Error message
194
189
  */
195
190
  KTSelect.prototype._renderErrorState = function (message) {
196
- // Create error option if the select is empty
197
- if (this._element.querySelectorAll('option').length <= 1) {
198
- var loadingOptions = this._element.querySelectorAll('option[disabled]:not([value])');
199
- loadingOptions.forEach(function (option) { return option.remove(); });
200
- // Use template function for error option instead of hardcoded element
201
- var errorOption = defaultTemplates.errorOption(__assign(__assign({}, this._config), { errorMessage: message }));
202
- this._element.appendChild(errorOption);
203
- }
204
191
  // If dropdown is already created, show error message there
205
192
  this._showDropdownMessage('error', message);
206
193
  if (!this._wrapperElement) {
@@ -223,7 +210,7 @@ var KTSelect = /** @class */ (function (_super) {
223
210
  // Create load more button using template
224
211
  this._loadMoreIndicator = defaultTemplates.loadMore(this._config);
225
212
  // Add to dropdown
226
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
213
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
227
214
  if (optionsContainer) {
228
215
  optionsContainer.appendChild(this._loadMoreIndicator);
229
216
  }
@@ -293,42 +280,26 @@ var KTSelect = /** @class */ (function (_super) {
293
280
  * @param newItems New items to add to the dropdown
294
281
  */
295
282
  KTSelect.prototype._updateOptionsInDropdown = function (newItems) {
296
- var _this = this;
297
283
  if (!this._dropdownContentElement || !newItems.length)
298
284
  return;
299
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
285
+ var optionsContainer = this._dropdownContentElement.querySelector("[data-kt-select-options]");
300
286
  if (!optionsContainer)
301
287
  return;
302
288
  // Get the load more button
303
- var loadMoreButton = optionsContainer.querySelector('[data-kt-select-load-more]');
289
+ var loadMoreButton = optionsContainer.querySelector("[data-kt-select-load-more]");
304
290
  // Process each new item
305
291
  newItems.forEach(function (item) {
306
292
  // Create option for the original select
307
- var selectOption = defaultTemplates.emptyOption(__assign(__assign({}, _this._config), { placeholder: item.title || 'Unnamed option' }));
293
+ var selectOption = document.createElement('option');
308
294
  selectOption.value = item.id || '';
309
- // Add description and icon attributes if available and valid
310
- if (item.description &&
311
- item.description !== 'null' &&
312
- item.description !== 'undefined') {
313
- selectOption.setAttribute('data-kt-select-option-description', item.description);
314
- }
315
- if (item.icon && item.icon !== 'null' && item.icon !== 'undefined') {
316
- selectOption.setAttribute('data-kt-select-option-icon', item.icon);
317
- }
318
- // Add the option to the original select element
319
- _this._element.appendChild(selectOption);
320
- // Create option element for the dropdown using the KTSelectOption class
321
- // This ensures consistent option rendering
322
- var ktOption = new KTSelectOption(selectOption, _this._config);
323
- var renderedOption = ktOption.render();
324
295
  // Add to dropdown container
325
296
  if (loadMoreButton) {
326
297
  // Insert before the load more button
327
- optionsContainer.insertBefore(renderedOption, loadMoreButton);
298
+ optionsContainer.insertBefore(selectOption, loadMoreButton);
328
299
  }
329
300
  else {
330
301
  // Append to the end
331
- optionsContainer.appendChild(renderedOption);
302
+ optionsContainer.appendChild(selectOption);
332
303
  }
333
304
  });
334
305
  // Update options NodeList to include the new options
@@ -350,7 +321,7 @@ var KTSelect = /** @class */ (function (_super) {
350
321
  this._setupElementReferences();
351
322
  this._initZIndex();
352
323
  // Initialize options
353
- this._initializeOptionsHtml();
324
+ // this._initializeOptionsHtml();
354
325
  this._preSelectOptions(this._element);
355
326
  // Apply disabled state if needed
356
327
  this._applyInitialDisabledState();
@@ -359,11 +330,11 @@ var KTSelect = /** @class */ (function (_super) {
359
330
  this._initializeSearchModule();
360
331
  }
361
332
  // Initialize combobox if enabled
362
- if (this._config.mode === SelectMode.COMBOBOX) {
333
+ if (this._config.combobox) {
363
334
  this._comboboxModule = new KTSelectCombobox(this);
364
335
  }
365
336
  // Initialize tags if enabled
366
- if (this._config.mode === SelectMode.TAGS) {
337
+ if (this._config.tags) {
367
338
  this._tagsModule = new KTSelectTags(this);
368
339
  }
369
340
  // Initialize focus manager after dropdown element is created
@@ -380,31 +351,37 @@ var KTSelect = /** @class */ (function (_super) {
380
351
  /**
381
352
  * Initialize options HTML from data
382
353
  */
383
- KTSelect.prototype._initializeOptionsHtml = function () {
384
- this._generateOptionsHtml(this._element);
385
- };
354
+ // private _initializeOptionsHtml() {
355
+ // this._generateOptionsHtml(this._element);
356
+ // }
386
357
  /**
387
358
  * Creates the HTML structure for the select component
388
359
  */
389
360
  KTSelect.prototype._createHtmlStructure = function () {
361
+ var _a;
390
362
  var _this = this;
391
363
  var options = Array.from(this._element.querySelectorAll('option'));
392
364
  // Create wrapper and display elements
393
- var wrapperElement = defaultTemplates.main(this._config);
365
+ var wrapperElement = defaultTemplates.wrapper(this._config);
394
366
  var displayElement = defaultTemplates.display(this._config);
395
367
  // Add the display element to the wrapper
396
368
  wrapperElement.appendChild(displayElement);
369
+ // Move classes from original select to display element
370
+ if (this._element.classList.length > 0) {
371
+ (_a = displayElement.classList).add.apply(_a, Array.from(this._element.classList));
372
+ this._element.className = '';
373
+ }
397
374
  // Create an empty dropdown first (without options) using template
398
- var dropdownElement = defaultTemplates.dropdownContent(__assign(__assign({}, this._config), { zindex: this._config.dropdownZindex }));
375
+ var dropdownElement = defaultTemplates.dropdown(__assign(__assign({}, this._config), { zindex: this._config.dropdownZindex }));
399
376
  // Add search input if needed
400
- var isCombobox = this._config.mode === SelectMode.COMBOBOX;
401
- var hasSearch = this._config.enableSearch && !isCombobox;
402
- if (hasSearch) {
377
+ if (this._config.enableSearch) {
403
378
  var searchElement = defaultTemplates.search(this._config);
404
379
  dropdownElement.appendChild(searchElement);
405
380
  }
406
381
  // Create options container using template
407
- var optionsContainer = defaultTemplates.optionsContainer(this._config);
382
+ var optionsContainer = defaultTemplates.options(this._config);
383
+ // Clear the options container
384
+ optionsContainer.innerHTML = '';
408
385
  // Add each option directly to the container
409
386
  options.forEach(function (optionElement) {
410
387
  // Skip empty placeholder options (only if BOTH value AND text are empty)
@@ -435,20 +412,17 @@ var KTSelect = /** @class */ (function (_super) {
435
412
  // Get display element
436
413
  this._displayElement = this._wrapperElement.querySelector("[data-kt-select-display]");
437
414
  // Get dropdown content element - this is critical for dropdown functionality
438
- this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown-content]");
415
+ this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown]");
439
416
  if (!this._dropdownContentElement) {
417
+ console.log(this._element);
440
418
  console.error('Dropdown content element not found', this._wrapperElement);
441
419
  }
442
420
  // Get search input element - this is used for the search functionality
443
- // First check if it's in dropdown, then check if it's in display (for combobox)
444
421
  this._searchInputElement = this._dropdownContentElement.querySelector("[data-kt-select-search]");
445
- // If not found in dropdown, check if it's the display element itself (for combobox)
446
- if (!this._searchInputElement &&
447
- this._config.mode === SelectMode.COMBOBOX) {
422
+ // If not found in dropdown, check if it's the display element itself
423
+ if (!this._searchInputElement) {
448
424
  this._searchInputElement = this._displayElement;
449
425
  }
450
- if (this._config.debug)
451
- console.log('Search input found:', this._searchInputElement ? 'Yes' : 'No', 'Mode:', this._config.mode, 'EnableSearch:', this._config.enableSearch);
452
426
  this._valueDisplayElement = this._wrapperElement.querySelector("[data-kt-select-value]");
453
427
  this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
454
428
  };
@@ -458,17 +432,18 @@ var KTSelect = /** @class */ (function (_super) {
458
432
  KTSelect.prototype._attachEventListeners = function () {
459
433
  // Document level event listeners
460
434
  document.addEventListener('click', this._handleDocumentClick.bind(this));
461
- document.addEventListener('keydown', this._handleEscKey.bind(this));
462
435
  // Dropdown option click events
463
436
  this._eventManager.addListener(this._dropdownContentElement, 'click', this._handleDropdownOptionClick.bind(this));
464
437
  // Only attach click handler to display element
465
- this._eventManager.addListener(this._displayElement, 'click', this._handleDropdownClick.bind(this));
466
- // Only attach keyboard navigation to display element if NOT in combobox mode
467
- // This prevents conflicts with the combobox module's keyboard handler
468
- if (this._config.mode !== SelectMode.COMBOBOX) {
469
- if (this._config.debug)
470
- console.log('Attaching keyboard navigation to display element (non-combobox mode)');
471
- this._eventManager.addListener(this._displayElement, 'keydown', this._handleDropdownKeyDown.bind(this));
438
+ // this._eventManager.addListener(
439
+ // this._wrapperElement,
440
+ // 'click',
441
+ // this._handleDropdownClick.bind(this),
442
+ // );
443
+ // Attach centralized keyboard handler
444
+ var keyboardTarget = this._searchInputElement || this._wrapperElement;
445
+ if (keyboardTarget) {
446
+ keyboardTarget.addEventListener('keydown', this._handleKeyboardEvent.bind(this));
472
447
  }
473
448
  };
474
449
  /**
@@ -538,52 +513,12 @@ var KTSelect = /** @class */ (function (_super) {
538
513
  label =
539
514
  extractedLabel !== null ? String(extractedLabel) : 'Unnamed option';
540
515
  }
541
- // Get description - skip if null, undefined, or "null" string
542
- var description = null;
543
- if (item.description !== undefined &&
544
- item.description !== null &&
545
- String(item.description) !== 'null' &&
546
- String(item.description) !== 'undefined') {
547
- description = String(item.description);
548
- }
549
- else if (_this._config.dataFieldDescription) {
550
- var extractedDesc = _this._getValueByKey(item, _this._config.dataFieldDescription);
551
- if (extractedDesc !== null &&
552
- extractedDesc !== undefined &&
553
- String(extractedDesc) !== 'null' &&
554
- String(extractedDesc) !== 'undefined') {
555
- description = String(extractedDesc);
556
- }
557
- }
558
- // Get icon - skip if null, undefined, or "null" string
559
- var icon = null;
560
- if (item.icon !== undefined &&
561
- item.icon !== null &&
562
- String(item.icon) !== 'null' &&
563
- String(item.icon) !== 'undefined') {
564
- icon = String(item.icon);
565
- }
566
- else if (_this._config.dataFieldIcon) {
567
- var extractedIcon = _this._getValueByKey(item, _this._config.dataFieldIcon);
568
- if (extractedIcon !== null &&
569
- extractedIcon !== undefined &&
570
- String(extractedIcon) !== 'null' &&
571
- String(extractedIcon) !== 'undefined') {
572
- icon = String(extractedIcon);
573
- }
574
- }
575
516
  // Log the extracted values for debugging
576
517
  if (_this._config.debug)
577
- console.log("Option: value=".concat(value, ", label=").concat(label, ", desc=").concat(description ? description : 'none', ", icon=").concat(icon ? icon : 'none'));
518
+ console.log("Option: value=".concat(value, ", label=").concat(label));
578
519
  // Set option attributes
579
520
  optionElement.value = value;
580
521
  optionElement.textContent = label || 'Unnamed option';
581
- if (description) {
582
- optionElement.setAttribute('data-kt-select-option-description', description);
583
- }
584
- if (icon) {
585
- optionElement.setAttribute('data-kt-select-option-icon', icon);
586
- }
587
522
  if (item.selected) {
588
523
  optionElement.setAttribute('selected', 'selected');
589
524
  }
@@ -653,8 +588,14 @@ var KTSelect = /** @class */ (function (_super) {
653
588
  */
654
589
  /**
655
590
  * Toggle dropdown visibility
591
+ * @deprecated
656
592
  */
657
593
  KTSelect.prototype.toggleDropdown = function () {
594
+ if (this._config.disabled) {
595
+ if (this._config.debug)
596
+ console.log('toggleDropdown: select is disabled, not opening');
597
+ return;
598
+ }
658
599
  if (this._config.debug)
659
600
  console.log('toggleDropdown called');
660
601
  if (this._dropdownModule) {
@@ -676,6 +617,11 @@ var KTSelect = /** @class */ (function (_super) {
676
617
  */
677
618
  KTSelect.prototype.openDropdown = function () {
678
619
  var _this = this;
620
+ if (this._config.disabled) {
621
+ if (this._config.debug)
622
+ console.log('openDropdown: select is disabled, not opening');
623
+ return;
624
+ }
679
625
  if (this._config.debug)
680
626
  console.log('openDropdown called, dropdownModule exists:', !!this._dropdownModule);
681
627
  if (!this._dropdownModule) {
@@ -781,6 +727,12 @@ var KTSelect = /** @class */ (function (_super) {
781
727
  * Select an option by value
782
728
  */
783
729
  KTSelect.prototype._selectOption = function (value) {
730
+ // Prevent selection if the option is disabled (in dropdown or original select)
731
+ if (this._isOptionDisabled(value)) {
732
+ if (this._config.debug)
733
+ console.log('_selectOption: Option is disabled, ignoring selection');
734
+ return;
735
+ }
784
736
  // Get current selection state
785
737
  var isSelected = this._state.isSelected(value);
786
738
  // Toggle selection in state
@@ -826,104 +778,34 @@ var KTSelect = /** @class */ (function (_super) {
826
778
  * Update selected option display value
827
779
  */
828
780
  KTSelect.prototype.updateSelectedOptionDisplay = function () {
829
- var _this = this;
830
781
  var selectedOptions = this.getSelectedOptions();
831
- if (this._config.renderSelected) {
782
+ // Tag mode: render tags if enabled
783
+ if (this._config.tags && this._tagsModule) {
784
+ this._tagsModule.updateTagsDisplay(selectedOptions);
785
+ return;
786
+ }
787
+ if (typeof this._config.renderSelected === 'function') {
832
788
  // Use the custom renderSelected function if provided
833
- this._updateValueDisplay(this._config.renderSelected(selectedOptions));
789
+ this._valueDisplayElement.innerHTML = this._config.renderSelected(selectedOptions);
834
790
  }
835
791
  else {
836
792
  if (selectedOptions.length === 0) {
837
- if (this._config.mode !== SelectMode.COMBOBOX) {
838
- this._updateValueDisplay(this._config.placeholder); // Use innerHTML for placeholder
839
- }
840
- }
841
- else if (this._config.multiple) {
842
- if (this._config.mode === SelectMode.TAGS) {
843
- // Use the tags module to render selected options as tags
844
- if (this._tagsModule) {
845
- this._tagsModule.updateTagsDisplay(selectedOptions);
846
- }
847
- else {
848
- // Fallback if tags module not initialized for some reason
849
- this._updateValueDisplay(selectedOptions.join(', '));
850
- }
851
- }
852
- else {
853
- // Render as comma-separated values
854
- var displayText = selectedOptions
855
- .map(function (option) { return _this._getOptionInnerHtml(option) || ''; })
856
- .join(', ');
857
- this._updateValueDisplay(displayText);
858
- }
793
+ var placeholder = defaultTemplates.placeholder(this._config);
794
+ this._valueDisplayElement.replaceChildren(placeholder);
859
795
  }
860
796
  else {
861
- var selectedOption = selectedOptions[0];
862
- if (selectedOption) {
863
- var selectedText = this._getOptionInnerHtml(selectedOption);
864
- this._updateValueDisplay(selectedText);
865
- // Update combobox input value if in combobox mode
866
- if (this._config.mode === SelectMode.COMBOBOX &&
867
- this._comboboxModule) {
868
- this._comboboxModule.updateSelectedValue(selectedText);
869
- }
797
+ var content = '';
798
+ if (this._config.displayTemplate) {
799
+ var selectedValues = this.getSelectedOptions();
800
+ content = this.renderDisplayTemplateForSelected(selectedValues);
870
801
  }
871
802
  else {
872
- this._updateValueDisplay(this._config.placeholder);
803
+ // If no displayTemplate is provided, use the default comma-separated list of selected options
804
+ content = this.getSelectedOptionsText();
873
805
  }
806
+ this._valueDisplayElement.innerHTML = content;
874
807
  }
875
808
  }
876
- // Update any debug display boxes if they exist
877
- this._updateDebugDisplays();
878
- };
879
- /**
880
- * Update the value display element
881
- */
882
- KTSelect.prototype._updateValueDisplay = function (value) {
883
- if (this._config.mode === SelectMode.COMBOBOX) {
884
- // For combobox, we only update the hidden value element, not the input
885
- // The combobox module will handle updating the input value
886
- if (!this._comboboxModule) {
887
- this._valueDisplayElement.value = value;
888
- }
889
- }
890
- else {
891
- this._valueDisplayElement.innerHTML = value;
892
- }
893
- };
894
- /**
895
- * Update debug displays if present
896
- */
897
- KTSelect.prototype._updateDebugDisplays = function () {
898
- // Check if we're in a test environment with debug boxes
899
- var selectId = this.getElement().id;
900
- if (selectId) {
901
- var debugElement = document.getElementById("".concat(selectId, "-value"));
902
- if (debugElement) {
903
- var selectedOptions = this.getSelectedOptions();
904
- // Format display based on selection mode
905
- if (this._config.multiple) {
906
- // For multiple selection, show comma-separated list
907
- debugElement.textContent =
908
- selectedOptions.length > 0 ? selectedOptions.join(', ') : 'None';
909
- }
910
- else {
911
- // For single selection, show just the one value
912
- debugElement.textContent =
913
- selectedOptions.length > 0 ? selectedOptions[0] : 'None';
914
- }
915
- }
916
- }
917
- };
918
- /**
919
- * Get option inner HTML content by option value
920
- */
921
- KTSelect.prototype._getOptionInnerHtml = function (optionValue) {
922
- var option = Array.from(this._options).find(function (opt) { return opt.dataset.value === optionValue; });
923
- if (this._config.mode == SelectMode.COMBOBOX) {
924
- return option.textContent;
925
- }
926
- return option.innerHTML; // Get the entire HTML content of the option
927
809
  };
928
810
  /**
929
811
  * Update CSS classes for selected options
@@ -969,17 +851,6 @@ var KTSelect = /** @class */ (function (_super) {
969
851
  this._state.setSelectedOptions([]);
970
852
  this.updateSelectedOptionDisplay();
971
853
  this._updateSelectedOptionClass();
972
- // For combobox, also clear the input value
973
- if (this._config.mode === SelectMode.COMBOBOX) {
974
- if (this._searchInputElement) {
975
- this._searchInputElement.value = '';
976
- }
977
- // If combobox has a clear button, hide it
978
- if (this._comboboxModule) {
979
- // The combobox module will handle hiding the clear button
980
- this._comboboxModule.resetInputValueToSelection();
981
- }
982
- }
983
854
  // Dispatch change event
984
855
  this._dispatchEvent('change');
985
856
  this._fireEvent('change');
@@ -991,49 +862,6 @@ var KTSelect = /** @class */ (function (_super) {
991
862
  var values = Array.from(options).map(function (option) { return option.value; });
992
863
  this._state.setSelectedOptions(values);
993
864
  };
994
- /**
995
- * ========================================================================
996
- * KEYBOARD NAVIGATION
997
- * ========================================================================
998
- */
999
- /**
1000
- * Handle dropdown key down events for keyboard navigation
1001
- * Only used for standard (non-combobox) dropdowns
1002
- */
1003
- KTSelect.prototype._handleDropdownKeyDown = function (event) {
1004
- // Log event for debugging
1005
- if (this._config.debug)
1006
- console.log('Standard dropdown keydown:', event.key);
1007
- // Use the shared handler
1008
- handleDropdownKeyNavigation(event, this, {
1009
- multiple: this._config.multiple,
1010
- closeOnSelect: this._config.closeOnSelect,
1011
- });
1012
- };
1013
- /**
1014
- * Focus next option in dropdown
1015
- */
1016
- KTSelect.prototype._focusNextOption = function () {
1017
- return this._focusManager.focusNext();
1018
- };
1019
- /**
1020
- * Focus previous option in dropdown
1021
- */
1022
- KTSelect.prototype._focusPreviousOption = function () {
1023
- return this._focusManager.focusPrevious();
1024
- };
1025
- /**
1026
- * Apply hover/focus state to focused option
1027
- */
1028
- KTSelect.prototype._hoverFocusedOption = function (option) {
1029
- this._focusManager.applyFocus(option);
1030
- };
1031
- /**
1032
- * Scroll option into view when navigating
1033
- */
1034
- KTSelect.prototype._scrollOptionIntoView = function (option) {
1035
- this._focusManager.scrollIntoView(option);
1036
- };
1037
865
  /**
1038
866
  * Select the currently focused option
1039
867
  */
@@ -1057,44 +885,7 @@ var KTSelect = /** @class */ (function (_super) {
1057
885
  if (selectedValue) {
1058
886
  this._selectOption(selectedValue);
1059
887
  }
1060
- // For combobox mode, update input value AFTER selection to ensure consistency
1061
- if (this._config.mode === SelectMode.COMBOBOX && this._comboboxModule) {
1062
- this._comboboxModule.updateSelectedValue(selectedText);
1063
- // Also directly update the input value for immediate visual feedback
1064
- if (this._searchInputElement) {
1065
- this._searchInputElement.value = selectedText;
1066
- }
1067
- }
1068
- }
1069
- };
1070
- /**
1071
- * ========================================================================
1072
- * COMBOBOX SPECIFIC METHODS
1073
- * ========================================================================
1074
- */
1075
- /**
1076
- * Handle combobox input events
1077
- */
1078
- KTSelect.prototype._handleComboboxInput = function (event) {
1079
- if (this._comboboxModule) {
1080
- return;
1081
- }
1082
- var inputElement = event.target;
1083
- var query = inputElement.value.toLowerCase();
1084
- // If dropdown isn't open, open it when user starts typing
1085
- if (!this._dropdownIsOpen) {
1086
- this.openDropdown();
1087
888
  }
1088
- // Filter options based on input
1089
- this._filterOptionsForCombobox(query);
1090
- };
1091
- /**
1092
- * Filter options for combobox based on input query
1093
- * Uses the shared filterOptions function
1094
- */
1095
- KTSelect.prototype._filterOptionsForCombobox = function (query) {
1096
- var options = Array.from(this._dropdownContentElement.querySelectorAll('[data-kt-select-option]'));
1097
- filterOptions(options, query, this._config, this._dropdownContentElement);
1098
889
  };
1099
890
  /**
1100
891
  * ========================================================================
@@ -1103,6 +894,7 @@ var KTSelect = /** @class */ (function (_super) {
1103
894
  */
1104
895
  /**
1105
896
  * Handle display element click
897
+ * @deprecated
1106
898
  */
1107
899
  KTSelect.prototype._handleDropdownClick = function (event) {
1108
900
  if (this._config.debug)
@@ -1164,14 +956,6 @@ var KTSelect = /** @class */ (function (_super) {
1164
956
  this.closeDropdown();
1165
957
  }
1166
958
  };
1167
- /**
1168
- * Handle escape key press
1169
- */
1170
- KTSelect.prototype._handleEscKey = function (event) {
1171
- if (event.key === 'Escape' && this._dropdownIsOpen) {
1172
- this.closeDropdown();
1173
- }
1174
- };
1175
959
  /**
1176
960
  * ========================================================================
1177
961
  * ACCESSIBILITY METHODS
@@ -1183,18 +967,6 @@ var KTSelect = /** @class */ (function (_super) {
1183
967
  KTSelect.prototype._setAriaAttributes = function () {
1184
968
  this._displayElement.setAttribute('aria-expanded', this._dropdownIsOpen.toString());
1185
969
  };
1186
- /**
1187
- * Handle focus events
1188
- */
1189
- KTSelect.prototype._handleFocus = function () {
1190
- // Implementation pending
1191
- };
1192
- /**
1193
- * Handle blur events
1194
- */
1195
- KTSelect.prototype._handleBlur = function () {
1196
- // Implementation pending
1197
- };
1198
970
  /**
1199
971
  * ========================================================================
1200
972
  * PUBLIC API
@@ -1263,7 +1035,7 @@ var KTSelect = /** @class */ (function (_super) {
1263
1035
  }
1264
1036
  });
1265
1037
  // If search input exists, clear it
1266
- if (this._searchInputElement && this._config.mode !== SelectMode.COMBOBOX) {
1038
+ if (this._searchInputElement) {
1267
1039
  this._searchInputElement.value = '';
1268
1040
  // If we have a search module, clear any search filtering
1269
1041
  if (this._searchModule) {
@@ -1287,6 +1059,12 @@ var KTSelect = /** @class */ (function (_super) {
1287
1059
  * Toggle the selection of an option
1288
1060
  */
1289
1061
  KTSelect.prototype.toggleSelection = function (value) {
1062
+ // Prevent selection if the option is disabled (in dropdown or original select)
1063
+ if (this._isOptionDisabled(value)) {
1064
+ if (this._config.debug)
1065
+ console.log('toggleSelection: Option is disabled, ignoring selection');
1066
+ return;
1067
+ }
1290
1068
  // Get current selection state
1291
1069
  var isSelected = this._state.isSelected(value);
1292
1070
  if (this._config.debug)
@@ -1454,7 +1232,7 @@ var KTSelect = /** @class */ (function (_super) {
1454
1232
  */
1455
1233
  KTSelect.prototype._renderSearchLoadingState = function () {
1456
1234
  if (!this._originalOptionsHtml && this._dropdownContentElement) {
1457
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
1235
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
1458
1236
  if (optionsContainer) {
1459
1237
  this._originalOptionsHtml = optionsContainer.innerHTML;
1460
1238
  }
@@ -1473,36 +1251,26 @@ var KTSelect = /** @class */ (function (_super) {
1473
1251
  * @param items Search result items
1474
1252
  */
1475
1253
  KTSelect.prototype._updateSearchResults = function (items) {
1476
- var _this = this;
1477
1254
  if (!this._dropdownContentElement)
1478
1255
  return;
1479
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
1256
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
1480
1257
  if (!optionsContainer)
1481
1258
  return;
1482
1259
  // Clear current options
1483
1260
  optionsContainer.innerHTML = '';
1484
1261
  if (items.length === 0) {
1485
1262
  // Show no results message using template for consistency and customization
1486
- var noResultsElement = defaultTemplates.noResults(this._config);
1263
+ var noResultsElement = defaultTemplates.empty(this._config);
1487
1264
  optionsContainer.appendChild(noResultsElement);
1488
1265
  return;
1489
1266
  }
1490
1267
  // Process each item individually to create options
1491
1268
  items.forEach(function (item) {
1492
1269
  // Create option for the original select
1493
- var selectOption = defaultTemplates.emptyOption(__assign(__assign({}, _this._config), { placeholder: item.title }));
1270
+ var selectOption = document.createElement('option');
1494
1271
  selectOption.value = item.id;
1495
- if (item.description) {
1496
- selectOption.setAttribute('data-kt-select-option-description', item.description);
1497
- }
1498
- if (item.icon) {
1499
- selectOption.setAttribute('data-kt-select-option-icon', item.icon);
1500
- }
1501
- // Create option element for the dropdown
1502
- var ktOption = new KTSelectOption(selectOption, _this._config);
1503
- var renderedOption = ktOption.render();
1504
1272
  // Add to dropdown container
1505
- optionsContainer.appendChild(renderedOption);
1273
+ optionsContainer.appendChild(selectOption);
1506
1274
  });
1507
1275
  // Add pagination "Load More" button if needed
1508
1276
  if (this._config.pagination && this._remoteModule.hasMorePages()) {
@@ -1511,18 +1279,137 @@ var KTSelect = /** @class */ (function (_super) {
1511
1279
  // Update options NodeList
1512
1280
  this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
1513
1281
  };
1514
- /**
1515
- * Filter options by query
1516
- */
1517
- KTSelect.prototype.filterOptions = function (query) {
1518
- this._filterOptionsForCombobox(query);
1519
- };
1520
1282
  /**
1521
1283
  * Check if dropdown is open
1522
1284
  */
1523
1285
  KTSelect.prototype.isDropdownOpen = function () {
1524
1286
  return this._dropdownIsOpen;
1525
1287
  };
1288
+ KTSelect.prototype.getSelectedOptionsText = function () {
1289
+ var _this = this;
1290
+ var selectedValues = this.getSelectedOptions();
1291
+ var displaySeparator = this._config.displaySeparator || ', ';
1292
+ var texts = selectedValues.map(function (value) {
1293
+ var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
1294
+ return (option === null || option === void 0 ? void 0 : option.getAttribute('data-text')) || '';
1295
+ }).filter(Boolean);
1296
+ return texts.join(displaySeparator);
1297
+ };
1298
+ /**
1299
+ * Check if an option is disabled (either in dropdown or original select)
1300
+ */
1301
+ KTSelect.prototype._isOptionDisabled = function (value) {
1302
+ var dropdownOption = Array.from(this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
1303
+ var isDropdownDisabled = dropdownOption && (dropdownOption.classList.contains('disabled') || dropdownOption.getAttribute('aria-disabled') === 'true');
1304
+ var selectOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
1305
+ var isNativeDisabled = selectOption && selectOption.disabled;
1306
+ return Boolean(isDropdownDisabled || isNativeDisabled);
1307
+ };
1308
+ /**
1309
+ * Centralized keyboard event handler for all select modes
1310
+ */
1311
+ KTSelect.prototype._handleKeyboardEvent = function (event) {
1312
+ var isOpen = this._dropdownIsOpen;
1313
+ var config = this._config;
1314
+ var focusManager = this._focusManager;
1315
+ var buffer = this._typeToSearchBuffer;
1316
+ // Ignore modifier keys
1317
+ if (event.altKey || event.ctrlKey || event.metaKey)
1318
+ return;
1319
+ // Type-to-search: only for single char keys
1320
+ if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/)) {
1321
+ buffer.push(event.key);
1322
+ var str = buffer.getBuffer();
1323
+ focusManager.focusByString(str);
1324
+ return;
1325
+ }
1326
+ switch (event.key) {
1327
+ case 'ArrowDown':
1328
+ event.preventDefault();
1329
+ if (!isOpen) {
1330
+ this.openDropdown();
1331
+ }
1332
+ else {
1333
+ focusManager.focusNext();
1334
+ }
1335
+ break;
1336
+ case 'ArrowUp':
1337
+ event.preventDefault();
1338
+ if (!isOpen) {
1339
+ this.openDropdown();
1340
+ }
1341
+ else {
1342
+ focusManager.focusPrevious();
1343
+ }
1344
+ break;
1345
+ case 'Home':
1346
+ event.preventDefault();
1347
+ if (isOpen)
1348
+ focusManager.focusFirst();
1349
+ break;
1350
+ case 'End':
1351
+ event.preventDefault();
1352
+ if (isOpen)
1353
+ focusManager.focusLast();
1354
+ break;
1355
+ case 'Enter':
1356
+ case ' ': // Space
1357
+ if (isOpen) {
1358
+ var focused = focusManager.getFocusedOption();
1359
+ if (focused) {
1360
+ var value = focused.dataset.value;
1361
+ if (value) {
1362
+ this.toggleSelection(value);
1363
+ if (!config.multiple && config.closeOnSelect) {
1364
+ this.closeDropdown();
1365
+ }
1366
+ }
1367
+ }
1368
+ // Prevent form submit
1369
+ event.preventDefault();
1370
+ }
1371
+ else {
1372
+ this.openDropdown();
1373
+ }
1374
+ break;
1375
+ case 'Escape':
1376
+ if (isOpen) {
1377
+ this.closeDropdown();
1378
+ event.target.blur();
1379
+ }
1380
+ break;
1381
+ case 'Tab':
1382
+ // Let Tab propagate for normal focus movement
1383
+ break;
1384
+ default:
1385
+ break;
1386
+ }
1387
+ };
1388
+ KTSelect.prototype.renderDisplayTemplateForSelected = function (selectedValues) {
1389
+ var _this = this;
1390
+ var optionsConfig = this._config.optionsConfig || {};
1391
+ var displaySeparator = this._config.displaySeparator || ', ';
1392
+ var contentArray = Array.from(new Set(selectedValues.map(function (value) {
1393
+ var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
1394
+ if (!option)
1395
+ return '';
1396
+ var displayTemplate = _this._config.displayTemplate;
1397
+ var text = option.getAttribute('data-text') || '';
1398
+ // Replace all {{varname}} in option.innerHTML with values from _config
1399
+ Object.entries(optionsConfig[value] || {}).forEach(function (_a) {
1400
+ var key = _a[0], val = _a[1];
1401
+ if (["string", "number", "boolean"].includes(typeof val)) {
1402
+ displayTemplate = displayTemplate.replace(new RegExp("{{".concat(key, "}}"), 'g'), String(val));
1403
+ }
1404
+ });
1405
+ return renderTemplateString(displayTemplate, {
1406
+ selectedCount: selectedValues.length || 0,
1407
+ selectedTexts: _this.getSelectedOptionsText() || '',
1408
+ text: text,
1409
+ });
1410
+ }).filter(Boolean)));
1411
+ return contentArray.join(displaySeparator);
1412
+ };
1526
1413
  /**
1527
1414
  * ========================================================================
1528
1415
  * STATIC METHODS