@keenthemes/ktui 1.0.11 → 1.0.13

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 (123) hide show
  1. package/dist/ktui.js +1687 -1517
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +5822 -0
  5. package/examples/select/avatar.html +47 -0
  6. package/examples/select/basic-usage.html +39 -0
  7. package/examples/select/combobox-icons_.html +59 -0
  8. package/examples/select/combobox_.html +46 -0
  9. package/examples/select/country.html +43 -0
  10. package/examples/select/description.html +53 -0
  11. package/examples/select/disable-option.html +37 -0
  12. package/examples/select/disable-select.html +35 -0
  13. package/examples/select/icon-multiple.html +50 -0
  14. package/examples/select/icon.html +48 -0
  15. package/examples/select/max-selection.html +38 -0
  16. package/examples/select/modal.html +72 -0
  17. package/examples/select/multiple.html +40 -0
  18. package/examples/select/placeholder.html +40 -0
  19. package/examples/select/remote-data_.html +32 -0
  20. package/examples/select/search.html +57 -0
  21. package/examples/select/sizes.html +94 -0
  22. package/examples/select/tags-icons_.html +58 -0
  23. package/examples/select/tags-selected_.html +59 -0
  24. package/examples/select/tags_.html +58 -0
  25. package/examples/select/template-customization.html +62 -0
  26. package/examples/toast/example.html +427 -0
  27. package/lib/cjs/components/datatable/datatable.js +23 -7
  28. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  29. package/lib/cjs/components/select/combobox.js +94 -141
  30. package/lib/cjs/components/select/combobox.js.map +1 -1
  31. package/lib/cjs/components/select/config.js +4 -18
  32. package/lib/cjs/components/select/config.js.map +1 -1
  33. package/lib/cjs/components/select/dropdown.js +35 -138
  34. package/lib/cjs/components/select/dropdown.js.map +1 -1
  35. package/lib/cjs/components/select/index.js +2 -1
  36. package/lib/cjs/components/select/index.js.map +1 -1
  37. package/lib/cjs/components/select/option.js +56 -6
  38. package/lib/cjs/components/select/option.js.map +1 -1
  39. package/lib/cjs/components/select/remote.js +1 -37
  40. package/lib/cjs/components/select/remote.js.map +1 -1
  41. package/lib/cjs/components/select/search.js +147 -128
  42. package/lib/cjs/components/select/search.js.map +1 -1
  43. package/lib/cjs/components/select/select.js +332 -391
  44. package/lib/cjs/components/select/select.js.map +1 -1
  45. package/lib/cjs/components/select/tags.js +38 -56
  46. package/lib/cjs/components/select/tags.js.map +1 -1
  47. package/lib/cjs/components/select/templates.js +168 -200
  48. package/lib/cjs/components/select/templates.js.map +1 -1
  49. package/lib/cjs/components/select/types.js +0 -12
  50. package/lib/cjs/components/select/types.js.map +1 -1
  51. package/lib/cjs/components/select/utils.js +187 -339
  52. package/lib/cjs/components/select/utils.js.map +1 -1
  53. package/lib/cjs/components/toast/index.js +10 -0
  54. package/lib/cjs/components/toast/index.js.map +1 -0
  55. package/lib/cjs/components/toast/toast.js +543 -0
  56. package/lib/cjs/components/toast/toast.js.map +1 -0
  57. package/lib/cjs/components/toast/types.js +7 -0
  58. package/lib/cjs/components/toast/types.js.map +1 -0
  59. package/lib/cjs/index.js +5 -1
  60. package/lib/cjs/index.js.map +1 -1
  61. package/lib/esm/components/datatable/datatable.js +23 -7
  62. package/lib/esm/components/datatable/datatable.js.map +1 -1
  63. package/lib/esm/components/select/combobox.js +95 -142
  64. package/lib/esm/components/select/combobox.js.map +1 -1
  65. package/lib/esm/components/select/config.js +3 -17
  66. package/lib/esm/components/select/config.js.map +1 -1
  67. package/lib/esm/components/select/dropdown.js +35 -138
  68. package/lib/esm/components/select/dropdown.js.map +1 -1
  69. package/lib/esm/components/select/index.js +1 -1
  70. package/lib/esm/components/select/index.js.map +1 -1
  71. package/lib/esm/components/select/option.js +56 -6
  72. package/lib/esm/components/select/option.js.map +1 -1
  73. package/lib/esm/components/select/remote.js +1 -37
  74. package/lib/esm/components/select/remote.js.map +1 -1
  75. package/lib/esm/components/select/search.js +148 -129
  76. package/lib/esm/components/select/search.js.map +1 -1
  77. package/lib/esm/components/select/select.js +333 -392
  78. package/lib/esm/components/select/select.js.map +1 -1
  79. package/lib/esm/components/select/tags.js +38 -56
  80. package/lib/esm/components/select/tags.js.map +1 -1
  81. package/lib/esm/components/select/templates.js +167 -199
  82. package/lib/esm/components/select/templates.js.map +1 -1
  83. package/lib/esm/components/select/types.js +1 -11
  84. package/lib/esm/components/select/types.js.map +1 -1
  85. package/lib/esm/components/select/utils.js +184 -336
  86. package/lib/esm/components/select/utils.js.map +1 -1
  87. package/lib/esm/components/toast/index.js +6 -0
  88. package/lib/esm/components/toast/index.js.map +1 -0
  89. package/lib/esm/components/toast/toast.js +540 -0
  90. package/lib/esm/components/toast/toast.js.map +1 -0
  91. package/lib/esm/components/toast/types.js +6 -0
  92. package/lib/esm/components/toast/types.js.map +1 -0
  93. package/lib/esm/index.js +3 -0
  94. package/lib/esm/index.js.map +1 -1
  95. package/package.json +14 -9
  96. package/src/components/alert/alert.css +15 -2
  97. package/src/components/datatable/datatable.ts +25 -17
  98. package/src/components/input/input.css +3 -1
  99. package/src/components/link/link.css +2 -2
  100. package/src/components/scrollable/scrollable.css +9 -5
  101. package/src/components/select/combobox.ts +96 -192
  102. package/src/components/select/config.ts +35 -36
  103. package/src/components/select/dropdown.ts +43 -155
  104. package/src/components/select/index.ts +1 -1
  105. package/src/components/select/option.ts +50 -10
  106. package/src/components/select/remote.ts +2 -42
  107. package/src/components/select/search.ts +159 -158
  108. package/src/components/select/select.css +137 -18
  109. package/src/components/select/select.ts +354 -506
  110. package/src/components/select/tags.ts +37 -60
  111. package/src/components/select/templates.ts +254 -328
  112. package/src/components/select/types.ts +0 -10
  113. package/src/components/select/utils.ts +190 -416
  114. package/src/components/textarea/textarea.css +2 -1
  115. package/src/components/toast/index.ts +7 -0
  116. package/src/components/toast/toast.css +60 -0
  117. package/src/components/toast/toast.ts +605 -0
  118. package/src/components/toast/types.ts +169 -0
  119. package/src/index.ts +4 -0
  120. package/styles/main.css +3 -0
  121. package/styles/vars.css +138 -0
  122. package/styles.css +1 -0
  123. package/webpack.config.js +6 -1
@@ -52,7 +52,6 @@ var combobox_1 = require("./combobox");
52
52
  var dropdown_1 = require("./dropdown");
53
53
  var utils_1 = require("./utils");
54
54
  var tags_1 = require("./tags");
55
- var types_1 = require("./types");
56
55
  var KTSelect = /** @class */ (function (_super) {
57
56
  __extends(KTSelect, _super);
58
57
  /**
@@ -69,6 +68,7 @@ var KTSelect = /** @class */ (function (_super) {
69
68
  _this._tagsModule = null;
70
69
  _this._dropdownModule = null;
71
70
  _this._loadMoreIndicator = null;
71
+ _this._typeToSearchBuffer = new utils_1.TypeToSearchBuffer();
72
72
  // Search debounce timeout
73
73
  _this._searchDebounceTimeout = null;
74
74
  // Store original options HTML for restoring after search
@@ -153,11 +153,6 @@ var KTSelect = /** @class */ (function (_super) {
153
153
  // Keep only the empty/placeholder option and remove the rest
154
154
  var options = Array.from(this._element.querySelectorAll('option:not([value=""])'));
155
155
  options.forEach(function (option) { return option.remove(); });
156
- // Ensure we have at least an empty option
157
- if (this._element.querySelectorAll('option').length === 0) {
158
- var emptyOption = templates_1.defaultTemplates.emptyOption(__assign(__assign({}, this._config), { placeholder: this._config.placeholder }));
159
- this._element.appendChild(emptyOption);
160
- }
161
156
  };
162
157
  /**
163
158
  * Helper to show a dropdown message (error, loading, noResults)
@@ -165,19 +160,20 @@ var KTSelect = /** @class */ (function (_super) {
165
160
  KTSelect.prototype._showDropdownMessage = function (type, message) {
166
161
  if (!this._dropdownContentElement)
167
162
  return;
168
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
163
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
169
164
  if (!optionsContainer)
170
165
  return;
166
+ // Clear previous messages
167
+ optionsContainer.innerHTML = '';
171
168
  switch (type) {
172
169
  case 'error':
173
- optionsContainer.innerHTML = templates_1.defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message }));
170
+ optionsContainer.appendChild(templates_1.defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message })));
174
171
  break;
175
172
  case 'loading':
176
- optionsContainer.innerHTML = templates_1.defaultTemplates.loading(this._config, message || 'Loading...').outerHTML;
173
+ optionsContainer.appendChild(templates_1.defaultTemplates.loading(this._config, message || 'Loading...'));
177
174
  break;
178
- case 'noResults':
179
- optionsContainer.innerHTML = '';
180
- optionsContainer.appendChild(templates_1.defaultTemplates.noResults(this._config));
175
+ case 'empty':
176
+ optionsContainer.appendChild(templates_1.defaultTemplates.empty(this._config));
181
177
  break;
182
178
  }
183
179
  };
@@ -196,14 +192,6 @@ var KTSelect = /** @class */ (function (_super) {
196
192
  * @param message Error message
197
193
  */
198
194
  KTSelect.prototype._renderErrorState = function (message) {
199
- // Create error option if the select is empty
200
- if (this._element.querySelectorAll('option').length <= 1) {
201
- var loadingOptions = this._element.querySelectorAll('option[disabled]:not([value])');
202
- loadingOptions.forEach(function (option) { return option.remove(); });
203
- // Use template function for error option instead of hardcoded element
204
- var errorOption = templates_1.defaultTemplates.errorOption(__assign(__assign({}, this._config), { errorMessage: message }));
205
- this._element.appendChild(errorOption);
206
- }
207
195
  // If dropdown is already created, show error message there
208
196
  this._showDropdownMessage('error', message);
209
197
  if (!this._wrapperElement) {
@@ -226,7 +214,7 @@ var KTSelect = /** @class */ (function (_super) {
226
214
  // Create load more button using template
227
215
  this._loadMoreIndicator = templates_1.defaultTemplates.loadMore(this._config);
228
216
  // Add to dropdown
229
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
217
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
230
218
  if (optionsContainer) {
231
219
  optionsContainer.appendChild(this._loadMoreIndicator);
232
220
  }
@@ -296,42 +284,26 @@ var KTSelect = /** @class */ (function (_super) {
296
284
  * @param newItems New items to add to the dropdown
297
285
  */
298
286
  KTSelect.prototype._updateOptionsInDropdown = function (newItems) {
299
- var _this = this;
300
287
  if (!this._dropdownContentElement || !newItems.length)
301
288
  return;
302
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
289
+ var optionsContainer = this._dropdownContentElement.querySelector("[data-kt-select-options]");
303
290
  if (!optionsContainer)
304
291
  return;
305
292
  // Get the load more button
306
- var loadMoreButton = optionsContainer.querySelector('[data-kt-select-load-more]');
293
+ var loadMoreButton = optionsContainer.querySelector("[data-kt-select-load-more]");
307
294
  // Process each new item
308
295
  newItems.forEach(function (item) {
309
296
  // Create option for the original select
310
- var selectOption = templates_1.defaultTemplates.emptyOption(__assign(__assign({}, _this._config), { placeholder: item.title || 'Unnamed option' }));
297
+ var selectOption = document.createElement('option');
311
298
  selectOption.value = item.id || '';
312
- // Add description and icon attributes if available and valid
313
- if (item.description &&
314
- item.description !== 'null' &&
315
- item.description !== 'undefined') {
316
- selectOption.setAttribute('data-kt-select-option-description', item.description);
317
- }
318
- if (item.icon && item.icon !== 'null' && item.icon !== 'undefined') {
319
- selectOption.setAttribute('data-kt-select-option-icon', item.icon);
320
- }
321
- // Add the option to the original select element
322
- _this._element.appendChild(selectOption);
323
- // Create option element for the dropdown using the KTSelectOption class
324
- // This ensures consistent option rendering
325
- var ktOption = new option_1.KTSelectOption(selectOption, _this._config);
326
- var renderedOption = ktOption.render();
327
299
  // Add to dropdown container
328
300
  if (loadMoreButton) {
329
301
  // Insert before the load more button
330
- optionsContainer.insertBefore(renderedOption, loadMoreButton);
302
+ optionsContainer.insertBefore(selectOption, loadMoreButton);
331
303
  }
332
304
  else {
333
305
  // Append to the end
334
- optionsContainer.appendChild(renderedOption);
306
+ optionsContainer.appendChild(selectOption);
335
307
  }
336
308
  });
337
309
  // Update options NodeList to include the new options
@@ -353,7 +325,7 @@ var KTSelect = /** @class */ (function (_super) {
353
325
  this._setupElementReferences();
354
326
  this._initZIndex();
355
327
  // Initialize options
356
- this._initializeOptionsHtml();
328
+ // this._initializeOptionsHtml();
357
329
  this._preSelectOptions(this._element);
358
330
  // Apply disabled state if needed
359
331
  this._applyInitialDisabledState();
@@ -362,17 +334,17 @@ var KTSelect = /** @class */ (function (_super) {
362
334
  this._initializeSearchModule();
363
335
  }
364
336
  // Initialize combobox if enabled
365
- if (this._config.mode === types_1.SelectMode.COMBOBOX) {
337
+ if (this._config.combobox) {
366
338
  this._comboboxModule = new combobox_1.KTSelectCombobox(this);
367
339
  }
368
340
  // Initialize tags if enabled
369
- if (this._config.mode === types_1.SelectMode.TAGS) {
341
+ if (this._config.tags) {
370
342
  this._tagsModule = new tags_1.KTSelectTags(this);
371
343
  }
372
344
  // Initialize focus manager after dropdown element is created
373
345
  this._focusManager = new utils_1.FocusManager(this._dropdownContentElement, '[data-kt-select-option]', this._config);
374
346
  // Initialize dropdown module after all elements are created
375
- this._dropdownModule = new dropdown_1.KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config);
347
+ this._dropdownModule = new dropdown_1.KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config, this);
376
348
  // Update display and set ARIA attributes
377
349
  this._updateDisplayAndAriaAttributes();
378
350
  this.updateSelectedOptionDisplay();
@@ -380,34 +352,34 @@ var KTSelect = /** @class */ (function (_super) {
380
352
  // Attach event listeners after all modules are initialized
381
353
  this._attachEventListeners();
382
354
  };
383
- /**
384
- * Initialize options HTML from data
385
- */
386
- KTSelect.prototype._initializeOptionsHtml = function () {
387
- this._generateOptionsHtml(this._element);
388
- };
389
355
  /**
390
356
  * Creates the HTML structure for the select component
391
357
  */
392
358
  KTSelect.prototype._createHtmlStructure = function () {
359
+ var _a;
393
360
  var _this = this;
394
361
  var options = Array.from(this._element.querySelectorAll('option'));
395
362
  // Create wrapper and display elements
396
- var wrapperElement = templates_1.defaultTemplates.main(this._config);
363
+ var wrapperElement = templates_1.defaultTemplates.wrapper(this._config);
397
364
  var displayElement = templates_1.defaultTemplates.display(this._config);
398
365
  // Add the display element to the wrapper
399
366
  wrapperElement.appendChild(displayElement);
367
+ // Move classes from original select to display element
368
+ if (this._element.classList.length > 0) {
369
+ (_a = displayElement.classList).add.apply(_a, Array.from(this._element.classList));
370
+ this._element.className = '';
371
+ }
400
372
  // Create an empty dropdown first (without options) using template
401
- var dropdownElement = templates_1.defaultTemplates.dropdownContent(__assign(__assign({}, this._config), { zindex: this._config.dropdownZindex }));
373
+ var dropdownElement = templates_1.defaultTemplates.dropdown(__assign(__assign({}, this._config), { zindex: this._config.dropdownZindex }));
402
374
  // Add search input if needed
403
- var isCombobox = this._config.mode === types_1.SelectMode.COMBOBOX;
404
- var hasSearch = this._config.enableSearch && !isCombobox;
405
- if (hasSearch) {
375
+ if (this._config.enableSearch) {
406
376
  var searchElement = templates_1.defaultTemplates.search(this._config);
407
377
  dropdownElement.appendChild(searchElement);
408
378
  }
409
379
  // Create options container using template
410
- var optionsContainer = templates_1.defaultTemplates.optionsContainer(this._config);
380
+ var optionsContainer = templates_1.defaultTemplates.options(this._config);
381
+ // Clear the options container
382
+ optionsContainer.innerHTML = '';
411
383
  // Add each option directly to the container
412
384
  options.forEach(function (optionElement) {
413
385
  // Skip empty placeholder options (only if BOTH value AND text are empty)
@@ -438,21 +410,17 @@ var KTSelect = /** @class */ (function (_super) {
438
410
  // Get display element
439
411
  this._displayElement = this._wrapperElement.querySelector("[data-kt-select-display]");
440
412
  // Get dropdown content element - this is critical for dropdown functionality
441
- this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown-content]");
413
+ this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown]");
442
414
  if (!this._dropdownContentElement) {
415
+ console.log(this._element);
443
416
  console.error('Dropdown content element not found', this._wrapperElement);
444
417
  }
445
418
  // Get search input element - this is used for the search functionality
446
- // First check if it's in dropdown, then check if it's in display (for combobox)
447
419
  this._searchInputElement = this._dropdownContentElement.querySelector("[data-kt-select-search]");
448
- // If not found in dropdown, check if it's the display element itself (for combobox)
449
- if (!this._searchInputElement &&
450
- this._config.mode === types_1.SelectMode.COMBOBOX) {
420
+ // If not found in dropdown, check if it's the display element itself
421
+ if (!this._searchInputElement) {
451
422
  this._searchInputElement = this._displayElement;
452
423
  }
453
- if (this._config.debug)
454
- console.log('Search input found:', this._searchInputElement ? 'Yes' : 'No', 'Mode:', this._config.mode, 'EnableSearch:', this._config.enableSearch);
455
- this._valueDisplayElement = this._wrapperElement.querySelector("[data-kt-select-value]");
456
424
  this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
457
425
  };
458
426
  /**
@@ -461,17 +429,12 @@ var KTSelect = /** @class */ (function (_super) {
461
429
  KTSelect.prototype._attachEventListeners = function () {
462
430
  // Document level event listeners
463
431
  document.addEventListener('click', this._handleDocumentClick.bind(this));
464
- document.addEventListener('keydown', this._handleEscKey.bind(this));
465
432
  // Dropdown option click events
466
433
  this._eventManager.addListener(this._dropdownContentElement, 'click', this._handleDropdownOptionClick.bind(this));
467
- // Only attach click handler to display element
468
- this._eventManager.addListener(this._displayElement, 'click', this._handleDropdownClick.bind(this));
469
- // Only attach keyboard navigation to display element if NOT in combobox mode
470
- // This prevents conflicts with the combobox module's keyboard handler
471
- if (this._config.mode !== types_1.SelectMode.COMBOBOX) {
472
- if (this._config.debug)
473
- console.log('Attaching keyboard navigation to display element (non-combobox mode)');
474
- this._eventManager.addListener(this._displayElement, 'keydown', this._handleDropdownKeyDown.bind(this));
434
+ // Attach centralized keyboard handler to the wrapper element.
435
+ // Events from focusable children like _displayElement or _searchInputElement (if present) will bubble up.
436
+ if (this._wrapperElement) {
437
+ this._wrapperElement.addEventListener('keydown', this._handleKeyboardEvent.bind(this));
475
438
  }
476
439
  };
477
440
  /**
@@ -541,52 +504,12 @@ var KTSelect = /** @class */ (function (_super) {
541
504
  label =
542
505
  extractedLabel !== null ? String(extractedLabel) : 'Unnamed option';
543
506
  }
544
- // Get description - skip if null, undefined, or "null" string
545
- var description = null;
546
- if (item.description !== undefined &&
547
- item.description !== null &&
548
- String(item.description) !== 'null' &&
549
- String(item.description) !== 'undefined') {
550
- description = String(item.description);
551
- }
552
- else if (_this._config.dataFieldDescription) {
553
- var extractedDesc = _this._getValueByKey(item, _this._config.dataFieldDescription);
554
- if (extractedDesc !== null &&
555
- extractedDesc !== undefined &&
556
- String(extractedDesc) !== 'null' &&
557
- String(extractedDesc) !== 'undefined') {
558
- description = String(extractedDesc);
559
- }
560
- }
561
- // Get icon - skip if null, undefined, or "null" string
562
- var icon = null;
563
- if (item.icon !== undefined &&
564
- item.icon !== null &&
565
- String(item.icon) !== 'null' &&
566
- String(item.icon) !== 'undefined') {
567
- icon = String(item.icon);
568
- }
569
- else if (_this._config.dataFieldIcon) {
570
- var extractedIcon = _this._getValueByKey(item, _this._config.dataFieldIcon);
571
- if (extractedIcon !== null &&
572
- extractedIcon !== undefined &&
573
- String(extractedIcon) !== 'null' &&
574
- String(extractedIcon) !== 'undefined') {
575
- icon = String(extractedIcon);
576
- }
577
- }
578
507
  // Log the extracted values for debugging
579
508
  if (_this._config.debug)
580
- console.log("Option: value=".concat(value, ", label=").concat(label, ", desc=").concat(description ? description : 'none', ", icon=").concat(icon ? icon : 'none'));
509
+ console.log("Option: value=".concat(value, ", label=").concat(label));
581
510
  // Set option attributes
582
511
  optionElement.value = value;
583
512
  optionElement.textContent = label || 'Unnamed option';
584
- if (description) {
585
- optionElement.setAttribute('data-kt-select-option-description', description);
586
- }
587
- if (icon) {
588
- optionElement.setAttribute('data-kt-select-option-icon', icon);
589
- }
590
513
  if (item.selected) {
591
514
  optionElement.setAttribute('selected', 'selected');
592
515
  }
@@ -654,31 +577,15 @@ var KTSelect = /** @class */ (function (_super) {
654
577
  * DROPDOWN MANAGEMENT
655
578
  * ========================================================================
656
579
  */
657
- /**
658
- * Toggle dropdown visibility
659
- */
660
- KTSelect.prototype.toggleDropdown = function () {
661
- if (this._config.debug)
662
- console.log('toggleDropdown called');
663
- if (this._dropdownModule) {
664
- // Always use the dropdown module's state to determine whether to open or close
665
- if (this._dropdownModule.isOpen()) {
666
- if (this._config.debug)
667
- console.log('Dropdown is open, closing...');
668
- this.closeDropdown();
669
- }
670
- else {
671
- if (this._config.debug)
672
- console.log('Dropdown is closed, opening...');
673
- this.openDropdown();
674
- }
675
- }
676
- };
677
580
  /**
678
581
  * Open the dropdown
679
582
  */
680
583
  KTSelect.prototype.openDropdown = function () {
681
- var _this = this;
584
+ if (this._config.disabled) {
585
+ if (this._config.debug)
586
+ console.log('openDropdown: select is disabled, not opening');
587
+ return;
588
+ }
682
589
  if (this._config.debug)
683
590
  console.log('openDropdown called, dropdownModule exists:', !!this._dropdownModule);
684
591
  if (!this._dropdownModule) {
@@ -701,14 +608,6 @@ var KTSelect = /** @class */ (function (_super) {
701
608
  // Dispatch custom event
702
609
  this._dispatchEvent('show');
703
610
  this._fireEvent('show');
704
- // Focus search input if configured and exists
705
- if (this._config.enableSearch &&
706
- this._config.searchAutofocus &&
707
- this._searchInputElement) {
708
- setTimeout(function () {
709
- _this._searchInputElement.focus();
710
- }, 50);
711
- }
712
611
  // Update ARIA states
713
612
  this._setAriaAttributes();
714
613
  // Focus the first selected option or first option if nothing selected
@@ -729,14 +628,14 @@ var KTSelect = /** @class */ (function (_super) {
729
628
  // Always close by delegating to the dropdown module, which is the source of truth
730
629
  if (this._config.debug)
731
630
  console.log('Closing dropdown via dropdownModule...');
732
- // Clear search input and highlights if the dropdown is closing
631
+ // Clear search input if the dropdown is closing
733
632
  if (this._searchModule && this._searchInputElement) {
734
633
  // Clear search input if configured to do so
735
634
  if (this._config.clearSearchOnClose) {
736
635
  this._searchInputElement.value = '';
737
636
  }
738
- // Always clear the highlights when dropdown closes
739
- this._searchModule.clearSearchHighlights();
637
+ // Clear search input when dropdown closes
638
+ this._searchModule.clearSearch();
740
639
  }
741
640
  // Set our internal flag to match what we're doing
742
641
  this._dropdownIsOpen = false;
@@ -770,10 +669,13 @@ var KTSelect = /** @class */ (function (_super) {
770
669
  var selectedOptions = this.getSelectedOptions();
771
670
  if (selectedOptions.length === 0)
772
671
  return;
773
- // Get the first selected option element
774
- var firstSelectedValue = selectedOptions[0];
775
- // Use the FocusManager to focus on the option
776
- this._focusManager.focusOptionByValue(firstSelectedValue);
672
+ // Iterate through selected options and focus the first one that is visible
673
+ for (var _i = 0, selectedOptions_1 = selectedOptions; _i < selectedOptions_1.length; _i++) {
674
+ var value = selectedOptions_1[_i];
675
+ if (this._focusManager && this._focusManager.focusOptionByValue(value)) {
676
+ break; // Stop after focusing the first found selected and visible option
677
+ }
678
+ }
777
679
  };
778
680
  /**
779
681
  * ========================================================================
@@ -784,6 +686,12 @@ var KTSelect = /** @class */ (function (_super) {
784
686
  * Select an option by value
785
687
  */
786
688
  KTSelect.prototype._selectOption = function (value) {
689
+ // Prevent selection if the option is disabled (in dropdown or original select)
690
+ if (this._isOptionDisabled(value)) {
691
+ if (this._config.debug)
692
+ console.log('_selectOption: Option is disabled, ignoring selection');
693
+ return;
694
+ }
787
695
  // Get current selection state
788
696
  var isSelected = this._state.isSelected(value);
789
697
  // Toggle selection in state
@@ -829,109 +737,91 @@ var KTSelect = /** @class */ (function (_super) {
829
737
  * Update selected option display value
830
738
  */
831
739
  KTSelect.prototype.updateSelectedOptionDisplay = function () {
832
- var _this = this;
833
740
  var selectedOptions = this.getSelectedOptions();
834
- if (this._config.renderSelected) {
835
- // Use the custom renderSelected function if provided
836
- this._updateValueDisplay(this._config.renderSelected(selectedOptions));
741
+ var tagsEnabled = this._config.tags && this._tagsModule;
742
+ var valueDisplayEl = this.getValueDisplayElement();
743
+ if (tagsEnabled) {
744
+ // Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
745
+ this._tagsModule.updateTagsDisplay(selectedOptions);
746
+ }
747
+ // Guard against valueDisplayEl being null due to template modifications
748
+ if (!valueDisplayEl) {
749
+ if (this._config.debug) {
750
+ console.warn('KTSelect: Value display element is null. Cannot update display or placeholder. Check template for [data-kt-select-value].');
751
+ }
752
+ return; // Nothing to display on if the element is missing
837
753
  }
838
- else {
839
- if (selectedOptions.length === 0) {
840
- if (this._config.mode !== types_1.SelectMode.COMBOBOX) {
841
- this._updateValueDisplay(this._config.placeholder); // Use innerHTML for placeholder
842
- }
754
+ // 1. Custom render function takes highest precedence
755
+ if (typeof this._config.renderSelected === 'function') {
756
+ valueDisplayEl.innerHTML = this._config.renderSelected(selectedOptions);
757
+ return;
758
+ }
759
+ // 2. Custom displayTemplate string
760
+ // Check if a custom display template string is provided directly in config or via config.templates
761
+ var customDisplayTemplateString = this._config.displayTemplate || (this._config.templates && this._config.templates.display);
762
+ if (customDisplayTemplateString) {
763
+ // If tags are enabled and items are selected, the tags module handles display, so clear the main display area.
764
+ if (tagsEnabled && selectedOptions.length > 0) {
765
+ valueDisplayEl.innerHTML = '';
843
766
  }
844
- else if (this._config.multiple) {
845
- if (this._config.mode === types_1.SelectMode.TAGS) {
846
- // Use the tags module to render selected options as tags
847
- if (this._tagsModule) {
848
- this._tagsModule.updateTagsDisplay(selectedOptions);
849
- }
850
- else {
851
- // Fallback if tags module not initialized for some reason
852
- this._updateValueDisplay(selectedOptions.join(', '));
853
- }
854
- }
855
- else {
856
- // Render as comma-separated values
857
- var displayText = selectedOptions
858
- .map(function (option) { return _this._getOptionInnerHtml(option) || ''; })
859
- .join(', ');
860
- this._updateValueDisplay(displayText);
861
- }
767
+ else {
768
+ // Otherwise, render the custom display template.
769
+ // If no options are selected, renderDisplayTemplateForSelected should handle showing a placeholder if the template supports it,
770
+ // or we might need a separate placeholder rendering for custom templates if they don't handle empty selection.
771
+ // For now, assume renderDisplayTemplateForSelected handles it or shows selected text.
772
+ valueDisplayEl.innerHTML = this.renderDisplayTemplateForSelected(selectedOptions);
773
+ }
774
+ return;
775
+ }
776
+ // 3. Default template behavior (no custom function or string template)
777
+ var textContainer = valueDisplayEl.querySelector('[data-kt-text-container="true"]');
778
+ if (tagsEnabled && selectedOptions.length > 0) {
779
+ // Tags are active and have content, clear the text container if it exists,
780
+ // or the whole display if it doesn't (though it should with default template).
781
+ if (textContainer) {
782
+ textContainer.innerHTML = '';
862
783
  }
863
784
  else {
864
- var selectedOption = selectedOptions[0];
865
- if (selectedOption) {
866
- var selectedText = this._getOptionInnerHtml(selectedOption);
867
- this._updateValueDisplay(selectedText);
868
- // Update combobox input value if in combobox mode
869
- if (this._config.mode === types_1.SelectMode.COMBOBOX &&
870
- this._comboboxModule) {
871
- this._comboboxModule.updateSelectedValue(selectedText);
872
- }
873
- }
874
- else {
875
- this._updateValueDisplay(this._config.placeholder);
876
- }
785
+ valueDisplayEl.innerHTML = ''; // Fallback: clear entire display area
877
786
  }
878
787
  }
879
- // Update any debug display boxes if they exist
880
- this._updateDebugDisplays();
881
- };
882
- /**
883
- * Update the value display element
884
- */
885
- KTSelect.prototype._updateValueDisplay = function (value) {
886
- if (this._config.mode === types_1.SelectMode.COMBOBOX) {
887
- // For combobox, we only update the hidden value element, not the input
888
- // The combobox module will handle updating the input value
889
- if (!this._comboboxModule) {
890
- this._valueDisplayElement.value = value;
788
+ else if (selectedOptions.length === 0) {
789
+ // No options selected: display placeholder text in the text container.
790
+ var placeholderTemplate = templates_1.defaultTemplates.placeholder(this._config);
791
+ var placeholderText = placeholderTemplate.textContent || ''; // Get text from placeholder element
792
+ if (textContainer) {
793
+ textContainer.innerHTML = placeholderText;
794
+ }
795
+ else {
796
+ // Fallback: If no text container, replace children of valueDisplayEl with the placeholder element itself.
797
+ // This ensures the placeholder (which might have its own structure/classes) is displayed.
798
+ valueDisplayEl.replaceChildren(placeholderTemplate);
891
799
  }
892
800
  }
893
801
  else {
894
- this._valueDisplayElement.innerHTML = value;
895
- }
896
- };
897
- /**
898
- * Update debug displays if present
899
- */
900
- KTSelect.prototype._updateDebugDisplays = function () {
901
- // Check if we're in a test environment with debug boxes
902
- var selectId = this.getElement().id;
903
- if (selectId) {
904
- var debugElement = document.getElementById("".concat(selectId, "-value"));
905
- if (debugElement) {
906
- var selectedOptions = this.getSelectedOptions();
907
- // Format display based on selection mode
908
- if (this._config.multiple) {
909
- // For multiple selection, show comma-separated list
910
- debugElement.textContent =
911
- selectedOptions.length > 0 ? selectedOptions.join(', ') : 'None';
912
- }
913
- else {
914
- // For single selection, show just the one value
915
- debugElement.textContent =
916
- selectedOptions.length > 0 ? selectedOptions[0] : 'None';
917
- }
802
+ // Options are selected, and tags are not enabled (or no selected options for tags):
803
+ // Render normal selected text in the text container.
804
+ var content = this.getSelectedOptionsText();
805
+ if (textContainer) {
806
+ textContainer.innerHTML = content;
807
+ }
808
+ else {
809
+ valueDisplayEl.innerHTML = content; // Fallback: set content on whole display area
918
810
  }
919
811
  }
920
812
  };
921
813
  /**
922
- * Get option inner HTML content by option value
814
+ * Check if an option was originally disabled in the HTML
923
815
  */
924
- KTSelect.prototype._getOptionInnerHtml = function (optionValue) {
925
- var option = Array.from(this._options).find(function (opt) { return opt.dataset.value === optionValue; });
926
- if (this._config.mode == types_1.SelectMode.COMBOBOX) {
927
- return option.textContent;
928
- }
929
- return option.innerHTML; // Get the entire HTML content of the option
816
+ KTSelect.prototype._isOptionOriginallyDisabled = function (value) {
817
+ var originalOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
818
+ return originalOption ? originalOption.disabled : false;
930
819
  };
931
820
  /**
932
821
  * Update CSS classes for selected options
933
822
  */
934
823
  KTSelect.prototype._updateSelectedOptionClass = function () {
824
+ var _this = this;
935
825
  var allOptions = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
936
826
  var selectedValues = this._state.getSelectedOptions();
937
827
  var maxReached = typeof this._config.maxSelections === 'number' &&
@@ -943,9 +833,11 @@ var KTSelect = /** @class */ (function (_super) {
943
833
  if (!optionValue)
944
834
  return;
945
835
  var isSelected = selectedValues.includes(optionValue);
836
+ var isOriginallyDisabled = _this._isOptionOriginallyDisabled(optionValue);
946
837
  if (isSelected) {
947
838
  option.classList.add('selected');
948
839
  option.setAttribute('aria-selected', 'true');
840
+ // Selected options should not be visually hidden or disabled by maxSelections logic
949
841
  option.classList.remove('hidden');
950
842
  option.classList.remove('disabled');
951
843
  option.removeAttribute('aria-disabled');
@@ -953,7 +845,8 @@ var KTSelect = /** @class */ (function (_super) {
953
845
  else {
954
846
  option.classList.remove('selected');
955
847
  option.setAttribute('aria-selected', 'false');
956
- if (maxReached) {
848
+ // An option should be disabled if it was originally disabled OR if maxSelections is reached
849
+ if (isOriginallyDisabled || maxReached) {
957
850
  option.classList.add('disabled');
958
851
  option.setAttribute('aria-disabled', 'true');
959
852
  }
@@ -972,17 +865,6 @@ var KTSelect = /** @class */ (function (_super) {
972
865
  this._state.setSelectedOptions([]);
973
866
  this.updateSelectedOptionDisplay();
974
867
  this._updateSelectedOptionClass();
975
- // For combobox, also clear the input value
976
- if (this._config.mode === types_1.SelectMode.COMBOBOX) {
977
- if (this._searchInputElement) {
978
- this._searchInputElement.value = '';
979
- }
980
- // If combobox has a clear button, hide it
981
- if (this._comboboxModule) {
982
- // The combobox module will handle hiding the clear button
983
- this._comboboxModule.resetInputValueToSelection();
984
- }
985
- }
986
868
  // Dispatch change event
987
869
  this._dispatchEvent('change');
988
870
  this._fireEvent('change');
@@ -994,49 +876,6 @@ var KTSelect = /** @class */ (function (_super) {
994
876
  var values = Array.from(options).map(function (option) { return option.value; });
995
877
  this._state.setSelectedOptions(values);
996
878
  };
997
- /**
998
- * ========================================================================
999
- * KEYBOARD NAVIGATION
1000
- * ========================================================================
1001
- */
1002
- /**
1003
- * Handle dropdown key down events for keyboard navigation
1004
- * Only used for standard (non-combobox) dropdowns
1005
- */
1006
- KTSelect.prototype._handleDropdownKeyDown = function (event) {
1007
- // Log event for debugging
1008
- if (this._config.debug)
1009
- console.log('Standard dropdown keydown:', event.key);
1010
- // Use the shared handler
1011
- (0, utils_1.handleDropdownKeyNavigation)(event, this, {
1012
- multiple: this._config.multiple,
1013
- closeOnSelect: this._config.closeOnSelect,
1014
- });
1015
- };
1016
- /**
1017
- * Focus next option in dropdown
1018
- */
1019
- KTSelect.prototype._focusNextOption = function () {
1020
- return this._focusManager.focusNext();
1021
- };
1022
- /**
1023
- * Focus previous option in dropdown
1024
- */
1025
- KTSelect.prototype._focusPreviousOption = function () {
1026
- return this._focusManager.focusPrevious();
1027
- };
1028
- /**
1029
- * Apply hover/focus state to focused option
1030
- */
1031
- KTSelect.prototype._hoverFocusedOption = function (option) {
1032
- this._focusManager.applyFocus(option);
1033
- };
1034
- /**
1035
- * Scroll option into view when navigating
1036
- */
1037
- KTSelect.prototype._scrollOptionIntoView = function (option) {
1038
- this._focusManager.scrollIntoView(option);
1039
- };
1040
879
  /**
1041
880
  * Select the currently focused option
1042
881
  */
@@ -1060,60 +899,13 @@ var KTSelect = /** @class */ (function (_super) {
1060
899
  if (selectedValue) {
1061
900
  this._selectOption(selectedValue);
1062
901
  }
1063
- // For combobox mode, update input value AFTER selection to ensure consistency
1064
- if (this._config.mode === types_1.SelectMode.COMBOBOX && this._comboboxModule) {
1065
- this._comboboxModule.updateSelectedValue(selectedText);
1066
- // Also directly update the input value for immediate visual feedback
1067
- if (this._searchInputElement) {
1068
- this._searchInputElement.value = selectedText;
1069
- }
1070
- }
1071
902
  }
1072
903
  };
1073
- /**
1074
- * ========================================================================
1075
- * COMBOBOX SPECIFIC METHODS
1076
- * ========================================================================
1077
- */
1078
- /**
1079
- * Handle combobox input events
1080
- */
1081
- KTSelect.prototype._handleComboboxInput = function (event) {
1082
- if (this._comboboxModule) {
1083
- return;
1084
- }
1085
- var inputElement = event.target;
1086
- var query = inputElement.value.toLowerCase();
1087
- // If dropdown isn't open, open it when user starts typing
1088
- if (!this._dropdownIsOpen) {
1089
- this.openDropdown();
1090
- }
1091
- // Filter options based on input
1092
- this._filterOptionsForCombobox(query);
1093
- };
1094
- /**
1095
- * Filter options for combobox based on input query
1096
- * Uses the shared filterOptions function
1097
- */
1098
- KTSelect.prototype._filterOptionsForCombobox = function (query) {
1099
- var options = Array.from(this._dropdownContentElement.querySelectorAll('[data-kt-select-option]'));
1100
- (0, utils_1.filterOptions)(options, query, this._config, this._dropdownContentElement);
1101
- };
1102
904
  /**
1103
905
  * ========================================================================
1104
906
  * EVENT HANDLERS
1105
907
  * ========================================================================
1106
908
  */
1107
- /**
1108
- * Handle display element click
1109
- */
1110
- KTSelect.prototype._handleDropdownClick = function (event) {
1111
- if (this._config.debug)
1112
- console.log('Display element clicked', event.target);
1113
- event.preventDefault();
1114
- event.stopPropagation(); // Prevent event bubbling
1115
- this.toggleDropdown();
1116
- };
1117
909
  /**
1118
910
  * Handle click within the dropdown
1119
911
  */
@@ -1154,6 +946,13 @@ var KTSelect = /** @class */ (function (_super) {
1154
946
  }
1155
947
  if (this._config.debug)
1156
948
  console.log('Option clicked:', optionValue);
949
+ // If in single-select mode and the clicked option is already selected, just close the dropdown.
950
+ if (!this._config.multiple && this._state.isSelected(optionValue)) {
951
+ if (this._config.debug)
952
+ console.log('Single select mode: clicked already selected option. Closing dropdown.');
953
+ this.closeDropdown();
954
+ return;
955
+ }
1157
956
  // Use toggleSelection instead of _selectOption to prevent re-rendering
1158
957
  this.toggleSelection(optionValue);
1159
958
  };
@@ -1167,14 +966,6 @@ var KTSelect = /** @class */ (function (_super) {
1167
966
  this.closeDropdown();
1168
967
  }
1169
968
  };
1170
- /**
1171
- * Handle escape key press
1172
- */
1173
- KTSelect.prototype._handleEscKey = function (event) {
1174
- if (event.key === 'Escape' && this._dropdownIsOpen) {
1175
- this.closeDropdown();
1176
- }
1177
- };
1178
969
  /**
1179
970
  * ========================================================================
1180
971
  * ACCESSIBILITY METHODS
@@ -1186,18 +977,6 @@ var KTSelect = /** @class */ (function (_super) {
1186
977
  KTSelect.prototype._setAriaAttributes = function () {
1187
978
  this._displayElement.setAttribute('aria-expanded', this._dropdownIsOpen.toString());
1188
979
  };
1189
- /**
1190
- * Handle focus events
1191
- */
1192
- KTSelect.prototype._handleFocus = function () {
1193
- // Implementation pending
1194
- };
1195
- /**
1196
- * Handle blur events
1197
- */
1198
- KTSelect.prototype._handleBlur = function () {
1199
- // Implementation pending
1200
- };
1201
980
  /**
1202
981
  * ========================================================================
1203
982
  * PUBLIC API
@@ -1237,7 +1016,13 @@ var KTSelect = /** @class */ (function (_super) {
1237
1016
  * Get value display element
1238
1017
  */
1239
1018
  KTSelect.prototype.getValueDisplayElement = function () {
1240
- return this._valueDisplayElement;
1019
+ return this._displayElement;
1020
+ };
1021
+ /**
1022
+ * Get wrapper element
1023
+ */
1024
+ KTSelect.prototype.getWrapperElement = function () {
1025
+ return this._wrapperElement;
1241
1026
  };
1242
1027
  /**
1243
1028
  * Show all options in the dropdown
@@ -1247,6 +1032,7 @@ var KTSelect = /** @class */ (function (_super) {
1247
1032
  var options = Array.from(this._wrapperElement.querySelectorAll("[data-kt-select-option]"));
1248
1033
  // Show all options by removing the hidden class and any inline styles
1249
1034
  options.forEach(function (option) {
1035
+ var _a;
1250
1036
  // Remove hidden class
1251
1037
  option.classList.remove('hidden');
1252
1038
  // Clean up any existing inline styles for backward compatibility
@@ -1260,17 +1046,17 @@ var KTSelect = /** @class */ (function (_super) {
1260
1046
  }
1261
1047
  else {
1262
1048
  // Otherwise, remove just the display property
1263
- option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
1049
+ option.setAttribute('style', (_a = styleAttr === null || styleAttr === void 0 ? void 0 : styleAttr.replace(/display:\s*[^;]+;?/gi, '')) === null || _a === void 0 ? void 0 : _a.trim());
1264
1050
  }
1265
1051
  }
1266
1052
  }
1267
1053
  });
1268
1054
  // If search input exists, clear it
1269
- if (this._searchInputElement && this._config.mode !== types_1.SelectMode.COMBOBOX) {
1055
+ if (this._searchInputElement) {
1270
1056
  this._searchInputElement.value = '';
1271
1057
  // If we have a search module, clear any search filtering
1272
1058
  if (this._searchModule) {
1273
- this._searchModule.clearSearchHighlights();
1059
+ this._searchModule.clearSearch();
1274
1060
  }
1275
1061
  }
1276
1062
  };
@@ -1290,10 +1076,16 @@ var KTSelect = /** @class */ (function (_super) {
1290
1076
  * Toggle the selection of an option
1291
1077
  */
1292
1078
  KTSelect.prototype.toggleSelection = function (value) {
1079
+ // Prevent selection if the option is disabled (in dropdown or original select)
1080
+ if (this._isOptionDisabled(value)) {
1081
+ if (this._config.debug)
1082
+ console.log('toggleSelection: Option is disabled, ignoring selection');
1083
+ return;
1084
+ }
1293
1085
  // Get current selection state
1294
1086
  var isSelected = this._state.isSelected(value);
1295
1087
  if (this._config.debug)
1296
- console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple, ", closeOnSelect: ").concat(this._config.closeOnSelect));
1088
+ console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple));
1297
1089
  // If already selected in single select mode, do nothing (can't deselect in single select)
1298
1090
  if (isSelected && !this._config.multiple) {
1299
1091
  if (this._config.debug)
@@ -1302,9 +1094,9 @@ var KTSelect = /** @class */ (function (_super) {
1302
1094
  }
1303
1095
  if (this._config.debug)
1304
1096
  console.log("Toggling selection for option: ".concat(value, ", currently selected: ").concat(isSelected));
1305
- // Ensure any search highlights are cleared when selection changes
1097
+ // Ensure any search input is cleared when selection changes
1306
1098
  if (this._searchModule) {
1307
- this._searchModule.clearSearchHighlights();
1099
+ this._searchModule.clearSearch();
1308
1100
  }
1309
1101
  // Toggle the selection in the state
1310
1102
  this._state.toggleSelectedOptions(value);
@@ -1327,15 +1119,14 @@ var KTSelect = /** @class */ (function (_super) {
1327
1119
  // Update option classes without re-rendering the dropdown content
1328
1120
  this._updateSelectedOptionClass();
1329
1121
  // For single select mode, always close the dropdown after selection
1330
- // For multiple select mode, only close if closeOnSelect is true
1331
1122
  if (!this._config.multiple) {
1332
1123
  if (this._config.debug)
1333
1124
  console.log('About to call closeDropdown() for single select mode - always close after selection');
1334
1125
  this.closeDropdown();
1335
1126
  }
1336
- else if (this._config.closeOnSelect) {
1127
+ else {
1337
1128
  if (this._config.debug)
1338
- console.log('About to call closeDropdown() for multiple select with closeOnSelect:true');
1129
+ console.log('About to call closeDropdown() for multiple select');
1339
1130
  this.closeDropdown();
1340
1131
  }
1341
1132
  // Dispatch custom change event with additional data
@@ -1435,9 +1226,9 @@ var KTSelect = /** @class */ (function (_super) {
1435
1226
  .then(function () {
1436
1227
  // Update options in the dropdown
1437
1228
  _this._updateSearchResults(items);
1438
- // Refresh the search module's option cache if search is enabled
1439
- if (_this._searchModule && _this._config.enableSearch) {
1440
- _this._searchModule.refreshOptionCache();
1229
+ // Refresh the search module to update focus and cache
1230
+ if (_this._searchModule) {
1231
+ _this._searchModule.refreshAfterSearch();
1441
1232
  }
1442
1233
  })
1443
1234
  .catch(function (error) {
@@ -1457,7 +1248,7 @@ var KTSelect = /** @class */ (function (_super) {
1457
1248
  */
1458
1249
  KTSelect.prototype._renderSearchLoadingState = function () {
1459
1250
  if (!this._originalOptionsHtml && this._dropdownContentElement) {
1460
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
1251
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
1461
1252
  if (optionsContainer) {
1462
1253
  this._originalOptionsHtml = optionsContainer.innerHTML;
1463
1254
  }
@@ -1476,36 +1267,26 @@ var KTSelect = /** @class */ (function (_super) {
1476
1267
  * @param items Search result items
1477
1268
  */
1478
1269
  KTSelect.prototype._updateSearchResults = function (items) {
1479
- var _this = this;
1480
1270
  if (!this._dropdownContentElement)
1481
1271
  return;
1482
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
1272
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
1483
1273
  if (!optionsContainer)
1484
1274
  return;
1485
1275
  // Clear current options
1486
1276
  optionsContainer.innerHTML = '';
1487
1277
  if (items.length === 0) {
1488
1278
  // Show no results message using template for consistency and customization
1489
- var noResultsElement = templates_1.defaultTemplates.noResults(this._config);
1279
+ var noResultsElement = templates_1.defaultTemplates.empty(this._config);
1490
1280
  optionsContainer.appendChild(noResultsElement);
1491
1281
  return;
1492
1282
  }
1493
1283
  // Process each item individually to create options
1494
1284
  items.forEach(function (item) {
1495
1285
  // Create option for the original select
1496
- var selectOption = templates_1.defaultTemplates.emptyOption(__assign(__assign({}, _this._config), { placeholder: item.title }));
1286
+ var selectOption = document.createElement('option');
1497
1287
  selectOption.value = item.id;
1498
- if (item.description) {
1499
- selectOption.setAttribute('data-kt-select-option-description', item.description);
1500
- }
1501
- if (item.icon) {
1502
- selectOption.setAttribute('data-kt-select-option-icon', item.icon);
1503
- }
1504
- // Create option element for the dropdown
1505
- var ktOption = new option_1.KTSelectOption(selectOption, _this._config);
1506
- var renderedOption = ktOption.render();
1507
1288
  // Add to dropdown container
1508
- optionsContainer.appendChild(renderedOption);
1289
+ optionsContainer.appendChild(selectOption);
1509
1290
  });
1510
1291
  // Add pagination "Load More" button if needed
1511
1292
  if (this._config.pagination && this._remoteModule.hasMorePages()) {
@@ -1514,18 +1295,178 @@ var KTSelect = /** @class */ (function (_super) {
1514
1295
  // Update options NodeList
1515
1296
  this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
1516
1297
  };
1517
- /**
1518
- * Filter options by query
1519
- */
1520
- KTSelect.prototype.filterOptions = function (query) {
1521
- this._filterOptionsForCombobox(query);
1522
- };
1523
1298
  /**
1524
1299
  * Check if dropdown is open
1525
1300
  */
1526
1301
  KTSelect.prototype.isDropdownOpen = function () {
1527
1302
  return this._dropdownIsOpen;
1528
1303
  };
1304
+ KTSelect.prototype.getSelectedOptionsText = function () {
1305
+ var _this = this;
1306
+ var selectedValues = this.getSelectedOptions();
1307
+ var displaySeparator = this._config.displaySeparator || ', ';
1308
+ var texts = selectedValues.map(function (value) {
1309
+ var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
1310
+ return (option === null || option === void 0 ? void 0 : option.getAttribute('data-text')) || '';
1311
+ }).filter(Boolean);
1312
+ return texts.join(displaySeparator);
1313
+ };
1314
+ /**
1315
+ * Check if an option is disabled (either in dropdown or original select)
1316
+ */
1317
+ KTSelect.prototype._isOptionDisabled = function (value) {
1318
+ var dropdownOption = Array.from(this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
1319
+ var isDropdownDisabled = dropdownOption && (dropdownOption.classList.contains('disabled') || dropdownOption.getAttribute('aria-disabled') === 'true');
1320
+ var selectOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
1321
+ var isNativeDisabled = selectOption && selectOption.disabled;
1322
+ return Boolean(isDropdownDisabled || isNativeDisabled);
1323
+ };
1324
+ /**
1325
+ * Centralized keyboard event handler for all select modes
1326
+ */
1327
+ KTSelect.prototype._handleKeyboardEvent = function (event) {
1328
+ // If the event target is the search input and the event was already handled (defaultPrevented),
1329
+ // then return early to avoid duplicate processing by this broader handler.
1330
+ if (event.target === this._searchInputElement && event.defaultPrevented) {
1331
+ return;
1332
+ }
1333
+ var isOpen = this._dropdownIsOpen;
1334
+ var config = this._config;
1335
+ var focusManager = this._focusManager;
1336
+ var buffer = this._typeToSearchBuffer;
1337
+ // If the event target is the search input, let it handle most typing keys naturally.
1338
+ if (event.target === this._searchInputElement) {
1339
+ // Allow navigation keys like ArrowDown, ArrowUp, Escape, Enter (for search/selection) to be handled by the logic below.
1340
+ // For other keys (characters, space, backspace, delete), let the input field process them.
1341
+ if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp' &&
1342
+ event.key !== 'Escape' && event.key !== 'Enter' && event.key !== 'Tab' &&
1343
+ event.key !== 'Home' && event.key !== 'End') {
1344
+ // If it's a character key and we are NOT type-to-searching (because search has focus)
1345
+ // then let the input field handle it for its own value.
1346
+ // The search module's 'input' event will handle filtering based on the input's value.
1347
+ buffer.clear(); // Clear type-to-search buffer when typing in search field
1348
+ return;
1349
+ }
1350
+ // For Enter specifically in search input, we might want to select the focused option or submit search.
1351
+ // This is handled later in the switch.
1352
+ }
1353
+ // Ignore modifier keys (except for specific combinations if added later)
1354
+ if (event.altKey || event.ctrlKey || event.metaKey)
1355
+ return;
1356
+ // Type-to-search: only for single char keys, when search input does not have focus
1357
+ if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/) && document.activeElement !== this._searchInputElement) {
1358
+ buffer.push(event.key);
1359
+ var str = buffer.getBuffer();
1360
+ if (isOpen) {
1361
+ focusManager.focusByString(str);
1362
+ }
1363
+ else {
1364
+ // If closed, type-to-search could potentially open and select.
1365
+ // For now, let's assume it only works when open or opens it first.
1366
+ // Or, we could find the matching option and set it directly without opening.
1367
+ }
1368
+ return; // Type-to-search handles the event
1369
+ }
1370
+ switch (event.key) {
1371
+ case 'ArrowDown':
1372
+ event.preventDefault();
1373
+ if (!isOpen) {
1374
+ this.openDropdown();
1375
+ }
1376
+ else {
1377
+ focusManager.focusNext();
1378
+ }
1379
+ break;
1380
+ case 'ArrowUp':
1381
+ event.preventDefault();
1382
+ if (!isOpen) {
1383
+ this.openDropdown();
1384
+ }
1385
+ else {
1386
+ focusManager.focusPrevious();
1387
+ }
1388
+ break;
1389
+ case 'Home':
1390
+ event.preventDefault();
1391
+ if (isOpen)
1392
+ focusManager.focusFirst();
1393
+ break;
1394
+ case 'End':
1395
+ event.preventDefault();
1396
+ if (isOpen)
1397
+ focusManager.focusLast();
1398
+ break;
1399
+ case 'Enter':
1400
+ case ' ': // Space
1401
+ if (isOpen) {
1402
+ var focusedOptionEl = this._focusManager.getFocusedOption();
1403
+ if (focusedOptionEl) {
1404
+ var val = focusedOptionEl.dataset.value;
1405
+ // If single select, and the item is already selected, just close.
1406
+ if (val !== undefined && !this._config.multiple && this._state.isSelected(val)) {
1407
+ if (this._config.debug)
1408
+ console.log('Enter on already selected item in single-select mode. Closing.');
1409
+ this.closeDropdown();
1410
+ event.preventDefault();
1411
+ break;
1412
+ }
1413
+ }
1414
+ // Proceed with selection if not handled above
1415
+ this.selectFocusedOption();
1416
+ // Close dropdown if configured to do so (for new selections)
1417
+ if (!this._config.multiple) {
1418
+ // This will also be true for the case handled above, but closeDropdown is idempotent.
1419
+ // However, the break above prevents this from being reached for that specific case.
1420
+ this.closeDropdown();
1421
+ }
1422
+ event.preventDefault(); // Prevent form submission or other default actions
1423
+ break;
1424
+ }
1425
+ else {
1426
+ this.openDropdown();
1427
+ }
1428
+ break;
1429
+ case 'Escape':
1430
+ if (isOpen) {
1431
+ this.closeDropdown();
1432
+ event.target.blur();
1433
+ }
1434
+ break;
1435
+ case 'Tab':
1436
+ // Let Tab propagate for normal focus movement
1437
+ break;
1438
+ default:
1439
+ break;
1440
+ }
1441
+ };
1442
+ KTSelect.prototype.renderDisplayTemplateForSelected = function (selectedValues) {
1443
+ var _this = this;
1444
+ var optionsConfig = this._config.optionsConfig || {};
1445
+ var displaySeparator = this._config.displaySeparator || ', ';
1446
+ var contentArray = Array.from(new Set(selectedValues.map(function (value) {
1447
+ var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
1448
+ if (!option)
1449
+ return '';
1450
+ var displayTemplate = _this._config.displayTemplate;
1451
+ var text = option.getAttribute('data-text') || '';
1452
+ // Replace all {{varname}} in option.innerHTML with values from _config
1453
+ Object.entries(optionsConfig[value] || {}).forEach(function (_a) {
1454
+ var key = _a[0], val = _a[1];
1455
+ if (["string", "number", "boolean"].includes(typeof val)) {
1456
+ displayTemplate = displayTemplate.replace(new RegExp("{{".concat(key, "}}"), 'g'), String(val));
1457
+ }
1458
+ });
1459
+ return (0, utils_1.renderTemplateString)(displayTemplate, {
1460
+ selectedCount: selectedValues.length || 0,
1461
+ selectedTexts: _this.getSelectedOptionsText() || '',
1462
+ text: text,
1463
+ });
1464
+ }).filter(Boolean)));
1465
+ return contentArray.join(displaySeparator);
1466
+ };
1467
+ KTSelect.prototype.getDisplayElement = function () {
1468
+ return this._displayElement;
1469
+ };
1529
1470
  /**
1530
1471
  * ========================================================================
1531
1472
  * STATIC METHODS