@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
package/dist/ktui.js CHANGED
@@ -21,7 +21,7 @@ return /******/ (function() { // webpackBootstrap
21
21
  * Copyright 2025 by Keenthemes Inc
22
22
  */
23
23
  Object.defineProperty(exports, "__esModule", ({ value: true }));
24
- exports.EventManager = exports.FocusManager = exports.filterOptions = exports.KTSelectDropdown = exports.KTSelectTags = exports.KTSelectSearch = exports.KTSelectCombobox = exports.KTSelectRemote = exports.KTSelect = void 0;
24
+ exports.TypeToSearchBuffer = exports.EventManager = exports.FocusManager = exports.filterOptions = exports.KTSelectDropdown = exports.KTSelectTags = exports.KTSelectSearch = exports.KTSelectCombobox = exports.KTSelectRemote = exports.KTSelect = void 0;
25
25
  var select_1 = __webpack_require__(8016);
26
26
  Object.defineProperty(exports, "KTSelect", ({ enumerable: true, get: function () { return select_1.KTSelect; } }));
27
27
  var remote_1 = __webpack_require__(3710);
@@ -38,6 +38,7 @@ var utils_1 = __webpack_require__(9011);
38
38
  Object.defineProperty(exports, "filterOptions", ({ enumerable: true, get: function () { return utils_1.filterOptions; } }));
39
39
  Object.defineProperty(exports, "FocusManager", ({ enumerable: true, get: function () { return utils_1.FocusManager; } }));
40
40
  Object.defineProperty(exports, "EventManager", ({ enumerable: true, get: function () { return utils_1.EventManager; } }));
41
+ Object.defineProperty(exports, "TypeToSearchBuffer", ({ enumerable: true, get: function () { return utils_1.TypeToSearchBuffer; } }));
41
42
 
42
43
 
43
44
  /***/ }),
@@ -3266,10 +3267,8 @@ var KTSelectRemote = /** @class */ (function () {
3266
3267
  // Get the field mapping from config with fallbacks for common field names
3267
3268
  var valueField = this._config.dataValueField || 'id';
3268
3269
  var labelField = this._config.dataFieldText || 'title';
3269
- var descriptionField = this._config.dataFieldDescription || 'description';
3270
- var iconField = this._config.dataFieldIcon || 'icon';
3271
3270
  if (this._config.debug)
3272
- console.log("Mapping fields: value=".concat(valueField, ", label=").concat(labelField, ", description=").concat(descriptionField, ", icon=").concat(iconField));
3271
+ console.log("Mapping fields: value=".concat(valueField, ", label=").concat(labelField));
3273
3272
  if (this._config.debug)
3274
3273
  console.log('Item data:', JSON.stringify(item).substring(0, 200) + '...'); // Trimmed for readability
3275
3274
  // Extract values using dot notation if needed
@@ -3360,44 +3359,10 @@ var KTSelectRemote = /** @class */ (function () {
3360
3359
  if (this._config.debug)
3361
3360
  console.log('After fallback checks, title:', title);
3362
3361
  }
3363
- // Get description - make sure we don't pass null, undefined, or "null" string values
3364
- var description = getValue(item, descriptionField);
3365
- if (description === null ||
3366
- description === undefined ||
3367
- String(description) === 'null' ||
3368
- String(description) === 'undefined') {
3369
- description = null;
3370
- }
3371
- else {
3372
- description = String(description);
3373
- }
3374
- if (this._config.debug)
3375
- console.log("Description field [".concat(descriptionField, "]:"), description);
3376
- // Try to get an icon - make sure we don't pass null, undefined, or "null" string values
3377
- var icon = getValue(item, iconField);
3378
- if (icon === null ||
3379
- icon === undefined ||
3380
- String(icon) === 'null' ||
3381
- String(icon) === 'undefined') {
3382
- icon = null;
3383
- }
3384
- else {
3385
- icon = String(icon);
3386
- }
3387
- if (this._config.debug)
3388
- console.log("Icon field [".concat(iconField, "]:"), icon);
3389
- // If ID is null, use the title as fallback
3390
- if (id === null || id === '') {
3391
- id = title;
3392
- if (this._config.debug)
3393
- console.log("Using title as fallback for ID: ".concat(id));
3394
- }
3395
3362
  // Create the option object with non-empty values
3396
3363
  var result = {
3397
3364
  id: id || title || 'id-' + Math.random().toString(36).substr(2, 9), // Ensure we always have an ID
3398
3365
  title: title || 'Unnamed option',
3399
- description: description,
3400
- icon: icon,
3401
3366
  };
3402
3367
  if (this._config.debug)
3403
3368
  console.log('Final mapped item:', JSON.stringify(result));
@@ -5688,6 +5653,17 @@ var __extends = (this && this.__extends) || (function () {
5688
5653
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
5689
5654
  };
5690
5655
  })();
5656
+ var __assign = (this && this.__assign) || function () {
5657
+ __assign = Object.assign || function(t) {
5658
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5659
+ s = arguments[i];
5660
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
5661
+ t[p] = s[p];
5662
+ }
5663
+ return t;
5664
+ };
5665
+ return __assign.apply(this, arguments);
5666
+ };
5691
5667
  Object.defineProperty(exports, "__esModule", ({ value: true }));
5692
5668
  exports.KTSelectOption = void 0;
5693
5669
  var component_1 = __webpack_require__(2658);
@@ -5700,22 +5676,61 @@ var KTSelectOption = /** @class */ (function (_super) {
5700
5676
  _this._dataOptionPrefix = 'kt-'; // Use 'kt-' prefix to support data-kt-select-option attributes
5701
5677
  // Always initialize a new option instance
5702
5678
  _this._init(element);
5703
- _this._buildConfig();
5704
5679
  _this._globalConfig = config;
5680
+ _this._buildConfig();
5681
+ // Clean the config
5682
+ _this._config = _this._config[''] || {};
5683
+ // Add the option config to the global config
5684
+ // Ensure optionsConfig is initialized
5685
+ if (_this._globalConfig) {
5686
+ _this._globalConfig.optionsConfig = _this._globalConfig.optionsConfig || {};
5687
+ _this._globalConfig.optionsConfig[element.value] = _this._config;
5688
+ }
5689
+ else {
5690
+ // Handle case where _globalConfig might be undefined, though constructor expects it.
5691
+ // This might indicate a need to ensure config is always passed or has a default.
5692
+ console.warn('KTSelectOption: _globalConfig is undefined during constructor.');
5693
+ }
5705
5694
  // Don't store in KTData to avoid Singleton pattern issues
5706
5695
  // Each option should be a unique instance
5707
5696
  element.instance = _this;
5708
5697
  return _this;
5709
5698
  }
5699
+ Object.defineProperty(KTSelectOption.prototype, "id", {
5700
+ get: function () {
5701
+ return this.getHTMLOptionElement().value;
5702
+ },
5703
+ enumerable: false,
5704
+ configurable: true
5705
+ });
5706
+ Object.defineProperty(KTSelectOption.prototype, "title", {
5707
+ get: function () {
5708
+ return this.getHTMLOptionElement().textContent || '';
5709
+ },
5710
+ enumerable: false,
5711
+ configurable: true
5712
+ });
5710
5713
  KTSelectOption.prototype.getHTMLOptionElement = function () {
5711
5714
  return this._element;
5712
5715
  };
5716
+ /**
5717
+ * Gathers all necessary data for rendering this option,
5718
+ * including standard HTML attributes and custom data-kt-* attributes.
5719
+ */
5720
+ KTSelectOption.prototype.getOptionDataForTemplate = function () {
5721
+ var el = this.getHTMLOptionElement();
5722
+ var text = el.textContent || '';
5723
+ return __assign(__assign({}, this._config), {
5724
+ // Standard HTMLOptionElement properties
5725
+ value: el.value, text: text, selected: el.selected, disabled: el.disabled,
5726
+ // Provide 'content' for convenience in templates, defaulting to text.
5727
+ // User's optionTemplate can then use {{content}} or specific fields like {{text}}, {{icon}}, etc.
5728
+ content: text });
5729
+ };
5713
5730
  KTSelectOption.prototype.render = function () {
5714
- var optionElement = this.getHTMLOptionElement();
5715
- // Use the global config if available, or create a minimal valid config
5716
- var config = this._globalConfig || { height: 250 };
5717
- // Create a new option element every time
5718
- return templates_1.defaultTemplates.option(optionElement, config);
5731
+ // 'this' is the KTSelectOption instance.
5732
+ // defaultTemplates.option will handle using this instance's data along with _globalConfig.
5733
+ return templates_1.defaultTemplates.option(this, this._globalConfig);
5719
5734
  };
5720
5735
  return KTSelectOption;
5721
5736
  }(component_1.default));
@@ -6533,31 +6548,35 @@ Object.defineProperty(exports, "KTScrollspy", ({ enumerable: true, get: function
6533
6548
  Object.defineProperty(exports, "__esModule", ({ value: true }));
6534
6549
  exports.KTSelectCombobox = void 0;
6535
6550
  var utils_1 = __webpack_require__(9011);
6551
+ var templates_1 = __webpack_require__(9069);
6536
6552
  /**
6537
6553
  * KTSelectCombobox - Handles combobox-specific functionality for KTSelect
6538
6554
  */
6539
6555
  var KTSelectCombobox = /** @class */ (function () {
6540
6556
  function KTSelectCombobox(select) {
6557
+ var _this = this;
6541
6558
  this._select = select;
6542
6559
  this._config = select.getConfig();
6543
- // Get the display element (could be the input directly or a parent div)
6544
- var displayElement = select.getValueDisplayElement();
6545
- // Find the input element - either it's the display element itself or a child
6546
- this._searchInputElement =
6547
- displayElement.tagName === 'INPUT'
6548
- ? displayElement
6549
- : displayElement.querySelector('input[data-kt-select-search]');
6550
- // Find the clear button
6551
- this._clearButtonElement =
6552
- displayElement.tagName === 'DIV'
6553
- ? displayElement.querySelector('[data-kt-select-clear-button]')
6554
- : null;
6555
- // Create bound handler references to allow proper cleanup
6556
- this._boundKeyNavHandler = this._handleComboboxKeyNav.bind(this);
6560
+ var displayElement = select.getDisplayElement(); // KTSelect's main display element for combobox
6561
+ this._searchInputElement = displayElement.querySelector('input[data-kt-select-search]');
6562
+ this._clearButtonElement = displayElement.querySelector('[data-kt-select-clear-button]');
6563
+ this._valuesContainerElement = displayElement.querySelector('[data-kt-select-combobox-values]');
6557
6564
  this._boundInputHandler = this._handleComboboxInput.bind(this);
6558
6565
  this._boundClearHandler = this._handleClearButtonClick.bind(this);
6559
- // Attach event listeners
6560
6566
  this._attachEventListeners();
6567
+ this._select.getElement().addEventListener('dropdown.close', function () {
6568
+ // When dropdown closes, if not multi-select and not using displayTemplate,
6569
+ // ensure input shows the selected value or placeholder.
6570
+ if (!_this._config.multiple && !_this._config.displayTemplate) {
6571
+ _this.updateDisplay(_this._select.getSelectedOptions());
6572
+ }
6573
+ else {
6574
+ // For tags or displayTemplate, the input should be clear for typing.
6575
+ _this._searchInputElement.value = '';
6576
+ }
6577
+ _this._toggleClearButtonVisibility(_this._searchInputElement.value);
6578
+ // this._select.showAllOptions(); // showAllOptions might be too broad, filtering is managed by typing.
6579
+ });
6561
6580
  if (this._config.debug)
6562
6581
  console.log('KTSelectCombobox initialized');
6563
6582
  }
@@ -6565,18 +6584,13 @@ var KTSelectCombobox = /** @class */ (function () {
6565
6584
  * Attach event listeners specific to combobox
6566
6585
  */
6567
6586
  KTSelectCombobox.prototype._attachEventListeners = function () {
6568
- // First remove any existing listeners to prevent duplicates
6569
6587
  this._removeEventListeners();
6570
- // Add input event handler to filter options as user types
6571
- this._searchInputElement.addEventListener('input', this._boundInputHandler);
6572
- // Add keyboard navigation for the combobox
6573
- this._searchInputElement.addEventListener('keydown', this._boundKeyNavHandler);
6574
- // Add clear button click event listener
6588
+ if (this._searchInputElement) { // Ensure element exists
6589
+ this._searchInputElement.addEventListener('input', this._boundInputHandler);
6590
+ }
6575
6591
  if (this._clearButtonElement) {
6576
6592
  this._clearButtonElement.addEventListener('click', this._boundClearHandler);
6577
6593
  }
6578
- if (this._config.debug)
6579
- console.log('Combobox event listeners attached to:', this._searchInputElement);
6580
6594
  };
6581
6595
  /**
6582
6596
  * Remove event listeners to prevent memory leaks or duplicates
@@ -6584,7 +6598,6 @@ var KTSelectCombobox = /** @class */ (function () {
6584
6598
  KTSelectCombobox.prototype._removeEventListeners = function () {
6585
6599
  if (this._searchInputElement) {
6586
6600
  this._searchInputElement.removeEventListener('input', this._boundInputHandler);
6587
- this._searchInputElement.removeEventListener('keydown', this._boundKeyNavHandler);
6588
6601
  }
6589
6602
  if (this._clearButtonElement) {
6590
6603
  this._clearButtonElement.removeEventListener('click', this._boundClearHandler);
@@ -6595,16 +6608,21 @@ var KTSelectCombobox = /** @class */ (function () {
6595
6608
  */
6596
6609
  KTSelectCombobox.prototype._handleComboboxInput = function (event) {
6597
6610
  var inputElement = event.target;
6598
- var query = inputElement.value.toLowerCase();
6599
- if (this._config.debug)
6600
- console.log('Combobox input event, query:', query);
6601
- // Toggle clear button visibility based on input value
6611
+ var query = inputElement.value;
6602
6612
  this._toggleClearButtonVisibility(query);
6603
- // If dropdown isn't open, open it when user starts typing
6604
- if (!this._select._dropdownIsOpen) {
6613
+ if (!this._select.isDropdownOpen()) { // Use public getter
6605
6614
  this._select.openDropdown();
6606
6615
  }
6607
- // Filter options based on input
6616
+ // For single select without displayTemplate, if user types, they are essentially clearing the previous selection text
6617
+ // The actual selection state isn't cleared until they pick a new option or clear explicitly.
6618
+ // For multi-select or with displayTemplate, the input is purely for search.
6619
+ if (this._config.multiple || this._config.displayTemplate) {
6620
+ // Values are in _valuesContainerElement, input is for search
6621
+ }
6622
+ else {
6623
+ // Single select, no displayTemplate: If user types, it implies they might be changing selection.
6624
+ // We don't clear the actual _select state here, just the visual in input.
6625
+ }
6608
6626
  this._filterOptionsForCombobox(query);
6609
6627
  };
6610
6628
  /**
@@ -6613,25 +6631,25 @@ var KTSelectCombobox = /** @class */ (function () {
6613
6631
  KTSelectCombobox.prototype._handleClearButtonClick = function (event) {
6614
6632
  event.preventDefault();
6615
6633
  event.stopPropagation();
6616
- // Clear the input
6617
6634
  this._searchInputElement.value = '';
6618
- // Hide the clear button
6619
6635
  this._toggleClearButtonVisibility('');
6620
- // Show all options and open dropdown
6621
- this._select.showAllOptions();
6636
+ if (this._valuesContainerElement) {
6637
+ this._valuesContainerElement.innerHTML = '';
6638
+ }
6639
+ this._select.clearSelection(); // This will also trigger updateSelectedOptionDisplay
6640
+ this._select.showAllOptions(); // Show all options after clearing
6622
6641
  this._select.openDropdown();
6623
- // Clear the current selection
6624
- this._select.clearSelection();
6625
- // Focus on the input
6626
6642
  this._searchInputElement.focus();
6627
6643
  };
6628
6644
  /**
6629
- * Toggle clear button visibility based on input value
6645
+ * Toggle clear button visibility based on input value and selection state.
6646
+ * Clear button should be visible if there's text in input OR if there are selected items (for multi/displayTemplate modes).
6630
6647
  */
6631
- KTSelectCombobox.prototype._toggleClearButtonVisibility = function (value) {
6648
+ KTSelectCombobox.prototype._toggleClearButtonVisibility = function (inputValue) {
6632
6649
  if (!this._clearButtonElement)
6633
6650
  return;
6634
- if (value.length > 0) {
6651
+ var hasSelectedItems = this._select.getSelectedOptions().length > 0;
6652
+ if (inputValue.length > 0 || (hasSelectedItems && (this._config.multiple || this._config.displayTemplate))) {
6635
6653
  this._clearButtonElement.classList.remove('hidden');
6636
6654
  }
6637
6655
  else {
@@ -6642,115 +6660,65 @@ var KTSelectCombobox = /** @class */ (function () {
6642
6660
  * Filter options for combobox based on input query
6643
6661
  */
6644
6662
  KTSelectCombobox.prototype._filterOptionsForCombobox = function (query) {
6645
- // Access the private method through type assertion
6646
- this._select._filterOptionsForCombobox(query);
6663
+ var options = Array.from(this._select.getOptionsElement());
6664
+ var config = this._select.getConfig();
6665
+ var dropdownElement = this._select.getDropdownElement();
6666
+ (0, utils_1.filterOptions)(options, query, config, dropdownElement);
6667
+ // After filtering, focusManager in KTSelectSearch (if search is also enabled there)
6668
+ // or the main FocusManager should adjust focus if needed.
6669
+ // For combobox, this filtering is the primary search mechanism.
6670
+ // We might need to tell select's focus manager to focus first option.
6671
+ this._select._focusManager.focusFirst(); // Consider if this is always right
6647
6672
  };
6648
6673
  /**
6649
- * Handle keyboard navigation in combobox mode
6674
+ * Updates the combobox display (input field or values container) based on selection.
6650
6675
  */
6651
- KTSelectCombobox.prototype._handleComboboxKeyNav = function (event) {
6652
- if (this._config.debug)
6653
- console.log('Combobox keydown event:', event.key);
6654
- // Prevent event propagation to stop bubbling to other handlers
6655
- event.stopPropagation();
6656
- // Handle clear with Escape when dropdown is closed
6657
- if (event.key === 'Escape' &&
6658
- !this._select._dropdownIsOpen &&
6659
- this._searchInputElement.value !== '') {
6660
- event.preventDefault();
6661
- this._searchInputElement.value = '';
6662
- this._toggleClearButtonVisibility('');
6663
- this._select.clearSelection();
6664
- return;
6665
- }
6666
- // Handle dropdown visibility with special keys
6667
- if (!this._select._dropdownIsOpen &&
6668
- (event.key === 'ArrowDown' ||
6669
- event.key === 'ArrowUp' ||
6670
- event.key === 'Enter')) {
6671
- if (this._config.debug)
6672
- console.log('Opening dropdown from keyboard in combobox');
6673
- this._select.openDropdown();
6674
- event.preventDefault();
6675
- // If it's arrow keys, also move focus
6676
- if (event.key === 'ArrowDown') {
6677
- this._select._focusNextOption();
6678
- }
6679
- else if (event.key === 'ArrowUp') {
6680
- this._select._focusPreviousOption();
6681
- }
6676
+ KTSelectCombobox.prototype.updateDisplay = function (selectedOptions) {
6677
+ var _this = this;
6678
+ if (!this._searchInputElement)
6682
6679
  return;
6683
- }
6684
- // Use the shared keyboard navigation handler
6685
- (0, utils_1.handleDropdownKeyNavigation)(event, this._select, {
6686
- multiple: this._config.multiple,
6687
- closeOnSelect: this._config.closeOnSelect,
6688
- });
6689
- };
6690
- /**
6691
- * Update the combobox input value when an option is selected
6692
- */
6693
- KTSelectCombobox.prototype.updateSelectedValue = function (selectedText) {
6694
- if (this._searchInputElement) {
6695
- // Extract just the text content if it contains HTML
6696
- var cleanText = selectedText;
6697
- // If the text might contain HTML (when description is present)
6698
- if (selectedText.includes('<') || selectedText.includes('>')) {
6699
- // Create a temporary element to extract just the text
6700
- var tempDiv = document.createElement('div');
6701
- tempDiv.innerHTML = selectedText;
6702
- // Find and use only the option-title text if available
6703
- var titleElement = tempDiv.querySelector('[data-kt-option-title]');
6704
- if (titleElement) {
6705
- cleanText = titleElement.textContent || selectedText;
6706
- }
6707
- else {
6708
- // Fallback to all text content if option-title not found
6709
- cleanText = tempDiv.textContent || selectedText;
6680
+ // Always clear the values container first if it exists
6681
+ if (this._valuesContainerElement) {
6682
+ this._valuesContainerElement.innerHTML = '';
6683
+ }
6684
+ if (this._config.tags && this._valuesContainerElement) { // Combobox + Tags
6685
+ selectedOptions.forEach(function (value) {
6686
+ // Ensure value is properly escaped for querySelector
6687
+ var optionElement = _this._select.getElement().querySelector("option[value=\"".concat(CSS.escape(value), "\"]"));
6688
+ if (optionElement) {
6689
+ var tagElement = templates_1.defaultTemplates.tag(optionElement, _this._config);
6690
+ _this._valuesContainerElement.appendChild(tagElement);
6710
6691
  }
6711
- }
6712
- // Set the input value directly for immediate feedback
6713
- this._searchInputElement.value = cleanText;
6714
- // Show the clear button if there's a value
6715
- this._toggleClearButtonVisibility(cleanText);
6716
- // Trigger an input event to ensure any input-based listeners are notified
6717
- var inputEvent = new Event('input', { bubbles: true });
6718
- this._searchInputElement.dispatchEvent(inputEvent);
6719
- if (this._config.debug)
6720
- console.log('Combobox value updated to:', cleanText);
6692
+ });
6693
+ this._searchInputElement.value = ''; // Input field is for typing new searches
6694
+ this._searchInputElement.placeholder = selectedOptions.length > 0 ? '' : (this._config.placeholder || 'Select...');
6695
+ }
6696
+ else if (this._config.displayTemplate && this._valuesContainerElement) { // Combobox + DisplayTemplate (no tags)
6697
+ this._valuesContainerElement.innerHTML = this._select.renderDisplayTemplateForSelected(selectedOptions);
6698
+ this._searchInputElement.value = ''; // Input field is for typing new searches
6699
+ this._searchInputElement.placeholder = selectedOptions.length > 0 ? '' : (this._config.placeholder || 'Select...');
6700
+ }
6701
+ else if (this._config.multiple && this._valuesContainerElement) { // Combobox + Multiple (no tags, no display template)
6702
+ // For simplicity, join text. A proper tag implementation would be more complex here.
6703
+ this._valuesContainerElement.innerHTML = selectedOptions.map(function (value) {
6704
+ var optionEl = _this._select.getElement().querySelector("option[value=\"".concat(CSS.escape(value), "\"]"));
6705
+ return optionEl ? optionEl.textContent : '';
6706
+ }).join(', '); // Basic comma separation
6707
+ this._searchInputElement.value = '';
6708
+ this._searchInputElement.placeholder = selectedOptions.length > 0 ? '' : (this._config.placeholder || 'Select...');
6721
6709
  }
6722
- };
6723
- /**
6724
- * Reset the input value to match the current selection
6725
- * This can be called to sync the input with the current state
6726
- */
6727
- KTSelectCombobox.prototype.resetInputValueToSelection = function () {
6728
- var _a, _b;
6729
- var selectedOptions = this._select.getSelectedOptions();
6730
- if (selectedOptions.length > 0) {
6731
- var selectedOption = Array.from(this._select.getOptionsElement()).find(function (opt) { return opt.dataset.value === selectedOptions[0]; });
6732
- if (selectedOption) {
6733
- // Find the option-title element to get just the title text
6734
- var titleElement = selectedOption.querySelector('[data-kt-option-title]');
6735
- var selectedText = '';
6736
- if (titleElement) {
6737
- // If it has a structured content with a title element
6738
- selectedText = ((_a = titleElement.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || '';
6739
- }
6740
- else {
6741
- // Fallback to the whole text content
6742
- selectedText = ((_b = selectedOption.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || '';
6743
- }
6744
- this.updateSelectedValue(selectedText);
6745
- }
6710
+ else if (!this._config.multiple && selectedOptions.length > 0) { // Single select combobox: display selected option's text in the input
6711
+ var selectedValue = selectedOptions[0];
6712
+ var optionElement = this._select.getElement().querySelector("option[value=\"".concat(CSS.escape(selectedValue), "\"]"));
6713
+ this._searchInputElement.value = optionElement ? optionElement.textContent || '' : '';
6714
+ // placeholder is implicitly handled by input value for single select
6746
6715
  }
6747
- else {
6748
- // No selection, clear the input
6749
- if (this._searchInputElement) {
6750
- this._searchInputElement.value = '';
6751
- this._toggleClearButtonVisibility('');
6752
- }
6716
+ else { // No selection or not fitting above categories (e.g. single select, no items)
6717
+ this._searchInputElement.value = '';
6718
+ this._searchInputElement.placeholder = this._config.placeholder || 'Select...';
6719
+ // _valuesContainerElement is already cleared if it exists
6753
6720
  }
6721
+ this._toggleClearButtonVisibility(this._searchInputElement.value);
6754
6722
  };
6755
6723
  /**
6756
6724
  * Destroy the combobox component and clean up event listeners
@@ -7169,6 +7137,22 @@ var stepper_1 = __webpack_require__(770);
7169
7137
  Object.defineProperty(exports, "KTStepper", ({ enumerable: true, get: function () { return stepper_1.KTStepper; } }));
7170
7138
 
7171
7139
 
7140
+ /***/ }),
7141
+
7142
+ /***/ 6265:
7143
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
7144
+
7145
+
7146
+ /**
7147
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
7148
+ * Copyright 2025 by Keenthemes Inc
7149
+ */
7150
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
7151
+ exports.KTToast = void 0;
7152
+ var toast_1 = __webpack_require__(8834);
7153
+ Object.defineProperty(exports, "KTToast", ({ enumerable: true, get: function () { return toast_1.KTToast; } }));
7154
+
7155
+
7172
7156
  /***/ }),
7173
7157
 
7174
7158
  /***/ 6292:
@@ -7627,6 +7611,7 @@ var KTDataTable = /** @class */ (function (_super) {
7627
7611
  _this._originalTdClasses = []; // Store original td classes as a 2D array [row][col]
7628
7612
  _this._originalThClasses = []; // Store original th classes
7629
7613
  _this._data = [];
7614
+ _this._isFetching = false;
7630
7615
  if (data_1.default.has(element, _this._name))
7631
7616
  return _this;
7632
7617
  _this._defaultConfig = _this._initDefaultConfig(config);
@@ -7930,11 +7915,21 @@ var KTDataTable = /** @class */ (function (_super) {
7930
7915
  KTDataTable.prototype._updateData = function () {
7931
7916
  return __awaiter(this, void 0, void 0, function () {
7932
7917
  return __generator(this, function (_a) {
7933
- this._showSpinner(); // Show spinner before fetching data
7934
- // Fetch data from the DOM and initialize the checkbox plugin
7935
- return [2 /*return*/, typeof this._config.apiEndpoint === 'undefined'
7936
- ? this._fetchDataFromLocal().then(this._finalize.bind(this))
7937
- : this._fetchDataFromServer().then(this._finalize.bind(this))];
7918
+ if (this._isFetching)
7919
+ return [2 /*return*/]; // Prevent duplicate fetches
7920
+ this._isFetching = true;
7921
+ try {
7922
+ this._showSpinner(); // Show spinner before fetching data
7923
+ // Fetch data from the DOM and initialize the checkbox plugin
7924
+ return [2 /*return*/, typeof this._config.apiEndpoint === 'undefined'
7925
+ ? this._fetchDataFromLocal().then(this._finalize.bind(this))
7926
+ : this._fetchDataFromServer().then(this._finalize.bind(this))];
7927
+ }
7928
+ finally {
7929
+ this._isFetching = false;
7930
+ }
7931
+ // removed by dead control flow
7932
+ {}
7938
7933
  });
7939
7934
  });
7940
7935
  };
@@ -7968,7 +7963,7 @@ var KTDataTable = /** @class */ (function (_super) {
7968
7963
  // Set search value
7969
7964
  if (searchElement) {
7970
7965
  searchElement.value =
7971
- typeof search === 'string' ? search : String(search);
7966
+ search === undefined || search === null ? '' : typeof search === 'string' ? search : String(search);
7972
7967
  }
7973
7968
  if (searchElement) {
7974
7969
  // Check if a debounced search function already exists
@@ -8374,7 +8369,13 @@ var KTDataTable = /** @class */ (function (_super) {
8374
8369
  td.className = _this._originalTdClasses[rowIndex][colIndex];
8375
8370
  }
8376
8371
  if (typeof columnDef.render === 'function') {
8377
- td.innerHTML = columnDef.render.call(_this, item[key], item, _this);
8372
+ var result = columnDef.render.call(_this, item[key], item, _this);
8373
+ if (result instanceof HTMLElement || result instanceof DocumentFragment) {
8374
+ td.appendChild(result);
8375
+ }
8376
+ else if (typeof result === 'string') {
8377
+ td.innerHTML = result;
8378
+ }
8378
8379
  }
8379
8380
  else {
8380
8381
  td.textContent = item[key];
@@ -9284,7 +9285,7 @@ var utils_1 = __webpack_require__(9011);
9284
9285
  *
9285
9286
  * A specialized dropdown implementation for the KTSelect component.
9286
9287
  * This module handles the dropdown functionality for the select component,
9287
- * including positioning, showing/hiding, and keyboard navigation.
9288
+ * including positioning and showing/hiding.
9288
9289
  */
9289
9290
  var KTSelectDropdown = /** @class */ (function (_super) {
9290
9291
  __extends(KTSelectDropdown, _super);
@@ -9295,7 +9296,7 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9295
9296
  * @param dropdownElement The dropdown content element
9296
9297
  * @param config The configuration options
9297
9298
  */
9298
- function KTSelectDropdown(element, toggleElement, dropdownElement, config) {
9299
+ function KTSelectDropdown(element, toggleElement, dropdownElement, config, ktSelectInstance) {
9299
9300
  var _this = _super.call(this) || this;
9300
9301
  _this._name = 'select-dropdown';
9301
9302
  // State
@@ -9306,6 +9307,7 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9306
9307
  _this._toggleElement = toggleElement;
9307
9308
  _this._dropdownElement = dropdownElement;
9308
9309
  _this._config = config;
9310
+ _this._ktSelectInstance = ktSelectInstance; // Assign instance
9309
9311
  _this._eventManager = new utils_1.EventManager();
9310
9312
  _this._focusManager = new utils_1.FocusManager(dropdownElement, '[data-kt-select-option]', config);
9311
9313
  _this._setupEventListeners();
@@ -9317,8 +9319,6 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9317
9319
  KTSelectDropdown.prototype._setupEventListeners = function () {
9318
9320
  // Toggle click
9319
9321
  this._eventManager.addListener(this._toggleElement, 'click', this._handleToggleClick.bind(this));
9320
- // Keyboard navigation
9321
- this._eventManager.addListener(this._element, 'keydown', this._handleKeyDown.bind(this));
9322
9322
  // Close on outside click
9323
9323
  this._eventManager.addListener(document, 'click', this._handleOutsideClick.bind(this));
9324
9324
  };
@@ -9328,47 +9328,17 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9328
9328
  KTSelectDropdown.prototype._handleToggleClick = function (event) {
9329
9329
  event.preventDefault();
9330
9330
  event.stopPropagation();
9331
- this.toggle();
9332
- };
9333
- /**
9334
- * Handle keyboard events
9335
- */
9336
- KTSelectDropdown.prototype._handleKeyDown = function (event) {
9337
- if (!this._isOpen)
9331
+ if (this._config.disabled) {
9332
+ if (this._config.debug)
9333
+ console.log('KTSelectDropdown._handleToggleClick: select is disabled');
9338
9334
  return;
9339
- switch (event.key) {
9340
- case 'Escape':
9341
- event.preventDefault();
9342
- this.close();
9343
- this._toggleElement.focus();
9344
- break;
9345
- case 'ArrowDown':
9346
- event.preventDefault();
9347
- this._focusManager.focusNext();
9348
- break;
9349
- case 'ArrowUp':
9350
- event.preventDefault();
9351
- this._focusManager.focusPrevious();
9352
- break;
9353
- case 'Home':
9354
- event.preventDefault();
9355
- // Focus first visible option
9356
- var firstOption = this._focusManager.getVisibleOptions()[0];
9357
- if (firstOption) {
9358
- this._focusManager.applyFocus(firstOption);
9359
- this._focusManager.scrollIntoView(firstOption);
9360
- }
9361
- break;
9362
- case 'End':
9363
- event.preventDefault();
9364
- // Focus last visible option
9365
- var visibleOptions = this._focusManager.getVisibleOptions();
9366
- var lastOption = visibleOptions[visibleOptions.length - 1];
9367
- if (lastOption) {
9368
- this._focusManager.applyFocus(lastOption);
9369
- this._focusManager.scrollIntoView(lastOption);
9370
- }
9371
- break;
9335
+ }
9336
+ // Call KTSelect's methods
9337
+ if (this._ktSelectInstance.isDropdownOpen()) {
9338
+ this._ktSelectInstance.closeDropdown();
9339
+ }
9340
+ else {
9341
+ this._ktSelectInstance.openDropdown();
9372
9342
  }
9373
9343
  };
9374
9344
  /**
@@ -9380,7 +9350,8 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9380
9350
  var target = event.target;
9381
9351
  if (!this._element.contains(target) &&
9382
9352
  !this._dropdownElement.contains(target)) {
9383
- this.close();
9353
+ // Call KTSelect's closeDropdown method
9354
+ this._ktSelectInstance.closeDropdown();
9384
9355
  }
9385
9356
  };
9386
9357
  /**
@@ -9482,102 +9453,53 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9482
9453
  this._popperInstance.update();
9483
9454
  }
9484
9455
  };
9485
- /**
9486
- * Toggle the dropdown
9487
- */
9488
- KTSelectDropdown.prototype.toggle = function () {
9489
- if (this._config.debug)
9490
- console.log('KTSelectDropdown.toggle called - isOpen:', this._isOpen);
9491
- if (this._isTransitioning) {
9492
- if (this._config.debug)
9493
- console.log('KTSelectDropdown.toggle - ignoring during transition');
9494
- return;
9495
- }
9496
- if (this._isOpen) {
9497
- this.close();
9498
- }
9499
- else {
9500
- this.open();
9501
- }
9502
- };
9503
9456
  /**
9504
9457
  * Open the dropdown
9505
9458
  */
9506
9459
  KTSelectDropdown.prototype.open = function () {
9507
9460
  var _this = this;
9508
- if (this._isOpen || this._isTransitioning)
9461
+ if (this._config.disabled) {
9462
+ if (this._config.debug)
9463
+ console.log('KTSelectDropdown.open: select is disabled, not opening');
9509
9464
  return;
9510
- // Fire before show event
9511
- var beforeShowEvent = new CustomEvent('kt.select.dropdown.show', {
9512
- bubbles: true,
9513
- cancelable: true,
9514
- });
9515
- this._element.dispatchEvent(beforeShowEvent);
9516
- if (beforeShowEvent.defaultPrevented)
9465
+ }
9466
+ if (this._isOpen || this._isTransitioning)
9517
9467
  return;
9518
9468
  // Begin opening transition
9519
9469
  this._isTransitioning = true;
9520
- // Set initial styles - remove display: block and use class toggling instead
9470
+ // Set initial styles
9521
9471
  this._dropdownElement.classList.remove('hidden');
9522
9472
  this._dropdownElement.style.opacity = '0';
9523
9473
  // Set dropdown width
9524
9474
  this._setDropdownWidth();
9525
- // Make sure the element is visible for transitioning
9475
+ // Reflow
9526
9476
  dom_1.default.reflow(this._dropdownElement);
9527
- // Apply z-index if configured
9477
+ // Apply z-index
9528
9478
  if (this._config.dropdownZindex) {
9529
9479
  this._dropdownElement.style.zIndex =
9530
9480
  this._config.dropdownZindex.toString();
9531
9481
  }
9532
9482
  else {
9533
- // Auto-calculate z-index
9534
9483
  var parentZindex = dom_1.default.getHighestZindex(this._element);
9535
9484
  if (parentZindex) {
9536
9485
  this._dropdownElement.style.zIndex = (parentZindex + 1).toString();
9537
9486
  }
9538
9487
  }
9539
- // Initialize popper for positioning
9488
+ // Initialize popper
9540
9489
  this._initPopper();
9541
- // Add active classes
9490
+ // Add active classes for visual state
9542
9491
  this._dropdownElement.classList.add('open');
9543
9492
  this._toggleElement.classList.add('active');
9544
- this._toggleElement.setAttribute('aria-expanded', 'true');
9493
+ // ARIA attributes will be handled by KTSelect
9545
9494
  // Start transition
9546
9495
  this._dropdownElement.style.opacity = '1';
9547
9496
  // Handle transition end
9548
9497
  dom_1.default.transitionEnd(this._dropdownElement, function () {
9549
9498
  _this._isTransitioning = false;
9550
9499
  _this._isOpen = true;
9551
- // Focus the first item if search is enabled
9552
- if (_this._config.enableSearch) {
9553
- var searchInput = _this._dropdownElement.querySelector('input[type="search"]');
9554
- if (searchInput) {
9555
- searchInput.focus();
9556
- }
9557
- else {
9558
- _this._focusFirstOption();
9559
- }
9560
- }
9561
- else {
9562
- _this._focusFirstOption();
9563
- }
9564
- // Fire after show event
9565
- var afterShowEvent = new CustomEvent('kt.select.dropdown.shown', {
9566
- bubbles: true,
9567
- });
9568
- _this._element.dispatchEvent(afterShowEvent);
9500
+ // Focus and events will be handled by KTSelect
9569
9501
  });
9570
9502
  };
9571
- /**
9572
- * Focus the first option in the dropdown
9573
- */
9574
- KTSelectDropdown.prototype._focusFirstOption = function () {
9575
- var firstOption = this._focusManager.getVisibleOptions()[0];
9576
- if (firstOption) {
9577
- this._focusManager.applyFocus(firstOption);
9578
- this._focusManager.scrollIntoView(firstOption);
9579
- }
9580
- };
9581
9503
  /**
9582
9504
  * Close the dropdown
9583
9505
  */
@@ -9590,34 +9512,19 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9590
9512
  console.log('KTSelectDropdown.close - early return: dropdown not open or is transitioning');
9591
9513
  return;
9592
9514
  }
9593
- // Fire before hide event
9594
- var beforeHideEvent = new CustomEvent('kt.select.dropdown.hide', {
9595
- bubbles: true,
9596
- cancelable: true,
9597
- });
9598
- this._element.dispatchEvent(beforeHideEvent);
9599
- if (beforeHideEvent.defaultPrevented) {
9600
- if (this._config.debug)
9601
- console.log('KTSelectDropdown.close - canceling due to defaultPrevented on beforeHideEvent');
9602
- return;
9603
- }
9515
+ // Events and ARIA will be handled by KTSelect
9604
9516
  if (this._config.debug)
9605
9517
  console.log('KTSelectDropdown.close - starting transition');
9606
- // Begin closing transition
9607
9518
  this._isTransitioning = true;
9608
- // Start transition
9609
9519
  this._dropdownElement.style.opacity = '0';
9610
- // Use a combination of transition end and a fallback timer
9611
9520
  var transitionComplete = false;
9612
- // Set a fixed-duration fallback in case the transition event doesn't fire
9613
9521
  var fallbackTimer = setTimeout(function () {
9614
9522
  if (!transitionComplete) {
9615
9523
  if (_this._config.debug)
9616
9524
  console.log('KTSelectDropdown.close - fallback timer triggered');
9617
9525
  completeTransition();
9618
9526
  }
9619
- }, 300); // 300ms should be enough for most transitions
9620
- // Setup the transition end function
9527
+ }, 300);
9621
9528
  var completeTransition = function () {
9622
9529
  if (transitionComplete)
9623
9530
  return;
@@ -9625,30 +9532,21 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9625
9532
  clearTimeout(fallbackTimer);
9626
9533
  if (_this._config.debug)
9627
9534
  console.log('KTSelectDropdown.close - transition ended');
9628
- // Remove active classes
9629
9535
  _this._dropdownElement.classList.add('hidden');
9630
9536
  _this._dropdownElement.classList.remove('open');
9631
9537
  _this._toggleElement.classList.remove('active');
9632
- _this._toggleElement.setAttribute('aria-expanded', 'false');
9633
- // Reset styles - replace display: none with adding hidden class
9634
- _this._dropdownElement.classList.add('hidden');
9635
- _this._dropdownElement.style.opacity = '';
9636
- _this._dropdownElement.style.zIndex = '';
9637
- // Destroy popper
9538
+ // ARIA attributes will be handled by KTSelect
9638
9539
  _this._destroyPopper();
9639
- // Update state
9640
9540
  _this._isTransitioning = false;
9641
9541
  _this._isOpen = false;
9642
- // Fire after hide event
9643
- var afterHideEvent = new CustomEvent('kt.select.dropdown.hidden', {
9644
- bubbles: true,
9645
- });
9646
- _this._element.dispatchEvent(afterHideEvent);
9542
+ // Events will be handled by KTSelect
9647
9543
  if (_this._config.debug)
9648
- console.log('KTSelectDropdown.close - complete, events fired');
9544
+ console.log('KTSelectDropdown.close - visual part complete');
9649
9545
  };
9650
- // Handle transition end via the utility but also have the fallback
9651
9546
  dom_1.default.transitionEnd(this._dropdownElement, completeTransition);
9547
+ if (dom_1.default.getCssProp(this._dropdownElement, 'transition-duration') === '0s') {
9548
+ completeTransition();
9549
+ }
9652
9550
  };
9653
9551
  /**
9654
9552
  * Check if dropdown is open
@@ -10003,7 +9901,6 @@ var KTSelectSearch = /** @class */ (function () {
10003
9901
  this._searchInput = select.getSearchInput();
10004
9902
  this._eventManager = new utils_1.EventManager();
10005
9903
  this._focusManager = new utils_1.FocusManager(this._select.getDropdownElement(), '[data-kt-select-option]', select.getConfig());
10006
- this._boundKeyNavHandler = this._handleKeyboardNavigation.bind(this);
10007
9904
  this.handleSearchInput = this._handleSearchInput.bind(this);
10008
9905
  this._config = select.getConfig();
10009
9906
  this._cacheOriginalOptionContents();
@@ -10017,15 +9914,17 @@ var KTSelectSearch = /** @class */ (function () {
10017
9914
  console.log('Initializing search module with input:', this._searchInput);
10018
9915
  // First remove any existing listeners to prevent duplicates
10019
9916
  this._removeEventListeners();
10020
- // Add the event listener
9917
+ // Add the input event listener for filtering
10021
9918
  this._eventManager.addListener(this._searchInput, 'input', this.handleSearchInput);
9919
+ // Add keydown event listener for navigation, selection, and escape
9920
+ this._eventManager.addListener(this._searchInput, 'keydown', this._handleSearchKeyDown.bind(this));
10022
9921
  // Add blur event listener to ensure highlights are cleared when focus is lost
10023
9922
  this._eventManager.addListener(this._searchInput, 'blur', function () {
10024
9923
  // Small delay to prevent race conditions with selection
10025
9924
  setTimeout(function () {
10026
9925
  if (!_this._searchInput.value) {
10027
9926
  _this._resetAllOptions();
10028
- _this.clearSearchHighlights();
9927
+ _this.clearSearch();
10029
9928
  }
10030
9929
  }, 100);
10031
9930
  });
@@ -10043,47 +9942,48 @@ var KTSelectSearch = /** @class */ (function () {
10043
9942
  _this.refreshOptionCache();
10044
9943
  });
10045
9944
  }
10046
- // Add keyboard navigation for search results
10047
- // This is stopping event propagation to prevent conflicts
10048
- this._eventManager.addListener(this._searchInput, 'keydown', this._boundKeyNavHandler);
10049
- // Listen for dropdown close to reset options if search is empty
10050
- this._select.getElement().addEventListener('dropdown.close', function () {
9945
+ // Listen for dropdown close to reset options - ATTACH TO WRAPPER
9946
+ this._select.getWrapperElement().addEventListener('dropdown.close', function () {
10051
9947
  _this._focusManager.resetFocus();
10052
- // Always clear highlights when dropdown closes
10053
- _this.clearSearchHighlights();
10054
- if (!_this._searchInput.value) {
10055
- _this._resetAllOptions();
10056
- }
10057
- // Clear the search input when dropdown closes if configured
10058
- if (_this._select.getConfig().clearSearchOnClose) {
10059
- _this._searchInput.value = '';
10060
- }
9948
+ // If clearSearchOnClose is false and there's a value, the search term and filtered state should persist.
9949
+ // KTSelect's closeDropdown method already calls this._searchModule.clearSearch() (which clears highlights)
9950
+ // and conditionally clears the input value based on KTSelect's config.clearSearchOnClose.
9951
+ // This listener in search.ts seems to unconditionally clear everything.
9952
+ // For now, keeping its original behavior:
9953
+ _this.clearSearch(); // Clears highlights from current options
9954
+ _this._searchInput.value = ''; // Clears the search input field
9955
+ _this._resetAllOptions(); // Shows all options, restores original text, removes highlights
9956
+ _this._clearNoResultsMessage(); // Clears any "no results" message
10061
9957
  });
10062
- // Clear highlights when an option is selected
9958
+ // Clear highlights when an option is selected - ATTACH TO ORIGINAL SELECT (standard 'change' event)
10063
9959
  this._select.getElement().addEventListener('change', function () {
10064
- _this.clearSearchHighlights();
9960
+ _this.clearSearch();
10065
9961
  // Close dropdown if configured to do so
10066
- if (_this._select.getConfig().closeOnSelect &&
10067
- !_this._select.getConfig().multiple) {
10068
- _this._select.closeDropdown();
10069
- }
9962
+ _this._select.closeDropdown();
10070
9963
  });
10071
- // Autofocus on search input
10072
- if (this._select.getConfig().searchAutofocus) {
10073
- this._select.getElement().addEventListener('dropdown.show', function () {
9964
+ // Consolidated 'dropdown.show' event listener - ATTACH TO WRAPPER
9965
+ this._select.getWrapperElement().addEventListener('dropdown.show', function () {
9966
+ var _a;
9967
+ _this._focusManager.resetFocus(); // Always clear previous focus state
9968
+ if ((_a = _this._searchInput) === null || _a === void 0 ? void 0 : _a.value) {
9969
+ // If there's an existing search term:
9970
+ // 1. Re-filter options. This ensures the display (hidden/visible) is correct
9971
+ // and "no results" message is handled if query yields nothing.
9972
+ _this._filterOptions(_this._searchInput.value);
9973
+ }
9974
+ else {
9975
+ // If search input is empty:
9976
+ // 1. Reset all options to their full, unfiltered, original state.
9977
+ _this._resetAllOptions(); // Shows all, clears highlights from options, restores original text
9978
+ // 2. Clear any "no results" message.
9979
+ _this._clearNoResultsMessage();
9980
+ }
9981
+ // Handle autofocus for the search input (this was one of the original separate listeners)
9982
+ if (_this._select.getConfig().searchAutofocus) {
10074
9983
  setTimeout(function () {
10075
9984
  var _a;
10076
- // Add slight delay to ensure the dropdown and search input are visible
10077
- (_a = _this._searchInput) === null || _a === void 0 ? void 0 : _a.focus();
10078
- }, 50);
10079
- });
10080
- }
10081
- // Listen for explicit dropdown open event to clear highlights if needed
10082
- this._select.getElement().addEventListener('dropdown.show', function () {
10083
- var _a;
10084
- // If search input is empty, ensure highlights are cleared on open
10085
- if (!((_a = _this._searchInput) === null || _a === void 0 ? void 0 : _a.value)) {
10086
- _this.clearSearchHighlights();
9985
+ (_a = _this._searchInput) === null || _a === void 0 ? void 0 : _a.focus(); // Focus search input
9986
+ }, 50); // Delay to ensure dropdown is visible
10087
9987
  }
10088
9988
  });
10089
9989
  }
@@ -10098,91 +9998,112 @@ var KTSelectSearch = /** @class */ (function () {
10098
9998
  }
10099
9999
  };
10100
10000
  /**
10101
- * Handle keyboard navigation for search results
10001
+ * Handles keydown events on the search input for navigation and actions.
10102
10002
  */
10103
- KTSelectSearch.prototype._handleKeyboardNavigation = function (event) {
10104
- var _this = this;
10105
- // Stop propagation to prevent multiple handlers from firing
10106
- event.stopPropagation();
10107
- if (this._config.debug)
10108
- console.log('Search module keydown:', event.key);
10109
- var visibleOptions = this._focusManager.getVisibleOptions();
10110
- if (visibleOptions.length === 0)
10111
- return;
10112
- // Use the shared keyboard navigation handler with custom callbacks
10113
- (0, utils_1.handleDropdownKeyNavigation)(event, this._select, {
10114
- multiple: this._select.getConfig().multiple,
10115
- closeOnSelect: this._select.getConfig().closeOnSelect,
10116
- }, {
10117
- onArrowDown: function () { return _this._focusManager.focusNext(); },
10118
- onArrowUp: function () { return _this._focusManager.focusPrevious(); },
10119
- onEnter: function () { return _this._selectFocusedOption(); },
10120
- onClose: function () {
10121
- if (event.key === 'Escape') {
10122
- _this.clearSearchHighlights();
10003
+ KTSelectSearch.prototype._handleSearchKeyDown = function (event) {
10004
+ var key = event.key;
10005
+ switch (key) {
10006
+ case 'ArrowDown':
10007
+ event.preventDefault();
10008
+ this._focusManager.focusNext();
10009
+ break;
10010
+ case 'ArrowUp':
10011
+ event.preventDefault();
10012
+ this._focusManager.focusPrevious();
10013
+ break;
10014
+ case 'Enter':
10015
+ event.preventDefault();
10016
+ // Always attempt to select the first available option in the list.
10017
+ // focusFirst() finds, focuses, and returns the first visible, non-disabled option.
10018
+ var firstAvailableOption = this._focusManager.focusFirst();
10019
+ if (firstAvailableOption) {
10020
+ var optionValue = firstAvailableOption.getAttribute('data-value');
10021
+ if (optionValue) {
10022
+ this._select.toggleSelection(optionValue);
10023
+ // KTSelect.toggleSelection handles closing the dropdown based on config.closeOnSelect and config.multiple
10024
+ }
10123
10025
  }
10124
- },
10125
- });
10026
+ break;
10027
+ case 'Escape':
10028
+ event.preventDefault();
10029
+ this._searchInput.value = '';
10030
+ this.clearSearch();
10031
+ this._resetAllOptions();
10032
+ this._clearNoResultsMessage();
10033
+ this._focusManager.focusFirst();
10034
+ break;
10035
+ default:
10036
+ break;
10037
+ }
10126
10038
  };
10127
10039
  /**
10128
- * Select the currently focused option
10129
- */
10130
- KTSelectSearch.prototype._selectFocusedOption = function () {
10131
- var focusedOption = this._focusManager.getFocusedOption();
10132
- if (focusedOption) {
10133
- var optionValue = focusedOption.getAttribute('data-value');
10134
- if (optionValue) {
10135
- // Ensure highlights are cleared before selection
10136
- this.clearSearchHighlights();
10137
- // Trigger the selection in the main select component
10138
- this._select['_selectOption'](optionValue);
10139
- }
10140
- }
10141
- };
10142
- /**
10143
- * Store original HTML content of all options for later restoration
10144
- * This prevents losing formatting when clearing search
10040
+ * Store original HTML content of all options for later restoration
10041
+ * This prevents losing formatting when clearing search
10145
10042
  */
10146
10043
  KTSelectSearch.prototype._cacheOriginalOptionContents = function () {
10147
10044
  var _this = this;
10148
10045
  // Wait for options to be initialized
10149
10046
  setTimeout(function () {
10047
+ _this._originalOptionContents.clear(); // Clear before re-caching
10150
10048
  var options = Array.from(_this._select.getOptionsElement());
10151
10049
  options.forEach(function (option) {
10152
10050
  var value = option.getAttribute('data-value');
10153
10051
  if (value) {
10052
+ // Store the full innerHTML as the original content
10154
10053
  _this._originalOptionContents.set(value, option.innerHTML);
10155
10054
  }
10156
10055
  });
10157
10056
  }, 0);
10158
10057
  };
10058
+ /**
10059
+ * Restores the innerHTML of all options from the cache if they have been modified.
10060
+ * This is typically called before applying new filters/highlights.
10061
+ */
10062
+ KTSelectSearch.prototype._restoreOptionContentsBeforeFilter = function () {
10063
+ var _this = this;
10064
+ var options = Array.from(this._select.getOptionsElement());
10065
+ options.forEach(function (option) {
10066
+ var value = option.getAttribute('data-value');
10067
+ if (value && _this._originalOptionContents.has(value)) {
10068
+ var originalContent = _this._originalOptionContents.get(value);
10069
+ // Only restore if current content is different, to avoid unnecessary DOM manipulation
10070
+ if (option.innerHTML !== originalContent) {
10071
+ option.innerHTML = originalContent;
10072
+ }
10073
+ }
10074
+ });
10075
+ };
10159
10076
  KTSelectSearch.prototype._handleSearchInput = function (event) {
10160
- var query = event.target.value.toLowerCase();
10077
+ var query = event.target.value;
10161
10078
  var config = this._select.getConfig();
10162
10079
  // Reset focused option when search changes
10163
10080
  this._focusManager.resetFocus();
10164
- // If search query is empty, clear all highlights
10081
+ // Restore original content for all options before filtering/highlighting again
10082
+ this._restoreOptionContentsBeforeFilter();
10165
10083
  if (query.trim() === '') {
10166
- this.clearSearchHighlights();
10084
+ this._resetAllOptions();
10085
+ this._focusManager.focusFirst(); // Focus first option when search is cleared
10086
+ return;
10167
10087
  }
10168
- // For remote search, we don't filter locally
10169
- // The KTSelect component will handle the remote search
10088
+ // For remote search, KTSelect component handles it.
10089
+ // KTSelect will call refreshAfterSearch on this module when remote data is updated.
10170
10090
  if (config.remote && config.searchParam) {
10171
- // If query is too short, reset all options to visible state
10172
10091
  if (query.length < config.searchMinLength) {
10173
10092
  this._resetAllOptions();
10174
10093
  this._clearNoResultsMessage();
10094
+ this._focusManager.focusFirst(); // Focus first if query too short
10175
10095
  }
10176
- // Otherwise, let KTSelect handle remote search
10177
10096
  return;
10178
10097
  }
10179
10098
  // For local search
10180
10099
  if (query.length >= config.searchMinLength) {
10181
10100
  this._filterOptions(query);
10101
+ this._focusManager.focusFirst(); // Focus first visible option after local filtering
10182
10102
  }
10183
10103
  else {
10184
10104
  this._resetAllOptions();
10185
10105
  this._clearNoResultsMessage();
10106
+ this._focusManager.focusFirst(); // Focus first if query too short and not remote
10186
10107
  }
10187
10108
  };
10188
10109
  KTSelectSearch.prototype._filterOptions = function (query) {
@@ -10194,20 +10115,11 @@ var KTSelectSearch = /** @class */ (function () {
10194
10115
  if (this._originalOptionContents.size === 0) {
10195
10116
  this._cacheOriginalOptionContents();
10196
10117
  }
10197
- // Use the shared filterOptions utility
10198
- (0, utils_1.filterOptions)(options, query, config, dropdownElement, function (visibleCount) {
10199
- return _this._handleNoResults(visibleCount);
10118
+ // Restore original content before filtering, so highlighting is applied fresh.
10119
+ this._restoreOptionContentsBeforeFilter();
10120
+ var visibleCount = (0, utils_1.filterOptions)(options, query, config, dropdownElement, function (count) {
10121
+ return _this._handleNoResults(count);
10200
10122
  });
10201
- // Apply specialized text highlighting if needed
10202
- if (config.searchHighlight && query.trim() !== '') {
10203
- this._applyHighlightToDisplay(query);
10204
- }
10205
- };
10206
- /**
10207
- * Apply highlighting to the display element for multi-select
10208
- */
10209
- KTSelectSearch.prototype._applyHighlightToDisplay = function (query) {
10210
- // Implementation for display highlighting
10211
10123
  };
10212
10124
  /**
10213
10125
  * Reset all options to their original state
@@ -10216,34 +10128,29 @@ var KTSelectSearch = /** @class */ (function () {
10216
10128
  var _this = this;
10217
10129
  // Show all options
10218
10130
  var options = Array.from(this._select.getOptionsElement());
10219
- // Cache original option HTML if not already cached
10131
+ // Ensure the cache is populated if it's somehow empty here
10220
10132
  if (this._originalOptionContents.size === 0) {
10221
10133
  this._cacheOriginalOptionContents();
10222
10134
  }
10223
10135
  options.forEach(function (option) {
10224
- // Remove the hidden class
10225
10136
  option.classList.remove('hidden');
10137
+ if (option.style.display === 'none')
10138
+ option.style.display = ''; // Ensure visible
10226
10139
  // Restore original HTML content (remove highlights)
10227
10140
  var value = option.getAttribute('data-value');
10228
10141
  if (value && _this._originalOptionContents.has(value)) {
10229
- option.innerHTML = _this._originalOptionContents.get(value);
10230
- }
10231
- // Remove any display styling
10232
- if (option.hasAttribute('style') &&
10233
- option.getAttribute('style').includes('display:')) {
10234
- var styleAttr = option.getAttribute('style');
10235
- if (styleAttr.trim() === 'display: none;' ||
10236
- styleAttr.trim() === 'display: block;') {
10237
- option.removeAttribute('style');
10238
- }
10239
- else {
10240
- option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
10142
+ var originalContent = _this._originalOptionContents.get(value);
10143
+ // Only update if different, to minimize DOM changes
10144
+ if (option.innerHTML !== originalContent) {
10145
+ option.innerHTML = originalContent;
10241
10146
  }
10242
10147
  }
10243
10148
  });
10149
+ this._clearNoResultsMessage(); // Ensure no results message is cleared when resetting
10244
10150
  };
10245
10151
  KTSelectSearch.prototype._handleNoResults = function (visibleOptionsCount) {
10246
- if (visibleOptionsCount === 0 && this._searchInput.value.trim() !== '') {
10152
+ var _a, _b;
10153
+ if (visibleOptionsCount === 0 && ((_b = (_a = this._searchInput) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.trim()) !== '') {
10247
10154
  this._showNoResultsMessage();
10248
10155
  }
10249
10156
  else {
@@ -10253,9 +10160,9 @@ var KTSelectSearch = /** @class */ (function () {
10253
10160
  KTSelectSearch.prototype._showNoResultsMessage = function () {
10254
10161
  this._clearNoResultsMessage();
10255
10162
  var config = this._select.getConfig();
10256
- this._noResultsElement = templates_1.defaultTemplates.noResults(config);
10163
+ this._noResultsElement = templates_1.defaultTemplates.empty(config);
10257
10164
  var dropdownElement = this._select.getDropdownElement();
10258
- var optionsContainer = dropdownElement.querySelector('[data-kt-select-options-container]');
10165
+ var optionsContainer = dropdownElement.querySelector('[data-kt-select-options]');
10259
10166
  if (optionsContainer) {
10260
10167
  optionsContainer.appendChild(this._noResultsElement);
10261
10168
  }
@@ -10273,24 +10180,24 @@ var KTSelectSearch = /** @class */ (function () {
10273
10180
  * Public method to explicitly clear all search highlights
10274
10181
  * This is called when search is reset or selection changes
10275
10182
  */
10276
- KTSelectSearch.prototype.clearSearchHighlights = function () {
10183
+ KTSelectSearch.prototype.clearSearch = function () {
10277
10184
  var _this = this;
10278
10185
  // Restore original option content (removes highlighting)
10279
- var options = Array.from(this._select.getOptionsElement());
10280
- options.forEach(function (option) {
10186
+ var optionsToClear = Array.from(this._select.getOptionsElement());
10187
+ // Ensure cache is available
10188
+ if (this._originalOptionContents.size === 0 && optionsToClear.length > 0) {
10189
+ this._cacheOriginalOptionContents();
10190
+ }
10191
+ optionsToClear.forEach(function (option) {
10281
10192
  var value = option.getAttribute('data-value');
10282
10193
  if (value && _this._originalOptionContents.has(value)) {
10283
- option.innerHTML = _this._originalOptionContents.get(value);
10194
+ var originalContent = _this._originalOptionContents.get(value);
10195
+ // Only restore if different
10196
+ if (option.innerHTML !== originalContent) {
10197
+ option.innerHTML = originalContent;
10198
+ }
10284
10199
  }
10285
10200
  });
10286
- // Also clear highlights from the display element
10287
- this._clearDisplayHighlights();
10288
- };
10289
- /**
10290
- * Clear any highlights from the display element (selected values)
10291
- */
10292
- KTSelectSearch.prototype._clearDisplayHighlights = function () {
10293
- // Implementation for clearing display highlights
10294
10201
  };
10295
10202
  /**
10296
10203
  * This ensures that search highlighting works correctly with new options
@@ -10299,14 +10206,23 @@ var KTSelectSearch = /** @class */ (function () {
10299
10206
  var _this = this;
10300
10207
  // Re-cache all option contents
10301
10208
  this._originalOptionContents.clear();
10302
- var options = Array.from(this._select.getOptionsElement());
10303
- options.forEach(function (option) {
10209
+ var currentOptions = Array.from(this._select.getOptionsElement());
10210
+ currentOptions.forEach(function (option) {
10304
10211
  var value = option.getAttribute('data-value');
10305
10212
  if (value) {
10306
10213
  _this._originalOptionContents.set(value, option.innerHTML);
10307
10214
  }
10308
10215
  });
10309
10216
  };
10217
+ /**
10218
+ * Called after search (local or remote via KTSelect) to reset focus.
10219
+ */
10220
+ KTSelectSearch.prototype.refreshAfterSearch = function () {
10221
+ this._focusManager.resetFocus();
10222
+ this._focusManager.focusFirst();
10223
+ // Re-cache original contents as options might have changed (especially after remote search)
10224
+ this.refreshOptionCache();
10225
+ };
10310
10226
  /**
10311
10227
  * Clean up all resources used by the search module
10312
10228
  */
@@ -10314,12 +10230,13 @@ var KTSelectSearch = /** @class */ (function () {
10314
10230
  // Remove all event listeners
10315
10231
  this._removeEventListeners();
10316
10232
  // Clear all references
10317
- this._focusManager.dispose();
10318
- this._eventManager.removeAllListeners(null);
10233
+ if (this._focusManager) {
10234
+ this._focusManager.dispose();
10235
+ }
10319
10236
  // Clear cached content
10320
10237
  this._originalOptionContents.clear();
10321
10238
  // Clear highlight elements
10322
- this.clearSearchHighlights();
10239
+ this.clearSearch();
10323
10240
  };
10324
10241
  return KTSelectSearch;
10325
10242
  }());
@@ -11424,7 +11341,6 @@ var combobox_1 = __webpack_require__(5539);
11424
11341
  var dropdown_1 = __webpack_require__(7125);
11425
11342
  var utils_1 = __webpack_require__(9011);
11426
11343
  var tags_1 = __webpack_require__(8797);
11427
- var types_1 = __webpack_require__(8135);
11428
11344
  var KTSelect = /** @class */ (function (_super) {
11429
11345
  __extends(KTSelect, _super);
11430
11346
  /**
@@ -11441,6 +11357,7 @@ var KTSelect = /** @class */ (function (_super) {
11441
11357
  _this._tagsModule = null;
11442
11358
  _this._dropdownModule = null;
11443
11359
  _this._loadMoreIndicator = null;
11360
+ _this._typeToSearchBuffer = new utils_1.TypeToSearchBuffer();
11444
11361
  // Search debounce timeout
11445
11362
  _this._searchDebounceTimeout = null;
11446
11363
  // Store original options HTML for restoring after search
@@ -11525,11 +11442,6 @@ var KTSelect = /** @class */ (function (_super) {
11525
11442
  // Keep only the empty/placeholder option and remove the rest
11526
11443
  var options = Array.from(this._element.querySelectorAll('option:not([value=""])'));
11527
11444
  options.forEach(function (option) { return option.remove(); });
11528
- // Ensure we have at least an empty option
11529
- if (this._element.querySelectorAll('option').length === 0) {
11530
- var emptyOption = templates_1.defaultTemplates.emptyOption(__assign(__assign({}, this._config), { placeholder: this._config.placeholder }));
11531
- this._element.appendChild(emptyOption);
11532
- }
11533
11445
  };
11534
11446
  /**
11535
11447
  * Helper to show a dropdown message (error, loading, noResults)
@@ -11537,19 +11449,20 @@ var KTSelect = /** @class */ (function (_super) {
11537
11449
  KTSelect.prototype._showDropdownMessage = function (type, message) {
11538
11450
  if (!this._dropdownContentElement)
11539
11451
  return;
11540
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
11452
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
11541
11453
  if (!optionsContainer)
11542
11454
  return;
11455
+ // Clear previous messages
11456
+ optionsContainer.innerHTML = '';
11543
11457
  switch (type) {
11544
11458
  case 'error':
11545
- optionsContainer.innerHTML = templates_1.defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message }));
11459
+ optionsContainer.appendChild(templates_1.defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message })));
11546
11460
  break;
11547
11461
  case 'loading':
11548
- optionsContainer.innerHTML = templates_1.defaultTemplates.loading(this._config, message || 'Loading...').outerHTML;
11462
+ optionsContainer.appendChild(templates_1.defaultTemplates.loading(this._config, message || 'Loading...'));
11549
11463
  break;
11550
- case 'noResults':
11551
- optionsContainer.innerHTML = '';
11552
- optionsContainer.appendChild(templates_1.defaultTemplates.noResults(this._config));
11464
+ case 'empty':
11465
+ optionsContainer.appendChild(templates_1.defaultTemplates.empty(this._config));
11553
11466
  break;
11554
11467
  }
11555
11468
  };
@@ -11568,14 +11481,6 @@ var KTSelect = /** @class */ (function (_super) {
11568
11481
  * @param message Error message
11569
11482
  */
11570
11483
  KTSelect.prototype._renderErrorState = function (message) {
11571
- // Create error option if the select is empty
11572
- if (this._element.querySelectorAll('option').length <= 1) {
11573
- var loadingOptions = this._element.querySelectorAll('option[disabled]:not([value])');
11574
- loadingOptions.forEach(function (option) { return option.remove(); });
11575
- // Use template function for error option instead of hardcoded element
11576
- var errorOption = templates_1.defaultTemplates.errorOption(__assign(__assign({}, this._config), { errorMessage: message }));
11577
- this._element.appendChild(errorOption);
11578
- }
11579
11484
  // If dropdown is already created, show error message there
11580
11485
  this._showDropdownMessage('error', message);
11581
11486
  if (!this._wrapperElement) {
@@ -11598,7 +11503,7 @@ var KTSelect = /** @class */ (function (_super) {
11598
11503
  // Create load more button using template
11599
11504
  this._loadMoreIndicator = templates_1.defaultTemplates.loadMore(this._config);
11600
11505
  // Add to dropdown
11601
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
11506
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
11602
11507
  if (optionsContainer) {
11603
11508
  optionsContainer.appendChild(this._loadMoreIndicator);
11604
11509
  }
@@ -11668,42 +11573,26 @@ var KTSelect = /** @class */ (function (_super) {
11668
11573
  * @param newItems New items to add to the dropdown
11669
11574
  */
11670
11575
  KTSelect.prototype._updateOptionsInDropdown = function (newItems) {
11671
- var _this = this;
11672
11576
  if (!this._dropdownContentElement || !newItems.length)
11673
11577
  return;
11674
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
11578
+ var optionsContainer = this._dropdownContentElement.querySelector("[data-kt-select-options]");
11675
11579
  if (!optionsContainer)
11676
11580
  return;
11677
11581
  // Get the load more button
11678
- var loadMoreButton = optionsContainer.querySelector('[data-kt-select-load-more]');
11582
+ var loadMoreButton = optionsContainer.querySelector("[data-kt-select-load-more]");
11679
11583
  // Process each new item
11680
11584
  newItems.forEach(function (item) {
11681
11585
  // Create option for the original select
11682
- var selectOption = templates_1.defaultTemplates.emptyOption(__assign(__assign({}, _this._config), { placeholder: item.title || 'Unnamed option' }));
11586
+ var selectOption = document.createElement('option');
11683
11587
  selectOption.value = item.id || '';
11684
- // Add description and icon attributes if available and valid
11685
- if (item.description &&
11686
- item.description !== 'null' &&
11687
- item.description !== 'undefined') {
11688
- selectOption.setAttribute('data-kt-select-option-description', item.description);
11689
- }
11690
- if (item.icon && item.icon !== 'null' && item.icon !== 'undefined') {
11691
- selectOption.setAttribute('data-kt-select-option-icon', item.icon);
11692
- }
11693
- // Add the option to the original select element
11694
- _this._element.appendChild(selectOption);
11695
- // Create option element for the dropdown using the KTSelectOption class
11696
- // This ensures consistent option rendering
11697
- var ktOption = new option_1.KTSelectOption(selectOption, _this._config);
11698
- var renderedOption = ktOption.render();
11699
11588
  // Add to dropdown container
11700
11589
  if (loadMoreButton) {
11701
11590
  // Insert before the load more button
11702
- optionsContainer.insertBefore(renderedOption, loadMoreButton);
11591
+ optionsContainer.insertBefore(selectOption, loadMoreButton);
11703
11592
  }
11704
11593
  else {
11705
11594
  // Append to the end
11706
- optionsContainer.appendChild(renderedOption);
11595
+ optionsContainer.appendChild(selectOption);
11707
11596
  }
11708
11597
  });
11709
11598
  // Update options NodeList to include the new options
@@ -11725,7 +11614,7 @@ var KTSelect = /** @class */ (function (_super) {
11725
11614
  this._setupElementReferences();
11726
11615
  this._initZIndex();
11727
11616
  // Initialize options
11728
- this._initializeOptionsHtml();
11617
+ // this._initializeOptionsHtml();
11729
11618
  this._preSelectOptions(this._element);
11730
11619
  // Apply disabled state if needed
11731
11620
  this._applyInitialDisabledState();
@@ -11734,17 +11623,17 @@ var KTSelect = /** @class */ (function (_super) {
11734
11623
  this._initializeSearchModule();
11735
11624
  }
11736
11625
  // Initialize combobox if enabled
11737
- if (this._config.mode === types_1.SelectMode.COMBOBOX) {
11626
+ if (this._config.combobox) {
11738
11627
  this._comboboxModule = new combobox_1.KTSelectCombobox(this);
11739
11628
  }
11740
11629
  // Initialize tags if enabled
11741
- if (this._config.mode === types_1.SelectMode.TAGS) {
11630
+ if (this._config.tags) {
11742
11631
  this._tagsModule = new tags_1.KTSelectTags(this);
11743
11632
  }
11744
11633
  // Initialize focus manager after dropdown element is created
11745
11634
  this._focusManager = new utils_1.FocusManager(this._dropdownContentElement, '[data-kt-select-option]', this._config);
11746
11635
  // Initialize dropdown module after all elements are created
11747
- this._dropdownModule = new dropdown_1.KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config);
11636
+ this._dropdownModule = new dropdown_1.KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config, this);
11748
11637
  // Update display and set ARIA attributes
11749
11638
  this._updateDisplayAndAriaAttributes();
11750
11639
  this.updateSelectedOptionDisplay();
@@ -11752,34 +11641,34 @@ var KTSelect = /** @class */ (function (_super) {
11752
11641
  // Attach event listeners after all modules are initialized
11753
11642
  this._attachEventListeners();
11754
11643
  };
11755
- /**
11756
- * Initialize options HTML from data
11757
- */
11758
- KTSelect.prototype._initializeOptionsHtml = function () {
11759
- this._generateOptionsHtml(this._element);
11760
- };
11761
11644
  /**
11762
11645
  * Creates the HTML structure for the select component
11763
11646
  */
11764
11647
  KTSelect.prototype._createHtmlStructure = function () {
11648
+ var _a;
11765
11649
  var _this = this;
11766
11650
  var options = Array.from(this._element.querySelectorAll('option'));
11767
11651
  // Create wrapper and display elements
11768
- var wrapperElement = templates_1.defaultTemplates.main(this._config);
11652
+ var wrapperElement = templates_1.defaultTemplates.wrapper(this._config);
11769
11653
  var displayElement = templates_1.defaultTemplates.display(this._config);
11770
11654
  // Add the display element to the wrapper
11771
11655
  wrapperElement.appendChild(displayElement);
11656
+ // Move classes from original select to display element
11657
+ if (this._element.classList.length > 0) {
11658
+ (_a = displayElement.classList).add.apply(_a, Array.from(this._element.classList));
11659
+ this._element.className = '';
11660
+ }
11772
11661
  // Create an empty dropdown first (without options) using template
11773
- var dropdownElement = templates_1.defaultTemplates.dropdownContent(__assign(__assign({}, this._config), { zindex: this._config.dropdownZindex }));
11662
+ var dropdownElement = templates_1.defaultTemplates.dropdown(__assign(__assign({}, this._config), { zindex: this._config.dropdownZindex }));
11774
11663
  // Add search input if needed
11775
- var isCombobox = this._config.mode === types_1.SelectMode.COMBOBOX;
11776
- var hasSearch = this._config.enableSearch && !isCombobox;
11777
- if (hasSearch) {
11664
+ if (this._config.enableSearch) {
11778
11665
  var searchElement = templates_1.defaultTemplates.search(this._config);
11779
11666
  dropdownElement.appendChild(searchElement);
11780
11667
  }
11781
11668
  // Create options container using template
11782
- var optionsContainer = templates_1.defaultTemplates.optionsContainer(this._config);
11669
+ var optionsContainer = templates_1.defaultTemplates.options(this._config);
11670
+ // Clear the options container
11671
+ optionsContainer.innerHTML = '';
11783
11672
  // Add each option directly to the container
11784
11673
  options.forEach(function (optionElement) {
11785
11674
  // Skip empty placeholder options (only if BOTH value AND text are empty)
@@ -11810,21 +11699,17 @@ var KTSelect = /** @class */ (function (_super) {
11810
11699
  // Get display element
11811
11700
  this._displayElement = this._wrapperElement.querySelector("[data-kt-select-display]");
11812
11701
  // Get dropdown content element - this is critical for dropdown functionality
11813
- this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown-content]");
11702
+ this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown]");
11814
11703
  if (!this._dropdownContentElement) {
11704
+ console.log(this._element);
11815
11705
  console.error('Dropdown content element not found', this._wrapperElement);
11816
11706
  }
11817
11707
  // Get search input element - this is used for the search functionality
11818
- // First check if it's in dropdown, then check if it's in display (for combobox)
11819
11708
  this._searchInputElement = this._dropdownContentElement.querySelector("[data-kt-select-search]");
11820
- // If not found in dropdown, check if it's the display element itself (for combobox)
11821
- if (!this._searchInputElement &&
11822
- this._config.mode === types_1.SelectMode.COMBOBOX) {
11709
+ // If not found in dropdown, check if it's the display element itself
11710
+ if (!this._searchInputElement) {
11823
11711
  this._searchInputElement = this._displayElement;
11824
11712
  }
11825
- if (this._config.debug)
11826
- console.log('Search input found:', this._searchInputElement ? 'Yes' : 'No', 'Mode:', this._config.mode, 'EnableSearch:', this._config.enableSearch);
11827
- this._valueDisplayElement = this._wrapperElement.querySelector("[data-kt-select-value]");
11828
11713
  this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
11829
11714
  };
11830
11715
  /**
@@ -11833,17 +11718,12 @@ var KTSelect = /** @class */ (function (_super) {
11833
11718
  KTSelect.prototype._attachEventListeners = function () {
11834
11719
  // Document level event listeners
11835
11720
  document.addEventListener('click', this._handleDocumentClick.bind(this));
11836
- document.addEventListener('keydown', this._handleEscKey.bind(this));
11837
11721
  // Dropdown option click events
11838
11722
  this._eventManager.addListener(this._dropdownContentElement, 'click', this._handleDropdownOptionClick.bind(this));
11839
- // Only attach click handler to display element
11840
- this._eventManager.addListener(this._displayElement, 'click', this._handleDropdownClick.bind(this));
11841
- // Only attach keyboard navigation to display element if NOT in combobox mode
11842
- // This prevents conflicts with the combobox module's keyboard handler
11843
- if (this._config.mode !== types_1.SelectMode.COMBOBOX) {
11844
- if (this._config.debug)
11845
- console.log('Attaching keyboard navigation to display element (non-combobox mode)');
11846
- this._eventManager.addListener(this._displayElement, 'keydown', this._handleDropdownKeyDown.bind(this));
11723
+ // Attach centralized keyboard handler to the wrapper element.
11724
+ // Events from focusable children like _displayElement or _searchInputElement (if present) will bubble up.
11725
+ if (this._wrapperElement) {
11726
+ this._wrapperElement.addEventListener('keydown', this._handleKeyboardEvent.bind(this));
11847
11727
  }
11848
11728
  };
11849
11729
  /**
@@ -11913,52 +11793,12 @@ var KTSelect = /** @class */ (function (_super) {
11913
11793
  label =
11914
11794
  extractedLabel !== null ? String(extractedLabel) : 'Unnamed option';
11915
11795
  }
11916
- // Get description - skip if null, undefined, or "null" string
11917
- var description = null;
11918
- if (item.description !== undefined &&
11919
- item.description !== null &&
11920
- String(item.description) !== 'null' &&
11921
- String(item.description) !== 'undefined') {
11922
- description = String(item.description);
11923
- }
11924
- else if (_this._config.dataFieldDescription) {
11925
- var extractedDesc = _this._getValueByKey(item, _this._config.dataFieldDescription);
11926
- if (extractedDesc !== null &&
11927
- extractedDesc !== undefined &&
11928
- String(extractedDesc) !== 'null' &&
11929
- String(extractedDesc) !== 'undefined') {
11930
- description = String(extractedDesc);
11931
- }
11932
- }
11933
- // Get icon - skip if null, undefined, or "null" string
11934
- var icon = null;
11935
- if (item.icon !== undefined &&
11936
- item.icon !== null &&
11937
- String(item.icon) !== 'null' &&
11938
- String(item.icon) !== 'undefined') {
11939
- icon = String(item.icon);
11940
- }
11941
- else if (_this._config.dataFieldIcon) {
11942
- var extractedIcon = _this._getValueByKey(item, _this._config.dataFieldIcon);
11943
- if (extractedIcon !== null &&
11944
- extractedIcon !== undefined &&
11945
- String(extractedIcon) !== 'null' &&
11946
- String(extractedIcon) !== 'undefined') {
11947
- icon = String(extractedIcon);
11948
- }
11949
- }
11950
11796
  // Log the extracted values for debugging
11951
11797
  if (_this._config.debug)
11952
- console.log("Option: value=".concat(value, ", label=").concat(label, ", desc=").concat(description ? description : 'none', ", icon=").concat(icon ? icon : 'none'));
11798
+ console.log("Option: value=".concat(value, ", label=").concat(label));
11953
11799
  // Set option attributes
11954
11800
  optionElement.value = value;
11955
11801
  optionElement.textContent = label || 'Unnamed option';
11956
- if (description) {
11957
- optionElement.setAttribute('data-kt-select-option-description', description);
11958
- }
11959
- if (icon) {
11960
- optionElement.setAttribute('data-kt-select-option-icon', icon);
11961
- }
11962
11802
  if (item.selected) {
11963
11803
  optionElement.setAttribute('selected', 'selected');
11964
11804
  }
@@ -12026,31 +11866,15 @@ var KTSelect = /** @class */ (function (_super) {
12026
11866
  * DROPDOWN MANAGEMENT
12027
11867
  * ========================================================================
12028
11868
  */
12029
- /**
12030
- * Toggle dropdown visibility
12031
- */
12032
- KTSelect.prototype.toggleDropdown = function () {
12033
- if (this._config.debug)
12034
- console.log('toggleDropdown called');
12035
- if (this._dropdownModule) {
12036
- // Always use the dropdown module's state to determine whether to open or close
12037
- if (this._dropdownModule.isOpen()) {
12038
- if (this._config.debug)
12039
- console.log('Dropdown is open, closing...');
12040
- this.closeDropdown();
12041
- }
12042
- else {
12043
- if (this._config.debug)
12044
- console.log('Dropdown is closed, opening...');
12045
- this.openDropdown();
12046
- }
12047
- }
12048
- };
12049
11869
  /**
12050
11870
  * Open the dropdown
12051
11871
  */
12052
11872
  KTSelect.prototype.openDropdown = function () {
12053
- var _this = this;
11873
+ if (this._config.disabled) {
11874
+ if (this._config.debug)
11875
+ console.log('openDropdown: select is disabled, not opening');
11876
+ return;
11877
+ }
12054
11878
  if (this._config.debug)
12055
11879
  console.log('openDropdown called, dropdownModule exists:', !!this._dropdownModule);
12056
11880
  if (!this._dropdownModule) {
@@ -12073,14 +11897,6 @@ var KTSelect = /** @class */ (function (_super) {
12073
11897
  // Dispatch custom event
12074
11898
  this._dispatchEvent('show');
12075
11899
  this._fireEvent('show');
12076
- // Focus search input if configured and exists
12077
- if (this._config.enableSearch &&
12078
- this._config.searchAutofocus &&
12079
- this._searchInputElement) {
12080
- setTimeout(function () {
12081
- _this._searchInputElement.focus();
12082
- }, 50);
12083
- }
12084
11900
  // Update ARIA states
12085
11901
  this._setAriaAttributes();
12086
11902
  // Focus the first selected option or first option if nothing selected
@@ -12101,14 +11917,14 @@ var KTSelect = /** @class */ (function (_super) {
12101
11917
  // Always close by delegating to the dropdown module, which is the source of truth
12102
11918
  if (this._config.debug)
12103
11919
  console.log('Closing dropdown via dropdownModule...');
12104
- // Clear search input and highlights if the dropdown is closing
11920
+ // Clear search input if the dropdown is closing
12105
11921
  if (this._searchModule && this._searchInputElement) {
12106
11922
  // Clear search input if configured to do so
12107
11923
  if (this._config.clearSearchOnClose) {
12108
11924
  this._searchInputElement.value = '';
12109
11925
  }
12110
- // Always clear the highlights when dropdown closes
12111
- this._searchModule.clearSearchHighlights();
11926
+ // Clear search input when dropdown closes
11927
+ this._searchModule.clearSearch();
12112
11928
  }
12113
11929
  // Set our internal flag to match what we're doing
12114
11930
  this._dropdownIsOpen = false;
@@ -12142,10 +11958,13 @@ var KTSelect = /** @class */ (function (_super) {
12142
11958
  var selectedOptions = this.getSelectedOptions();
12143
11959
  if (selectedOptions.length === 0)
12144
11960
  return;
12145
- // Get the first selected option element
12146
- var firstSelectedValue = selectedOptions[0];
12147
- // Use the FocusManager to focus on the option
12148
- this._focusManager.focusOptionByValue(firstSelectedValue);
11961
+ // Iterate through selected options and focus the first one that is visible
11962
+ for (var _i = 0, selectedOptions_1 = selectedOptions; _i < selectedOptions_1.length; _i++) {
11963
+ var value = selectedOptions_1[_i];
11964
+ if (this._focusManager && this._focusManager.focusOptionByValue(value)) {
11965
+ break; // Stop after focusing the first found selected and visible option
11966
+ }
11967
+ }
12149
11968
  };
12150
11969
  /**
12151
11970
  * ========================================================================
@@ -12156,6 +11975,12 @@ var KTSelect = /** @class */ (function (_super) {
12156
11975
  * Select an option by value
12157
11976
  */
12158
11977
  KTSelect.prototype._selectOption = function (value) {
11978
+ // Prevent selection if the option is disabled (in dropdown or original select)
11979
+ if (this._isOptionDisabled(value)) {
11980
+ if (this._config.debug)
11981
+ console.log('_selectOption: Option is disabled, ignoring selection');
11982
+ return;
11983
+ }
12159
11984
  // Get current selection state
12160
11985
  var isSelected = this._state.isSelected(value);
12161
11986
  // Toggle selection in state
@@ -12201,109 +12026,91 @@ var KTSelect = /** @class */ (function (_super) {
12201
12026
  * Update selected option display value
12202
12027
  */
12203
12028
  KTSelect.prototype.updateSelectedOptionDisplay = function () {
12204
- var _this = this;
12205
12029
  var selectedOptions = this.getSelectedOptions();
12206
- if (this._config.renderSelected) {
12207
- // Use the custom renderSelected function if provided
12208
- this._updateValueDisplay(this._config.renderSelected(selectedOptions));
12030
+ var tagsEnabled = this._config.tags && this._tagsModule;
12031
+ var valueDisplayEl = this.getValueDisplayElement();
12032
+ if (tagsEnabled) {
12033
+ // Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
12034
+ this._tagsModule.updateTagsDisplay(selectedOptions);
12035
+ }
12036
+ // Guard against valueDisplayEl being null due to template modifications
12037
+ if (!valueDisplayEl) {
12038
+ if (this._config.debug) {
12039
+ console.warn('KTSelect: Value display element is null. Cannot update display or placeholder. Check template for [data-kt-select-value].');
12040
+ }
12041
+ return; // Nothing to display on if the element is missing
12042
+ }
12043
+ // 1. Custom render function takes highest precedence
12044
+ if (typeof this._config.renderSelected === 'function') {
12045
+ valueDisplayEl.innerHTML = this._config.renderSelected(selectedOptions);
12046
+ return;
12209
12047
  }
12210
- else {
12211
- if (selectedOptions.length === 0) {
12212
- if (this._config.mode !== types_1.SelectMode.COMBOBOX) {
12213
- this._updateValueDisplay(this._config.placeholder); // Use innerHTML for placeholder
12214
- }
12048
+ // 2. Custom displayTemplate string
12049
+ // Check if a custom display template string is provided directly in config or via config.templates
12050
+ var customDisplayTemplateString = this._config.displayTemplate || (this._config.templates && this._config.templates.display);
12051
+ if (customDisplayTemplateString) {
12052
+ // If tags are enabled and items are selected, the tags module handles display, so clear the main display area.
12053
+ if (tagsEnabled && selectedOptions.length > 0) {
12054
+ valueDisplayEl.innerHTML = '';
12215
12055
  }
12216
- else if (this._config.multiple) {
12217
- if (this._config.mode === types_1.SelectMode.TAGS) {
12218
- // Use the tags module to render selected options as tags
12219
- if (this._tagsModule) {
12220
- this._tagsModule.updateTagsDisplay(selectedOptions);
12221
- }
12222
- else {
12223
- // Fallback if tags module not initialized for some reason
12224
- this._updateValueDisplay(selectedOptions.join(', '));
12225
- }
12226
- }
12227
- else {
12228
- // Render as comma-separated values
12229
- var displayText = selectedOptions
12230
- .map(function (option) { return _this._getOptionInnerHtml(option) || ''; })
12231
- .join(', ');
12232
- this._updateValueDisplay(displayText);
12233
- }
12056
+ else {
12057
+ // Otherwise, render the custom display template.
12058
+ // If no options are selected, renderDisplayTemplateForSelected should handle showing a placeholder if the template supports it,
12059
+ // or we might need a separate placeholder rendering for custom templates if they don't handle empty selection.
12060
+ // For now, assume renderDisplayTemplateForSelected handles it or shows selected text.
12061
+ valueDisplayEl.innerHTML = this.renderDisplayTemplateForSelected(selectedOptions);
12062
+ }
12063
+ return;
12064
+ }
12065
+ // 3. Default template behavior (no custom function or string template)
12066
+ var textContainer = valueDisplayEl.querySelector('[data-kt-text-container="true"]');
12067
+ if (tagsEnabled && selectedOptions.length > 0) {
12068
+ // Tags are active and have content, clear the text container if it exists,
12069
+ // or the whole display if it doesn't (though it should with default template).
12070
+ if (textContainer) {
12071
+ textContainer.innerHTML = '';
12234
12072
  }
12235
12073
  else {
12236
- var selectedOption = selectedOptions[0];
12237
- if (selectedOption) {
12238
- var selectedText = this._getOptionInnerHtml(selectedOption);
12239
- this._updateValueDisplay(selectedText);
12240
- // Update combobox input value if in combobox mode
12241
- if (this._config.mode === types_1.SelectMode.COMBOBOX &&
12242
- this._comboboxModule) {
12243
- this._comboboxModule.updateSelectedValue(selectedText);
12244
- }
12245
- }
12246
- else {
12247
- this._updateValueDisplay(this._config.placeholder);
12248
- }
12074
+ valueDisplayEl.innerHTML = ''; // Fallback: clear entire display area
12249
12075
  }
12250
12076
  }
12251
- // Update any debug display boxes if they exist
12252
- this._updateDebugDisplays();
12253
- };
12254
- /**
12255
- * Update the value display element
12256
- */
12257
- KTSelect.prototype._updateValueDisplay = function (value) {
12258
- if (this._config.mode === types_1.SelectMode.COMBOBOX) {
12259
- // For combobox, we only update the hidden value element, not the input
12260
- // The combobox module will handle updating the input value
12261
- if (!this._comboboxModule) {
12262
- this._valueDisplayElement.value = value;
12077
+ else if (selectedOptions.length === 0) {
12078
+ // No options selected: display placeholder text in the text container.
12079
+ var placeholderTemplate = templates_1.defaultTemplates.placeholder(this._config);
12080
+ var placeholderText = placeholderTemplate.textContent || ''; // Get text from placeholder element
12081
+ if (textContainer) {
12082
+ textContainer.innerHTML = placeholderText;
12083
+ }
12084
+ else {
12085
+ // Fallback: If no text container, replace children of valueDisplayEl with the placeholder element itself.
12086
+ // This ensures the placeholder (which might have its own structure/classes) is displayed.
12087
+ valueDisplayEl.replaceChildren(placeholderTemplate);
12263
12088
  }
12264
12089
  }
12265
12090
  else {
12266
- this._valueDisplayElement.innerHTML = value;
12267
- }
12268
- };
12269
- /**
12270
- * Update debug displays if present
12271
- */
12272
- KTSelect.prototype._updateDebugDisplays = function () {
12273
- // Check if we're in a test environment with debug boxes
12274
- var selectId = this.getElement().id;
12275
- if (selectId) {
12276
- var debugElement = document.getElementById("".concat(selectId, "-value"));
12277
- if (debugElement) {
12278
- var selectedOptions = this.getSelectedOptions();
12279
- // Format display based on selection mode
12280
- if (this._config.multiple) {
12281
- // For multiple selection, show comma-separated list
12282
- debugElement.textContent =
12283
- selectedOptions.length > 0 ? selectedOptions.join(', ') : 'None';
12284
- }
12285
- else {
12286
- // For single selection, show just the one value
12287
- debugElement.textContent =
12288
- selectedOptions.length > 0 ? selectedOptions[0] : 'None';
12289
- }
12091
+ // Options are selected, and tags are not enabled (or no selected options for tags):
12092
+ // Render normal selected text in the text container.
12093
+ var content = this.getSelectedOptionsText();
12094
+ if (textContainer) {
12095
+ textContainer.innerHTML = content;
12096
+ }
12097
+ else {
12098
+ valueDisplayEl.innerHTML = content; // Fallback: set content on whole display area
12290
12099
  }
12291
12100
  }
12292
12101
  };
12293
12102
  /**
12294
- * Get option inner HTML content by option value
12103
+ * Check if an option was originally disabled in the HTML
12295
12104
  */
12296
- KTSelect.prototype._getOptionInnerHtml = function (optionValue) {
12297
- var option = Array.from(this._options).find(function (opt) { return opt.dataset.value === optionValue; });
12298
- if (this._config.mode == types_1.SelectMode.COMBOBOX) {
12299
- return option.textContent;
12300
- }
12301
- return option.innerHTML; // Get the entire HTML content of the option
12105
+ KTSelect.prototype._isOptionOriginallyDisabled = function (value) {
12106
+ var originalOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
12107
+ return originalOption ? originalOption.disabled : false;
12302
12108
  };
12303
12109
  /**
12304
12110
  * Update CSS classes for selected options
12305
12111
  */
12306
12112
  KTSelect.prototype._updateSelectedOptionClass = function () {
12113
+ var _this = this;
12307
12114
  var allOptions = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
12308
12115
  var selectedValues = this._state.getSelectedOptions();
12309
12116
  var maxReached = typeof this._config.maxSelections === 'number' &&
@@ -12315,9 +12122,11 @@ var KTSelect = /** @class */ (function (_super) {
12315
12122
  if (!optionValue)
12316
12123
  return;
12317
12124
  var isSelected = selectedValues.includes(optionValue);
12125
+ var isOriginallyDisabled = _this._isOptionOriginallyDisabled(optionValue);
12318
12126
  if (isSelected) {
12319
12127
  option.classList.add('selected');
12320
12128
  option.setAttribute('aria-selected', 'true');
12129
+ // Selected options should not be visually hidden or disabled by maxSelections logic
12321
12130
  option.classList.remove('hidden');
12322
12131
  option.classList.remove('disabled');
12323
12132
  option.removeAttribute('aria-disabled');
@@ -12325,7 +12134,8 @@ var KTSelect = /** @class */ (function (_super) {
12325
12134
  else {
12326
12135
  option.classList.remove('selected');
12327
12136
  option.setAttribute('aria-selected', 'false');
12328
- if (maxReached) {
12137
+ // An option should be disabled if it was originally disabled OR if maxSelections is reached
12138
+ if (isOriginallyDisabled || maxReached) {
12329
12139
  option.classList.add('disabled');
12330
12140
  option.setAttribute('aria-disabled', 'true');
12331
12141
  }
@@ -12344,17 +12154,6 @@ var KTSelect = /** @class */ (function (_super) {
12344
12154
  this._state.setSelectedOptions([]);
12345
12155
  this.updateSelectedOptionDisplay();
12346
12156
  this._updateSelectedOptionClass();
12347
- // For combobox, also clear the input value
12348
- if (this._config.mode === types_1.SelectMode.COMBOBOX) {
12349
- if (this._searchInputElement) {
12350
- this._searchInputElement.value = '';
12351
- }
12352
- // If combobox has a clear button, hide it
12353
- if (this._comboboxModule) {
12354
- // The combobox module will handle hiding the clear button
12355
- this._comboboxModule.resetInputValueToSelection();
12356
- }
12357
- }
12358
12157
  // Dispatch change event
12359
12158
  this._dispatchEvent('change');
12360
12159
  this._fireEvent('change');
@@ -12366,49 +12165,6 @@ var KTSelect = /** @class */ (function (_super) {
12366
12165
  var values = Array.from(options).map(function (option) { return option.value; });
12367
12166
  this._state.setSelectedOptions(values);
12368
12167
  };
12369
- /**
12370
- * ========================================================================
12371
- * KEYBOARD NAVIGATION
12372
- * ========================================================================
12373
- */
12374
- /**
12375
- * Handle dropdown key down events for keyboard navigation
12376
- * Only used for standard (non-combobox) dropdowns
12377
- */
12378
- KTSelect.prototype._handleDropdownKeyDown = function (event) {
12379
- // Log event for debugging
12380
- if (this._config.debug)
12381
- console.log('Standard dropdown keydown:', event.key);
12382
- // Use the shared handler
12383
- (0, utils_1.handleDropdownKeyNavigation)(event, this, {
12384
- multiple: this._config.multiple,
12385
- closeOnSelect: this._config.closeOnSelect,
12386
- });
12387
- };
12388
- /**
12389
- * Focus next option in dropdown
12390
- */
12391
- KTSelect.prototype._focusNextOption = function () {
12392
- return this._focusManager.focusNext();
12393
- };
12394
- /**
12395
- * Focus previous option in dropdown
12396
- */
12397
- KTSelect.prototype._focusPreviousOption = function () {
12398
- return this._focusManager.focusPrevious();
12399
- };
12400
- /**
12401
- * Apply hover/focus state to focused option
12402
- */
12403
- KTSelect.prototype._hoverFocusedOption = function (option) {
12404
- this._focusManager.applyFocus(option);
12405
- };
12406
- /**
12407
- * Scroll option into view when navigating
12408
- */
12409
- KTSelect.prototype._scrollOptionIntoView = function (option) {
12410
- this._focusManager.scrollIntoView(option);
12411
- };
12412
12168
  /**
12413
12169
  * Select the currently focused option
12414
12170
  */
@@ -12432,60 +12188,13 @@ var KTSelect = /** @class */ (function (_super) {
12432
12188
  if (selectedValue) {
12433
12189
  this._selectOption(selectedValue);
12434
12190
  }
12435
- // For combobox mode, update input value AFTER selection to ensure consistency
12436
- if (this._config.mode === types_1.SelectMode.COMBOBOX && this._comboboxModule) {
12437
- this._comboboxModule.updateSelectedValue(selectedText);
12438
- // Also directly update the input value for immediate visual feedback
12439
- if (this._searchInputElement) {
12440
- this._searchInputElement.value = selectedText;
12441
- }
12442
- }
12443
- }
12444
- };
12445
- /**
12446
- * ========================================================================
12447
- * COMBOBOX SPECIFIC METHODS
12448
- * ========================================================================
12449
- */
12450
- /**
12451
- * Handle combobox input events
12452
- */
12453
- KTSelect.prototype._handleComboboxInput = function (event) {
12454
- if (this._comboboxModule) {
12455
- return;
12456
- }
12457
- var inputElement = event.target;
12458
- var query = inputElement.value.toLowerCase();
12459
- // If dropdown isn't open, open it when user starts typing
12460
- if (!this._dropdownIsOpen) {
12461
- this.openDropdown();
12462
12191
  }
12463
- // Filter options based on input
12464
- this._filterOptionsForCombobox(query);
12465
- };
12466
- /**
12467
- * Filter options for combobox based on input query
12468
- * Uses the shared filterOptions function
12469
- */
12470
- KTSelect.prototype._filterOptionsForCombobox = function (query) {
12471
- var options = Array.from(this._dropdownContentElement.querySelectorAll('[data-kt-select-option]'));
12472
- (0, utils_1.filterOptions)(options, query, this._config, this._dropdownContentElement);
12473
12192
  };
12474
12193
  /**
12475
12194
  * ========================================================================
12476
12195
  * EVENT HANDLERS
12477
12196
  * ========================================================================
12478
12197
  */
12479
- /**
12480
- * Handle display element click
12481
- */
12482
- KTSelect.prototype._handleDropdownClick = function (event) {
12483
- if (this._config.debug)
12484
- console.log('Display element clicked', event.target);
12485
- event.preventDefault();
12486
- event.stopPropagation(); // Prevent event bubbling
12487
- this.toggleDropdown();
12488
- };
12489
12198
  /**
12490
12199
  * Handle click within the dropdown
12491
12200
  */
@@ -12526,6 +12235,13 @@ var KTSelect = /** @class */ (function (_super) {
12526
12235
  }
12527
12236
  if (this._config.debug)
12528
12237
  console.log('Option clicked:', optionValue);
12238
+ // If in single-select mode and the clicked option is already selected, just close the dropdown.
12239
+ if (!this._config.multiple && this._state.isSelected(optionValue)) {
12240
+ if (this._config.debug)
12241
+ console.log('Single select mode: clicked already selected option. Closing dropdown.');
12242
+ this.closeDropdown();
12243
+ return;
12244
+ }
12529
12245
  // Use toggleSelection instead of _selectOption to prevent re-rendering
12530
12246
  this.toggleSelection(optionValue);
12531
12247
  };
@@ -12539,14 +12255,6 @@ var KTSelect = /** @class */ (function (_super) {
12539
12255
  this.closeDropdown();
12540
12256
  }
12541
12257
  };
12542
- /**
12543
- * Handle escape key press
12544
- */
12545
- KTSelect.prototype._handleEscKey = function (event) {
12546
- if (event.key === 'Escape' && this._dropdownIsOpen) {
12547
- this.closeDropdown();
12548
- }
12549
- };
12550
12258
  /**
12551
12259
  * ========================================================================
12552
12260
  * ACCESSIBILITY METHODS
@@ -12558,18 +12266,6 @@ var KTSelect = /** @class */ (function (_super) {
12558
12266
  KTSelect.prototype._setAriaAttributes = function () {
12559
12267
  this._displayElement.setAttribute('aria-expanded', this._dropdownIsOpen.toString());
12560
12268
  };
12561
- /**
12562
- * Handle focus events
12563
- */
12564
- KTSelect.prototype._handleFocus = function () {
12565
- // Implementation pending
12566
- };
12567
- /**
12568
- * Handle blur events
12569
- */
12570
- KTSelect.prototype._handleBlur = function () {
12571
- // Implementation pending
12572
- };
12573
12269
  /**
12574
12270
  * ========================================================================
12575
12271
  * PUBLIC API
@@ -12609,7 +12305,13 @@ var KTSelect = /** @class */ (function (_super) {
12609
12305
  * Get value display element
12610
12306
  */
12611
12307
  KTSelect.prototype.getValueDisplayElement = function () {
12612
- return this._valueDisplayElement;
12308
+ return this._displayElement;
12309
+ };
12310
+ /**
12311
+ * Get wrapper element
12312
+ */
12313
+ KTSelect.prototype.getWrapperElement = function () {
12314
+ return this._wrapperElement;
12613
12315
  };
12614
12316
  /**
12615
12317
  * Show all options in the dropdown
@@ -12619,6 +12321,7 @@ var KTSelect = /** @class */ (function (_super) {
12619
12321
  var options = Array.from(this._wrapperElement.querySelectorAll("[data-kt-select-option]"));
12620
12322
  // Show all options by removing the hidden class and any inline styles
12621
12323
  options.forEach(function (option) {
12324
+ var _a;
12622
12325
  // Remove hidden class
12623
12326
  option.classList.remove('hidden');
12624
12327
  // Clean up any existing inline styles for backward compatibility
@@ -12632,17 +12335,17 @@ var KTSelect = /** @class */ (function (_super) {
12632
12335
  }
12633
12336
  else {
12634
12337
  // Otherwise, remove just the display property
12635
- option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
12338
+ option.setAttribute('style', (_a = styleAttr === null || styleAttr === void 0 ? void 0 : styleAttr.replace(/display:\s*[^;]+;?/gi, '')) === null || _a === void 0 ? void 0 : _a.trim());
12636
12339
  }
12637
12340
  }
12638
12341
  }
12639
12342
  });
12640
12343
  // If search input exists, clear it
12641
- if (this._searchInputElement && this._config.mode !== types_1.SelectMode.COMBOBOX) {
12344
+ if (this._searchInputElement) {
12642
12345
  this._searchInputElement.value = '';
12643
12346
  // If we have a search module, clear any search filtering
12644
12347
  if (this._searchModule) {
12645
- this._searchModule.clearSearchHighlights();
12348
+ this._searchModule.clearSearch();
12646
12349
  }
12647
12350
  }
12648
12351
  };
@@ -12662,10 +12365,16 @@ var KTSelect = /** @class */ (function (_super) {
12662
12365
  * Toggle the selection of an option
12663
12366
  */
12664
12367
  KTSelect.prototype.toggleSelection = function (value) {
12368
+ // Prevent selection if the option is disabled (in dropdown or original select)
12369
+ if (this._isOptionDisabled(value)) {
12370
+ if (this._config.debug)
12371
+ console.log('toggleSelection: Option is disabled, ignoring selection');
12372
+ return;
12373
+ }
12665
12374
  // Get current selection state
12666
12375
  var isSelected = this._state.isSelected(value);
12667
12376
  if (this._config.debug)
12668
- console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple, ", closeOnSelect: ").concat(this._config.closeOnSelect));
12377
+ console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple));
12669
12378
  // If already selected in single select mode, do nothing (can't deselect in single select)
12670
12379
  if (isSelected && !this._config.multiple) {
12671
12380
  if (this._config.debug)
@@ -12674,9 +12383,9 @@ var KTSelect = /** @class */ (function (_super) {
12674
12383
  }
12675
12384
  if (this._config.debug)
12676
12385
  console.log("Toggling selection for option: ".concat(value, ", currently selected: ").concat(isSelected));
12677
- // Ensure any search highlights are cleared when selection changes
12386
+ // Ensure any search input is cleared when selection changes
12678
12387
  if (this._searchModule) {
12679
- this._searchModule.clearSearchHighlights();
12388
+ this._searchModule.clearSearch();
12680
12389
  }
12681
12390
  // Toggle the selection in the state
12682
12391
  this._state.toggleSelectedOptions(value);
@@ -12699,15 +12408,14 @@ var KTSelect = /** @class */ (function (_super) {
12699
12408
  // Update option classes without re-rendering the dropdown content
12700
12409
  this._updateSelectedOptionClass();
12701
12410
  // For single select mode, always close the dropdown after selection
12702
- // For multiple select mode, only close if closeOnSelect is true
12703
12411
  if (!this._config.multiple) {
12704
12412
  if (this._config.debug)
12705
12413
  console.log('About to call closeDropdown() for single select mode - always close after selection');
12706
12414
  this.closeDropdown();
12707
12415
  }
12708
- else if (this._config.closeOnSelect) {
12416
+ else {
12709
12417
  if (this._config.debug)
12710
- console.log('About to call closeDropdown() for multiple select with closeOnSelect:true');
12418
+ console.log('About to call closeDropdown() for multiple select');
12711
12419
  this.closeDropdown();
12712
12420
  }
12713
12421
  // Dispatch custom change event with additional data
@@ -12807,9 +12515,9 @@ var KTSelect = /** @class */ (function (_super) {
12807
12515
  .then(function () {
12808
12516
  // Update options in the dropdown
12809
12517
  _this._updateSearchResults(items);
12810
- // Refresh the search module's option cache if search is enabled
12811
- if (_this._searchModule && _this._config.enableSearch) {
12812
- _this._searchModule.refreshOptionCache();
12518
+ // Refresh the search module to update focus and cache
12519
+ if (_this._searchModule) {
12520
+ _this._searchModule.refreshAfterSearch();
12813
12521
  }
12814
12522
  })
12815
12523
  .catch(function (error) {
@@ -12829,7 +12537,7 @@ var KTSelect = /** @class */ (function (_super) {
12829
12537
  */
12830
12538
  KTSelect.prototype._renderSearchLoadingState = function () {
12831
12539
  if (!this._originalOptionsHtml && this._dropdownContentElement) {
12832
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
12540
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
12833
12541
  if (optionsContainer) {
12834
12542
  this._originalOptionsHtml = optionsContainer.innerHTML;
12835
12543
  }
@@ -12848,36 +12556,26 @@ var KTSelect = /** @class */ (function (_super) {
12848
12556
  * @param items Search result items
12849
12557
  */
12850
12558
  KTSelect.prototype._updateSearchResults = function (items) {
12851
- var _this = this;
12852
12559
  if (!this._dropdownContentElement)
12853
12560
  return;
12854
- var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options-container]');
12561
+ var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
12855
12562
  if (!optionsContainer)
12856
12563
  return;
12857
12564
  // Clear current options
12858
12565
  optionsContainer.innerHTML = '';
12859
12566
  if (items.length === 0) {
12860
12567
  // Show no results message using template for consistency and customization
12861
- var noResultsElement = templates_1.defaultTemplates.noResults(this._config);
12568
+ var noResultsElement = templates_1.defaultTemplates.empty(this._config);
12862
12569
  optionsContainer.appendChild(noResultsElement);
12863
12570
  return;
12864
12571
  }
12865
12572
  // Process each item individually to create options
12866
12573
  items.forEach(function (item) {
12867
12574
  // Create option for the original select
12868
- var selectOption = templates_1.defaultTemplates.emptyOption(__assign(__assign({}, _this._config), { placeholder: item.title }));
12575
+ var selectOption = document.createElement('option');
12869
12576
  selectOption.value = item.id;
12870
- if (item.description) {
12871
- selectOption.setAttribute('data-kt-select-option-description', item.description);
12872
- }
12873
- if (item.icon) {
12874
- selectOption.setAttribute('data-kt-select-option-icon', item.icon);
12875
- }
12876
- // Create option element for the dropdown
12877
- var ktOption = new option_1.KTSelectOption(selectOption, _this._config);
12878
- var renderedOption = ktOption.render();
12879
12577
  // Add to dropdown container
12880
- optionsContainer.appendChild(renderedOption);
12578
+ optionsContainer.appendChild(selectOption);
12881
12579
  });
12882
12580
  // Add pagination "Load More" button if needed
12883
12581
  if (this._config.pagination && this._remoteModule.hasMorePages()) {
@@ -12886,70 +12584,205 @@ var KTSelect = /** @class */ (function (_super) {
12886
12584
  // Update options NodeList
12887
12585
  this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
12888
12586
  };
12889
- /**
12890
- * Filter options by query
12891
- */
12892
- KTSelect.prototype.filterOptions = function (query) {
12893
- this._filterOptionsForCombobox(query);
12894
- };
12895
12587
  /**
12896
12588
  * Check if dropdown is open
12897
12589
  */
12898
12590
  KTSelect.prototype.isDropdownOpen = function () {
12899
12591
  return this._dropdownIsOpen;
12900
12592
  };
12593
+ KTSelect.prototype.getSelectedOptionsText = function () {
12594
+ var _this = this;
12595
+ var selectedValues = this.getSelectedOptions();
12596
+ var displaySeparator = this._config.displaySeparator || ', ';
12597
+ var texts = selectedValues.map(function (value) {
12598
+ var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
12599
+ return (option === null || option === void 0 ? void 0 : option.getAttribute('data-text')) || '';
12600
+ }).filter(Boolean);
12601
+ return texts.join(displaySeparator);
12602
+ };
12901
12603
  /**
12902
- * ========================================================================
12903
- * STATIC METHODS
12904
- * ========================================================================
12604
+ * Check if an option is disabled (either in dropdown or original select)
12905
12605
  */
12906
- KTSelect._instances = new Map();
12907
- return KTSelect;
12908
- }(component_1.default));
12909
- exports.KTSelect = KTSelect;
12910
-
12911
-
12912
- /***/ }),
12913
-
12914
- /***/ 8069:
12915
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
12916
-
12917
-
12918
- /**
12919
- * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
12920
- * Copyright 2025 by Keenthemes Inc
12921
- */
12922
- Object.defineProperty(exports, "__esModule", ({ value: true }));
12923
- exports.KTTooltip = void 0;
12924
- var tooltip_1 = __webpack_require__(1850);
12925
- Object.defineProperty(exports, "KTTooltip", ({ enumerable: true, get: function () { return tooltip_1.KTTooltip; } }));
12926
-
12927
-
12928
- /***/ }),
12929
-
12930
- /***/ 8135:
12931
- /***/ (function(__unused_webpack_module, exports) {
12932
-
12933
-
12934
- /**
12935
- * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
12936
- * Copyright 2025 by Keenthemes Inc
12937
- */
12938
- Object.defineProperty(exports, "__esModule", ({ value: true }));
12939
- exports.SelectMode = void 0;
12940
- /**
12941
- * Common type interfaces for the KTSelect component
12942
- */
12943
- /**
12944
- * Select mode options
12945
- */
12946
- var SelectMode;
12947
- (function (SelectMode) {
12948
- SelectMode["TAGS"] = "tags";
12949
- SelectMode["COMBOBOX"] = "combobox";
12950
- })(SelectMode || (exports.SelectMode = SelectMode = {}));
12951
-
12952
-
12606
+ KTSelect.prototype._isOptionDisabled = function (value) {
12607
+ var dropdownOption = Array.from(this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
12608
+ var isDropdownDisabled = dropdownOption && (dropdownOption.classList.contains('disabled') || dropdownOption.getAttribute('aria-disabled') === 'true');
12609
+ var selectOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
12610
+ var isNativeDisabled = selectOption && selectOption.disabled;
12611
+ return Boolean(isDropdownDisabled || isNativeDisabled);
12612
+ };
12613
+ /**
12614
+ * Centralized keyboard event handler for all select modes
12615
+ */
12616
+ KTSelect.prototype._handleKeyboardEvent = function (event) {
12617
+ // If the event target is the search input and the event was already handled (defaultPrevented),
12618
+ // then return early to avoid duplicate processing by this broader handler.
12619
+ if (event.target === this._searchInputElement && event.defaultPrevented) {
12620
+ return;
12621
+ }
12622
+ var isOpen = this._dropdownIsOpen;
12623
+ var config = this._config;
12624
+ var focusManager = this._focusManager;
12625
+ var buffer = this._typeToSearchBuffer;
12626
+ // If the event target is the search input, let it handle most typing keys naturally.
12627
+ if (event.target === this._searchInputElement) {
12628
+ // Allow navigation keys like ArrowDown, ArrowUp, Escape, Enter (for search/selection) to be handled by the logic below.
12629
+ // For other keys (characters, space, backspace, delete), let the input field process them.
12630
+ if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp' &&
12631
+ event.key !== 'Escape' && event.key !== 'Enter' && event.key !== 'Tab' &&
12632
+ event.key !== 'Home' && event.key !== 'End') {
12633
+ // If it's a character key and we are NOT type-to-searching (because search has focus)
12634
+ // then let the input field handle it for its own value.
12635
+ // The search module's 'input' event will handle filtering based on the input's value.
12636
+ buffer.clear(); // Clear type-to-search buffer when typing in search field
12637
+ return;
12638
+ }
12639
+ // For Enter specifically in search input, we might want to select the focused option or submit search.
12640
+ // This is handled later in the switch.
12641
+ }
12642
+ // Ignore modifier keys (except for specific combinations if added later)
12643
+ if (event.altKey || event.ctrlKey || event.metaKey)
12644
+ return;
12645
+ // Type-to-search: only for single char keys, when search input does not have focus
12646
+ if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/) && document.activeElement !== this._searchInputElement) {
12647
+ buffer.push(event.key);
12648
+ var str = buffer.getBuffer();
12649
+ if (isOpen) {
12650
+ focusManager.focusByString(str);
12651
+ }
12652
+ else {
12653
+ // If closed, type-to-search could potentially open and select.
12654
+ // For now, let's assume it only works when open or opens it first.
12655
+ // Or, we could find the matching option and set it directly without opening.
12656
+ }
12657
+ return; // Type-to-search handles the event
12658
+ }
12659
+ switch (event.key) {
12660
+ case 'ArrowDown':
12661
+ event.preventDefault();
12662
+ if (!isOpen) {
12663
+ this.openDropdown();
12664
+ }
12665
+ else {
12666
+ focusManager.focusNext();
12667
+ }
12668
+ break;
12669
+ case 'ArrowUp':
12670
+ event.preventDefault();
12671
+ if (!isOpen) {
12672
+ this.openDropdown();
12673
+ }
12674
+ else {
12675
+ focusManager.focusPrevious();
12676
+ }
12677
+ break;
12678
+ case 'Home':
12679
+ event.preventDefault();
12680
+ if (isOpen)
12681
+ focusManager.focusFirst();
12682
+ break;
12683
+ case 'End':
12684
+ event.preventDefault();
12685
+ if (isOpen)
12686
+ focusManager.focusLast();
12687
+ break;
12688
+ case 'Enter':
12689
+ case ' ': // Space
12690
+ if (isOpen) {
12691
+ var focusedOptionEl = this._focusManager.getFocusedOption();
12692
+ if (focusedOptionEl) {
12693
+ var val = focusedOptionEl.dataset.value;
12694
+ // If single select, and the item is already selected, just close.
12695
+ if (val !== undefined && !this._config.multiple && this._state.isSelected(val)) {
12696
+ if (this._config.debug)
12697
+ console.log('Enter on already selected item in single-select mode. Closing.');
12698
+ this.closeDropdown();
12699
+ event.preventDefault();
12700
+ break;
12701
+ }
12702
+ }
12703
+ // Proceed with selection if not handled above
12704
+ this.selectFocusedOption();
12705
+ // Close dropdown if configured to do so (for new selections)
12706
+ if (!this._config.multiple) {
12707
+ // This will also be true for the case handled above, but closeDropdown is idempotent.
12708
+ // However, the break above prevents this from being reached for that specific case.
12709
+ this.closeDropdown();
12710
+ }
12711
+ event.preventDefault(); // Prevent form submission or other default actions
12712
+ break;
12713
+ }
12714
+ else {
12715
+ this.openDropdown();
12716
+ }
12717
+ break;
12718
+ case 'Escape':
12719
+ if (isOpen) {
12720
+ this.closeDropdown();
12721
+ event.target.blur();
12722
+ }
12723
+ break;
12724
+ case 'Tab':
12725
+ // Let Tab propagate for normal focus movement
12726
+ break;
12727
+ default:
12728
+ break;
12729
+ }
12730
+ };
12731
+ KTSelect.prototype.renderDisplayTemplateForSelected = function (selectedValues) {
12732
+ var _this = this;
12733
+ var optionsConfig = this._config.optionsConfig || {};
12734
+ var displaySeparator = this._config.displaySeparator || ', ';
12735
+ var contentArray = Array.from(new Set(selectedValues.map(function (value) {
12736
+ var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
12737
+ if (!option)
12738
+ return '';
12739
+ var displayTemplate = _this._config.displayTemplate;
12740
+ var text = option.getAttribute('data-text') || '';
12741
+ // Replace all {{varname}} in option.innerHTML with values from _config
12742
+ Object.entries(optionsConfig[value] || {}).forEach(function (_a) {
12743
+ var key = _a[0], val = _a[1];
12744
+ if (["string", "number", "boolean"].includes(typeof val)) {
12745
+ displayTemplate = displayTemplate.replace(new RegExp("{{".concat(key, "}}"), 'g'), String(val));
12746
+ }
12747
+ });
12748
+ return (0, utils_1.renderTemplateString)(displayTemplate, {
12749
+ selectedCount: selectedValues.length || 0,
12750
+ selectedTexts: _this.getSelectedOptionsText() || '',
12751
+ text: text,
12752
+ });
12753
+ }).filter(Boolean)));
12754
+ return contentArray.join(displaySeparator);
12755
+ };
12756
+ KTSelect.prototype.getDisplayElement = function () {
12757
+ return this._displayElement;
12758
+ };
12759
+ /**
12760
+ * ========================================================================
12761
+ * STATIC METHODS
12762
+ * ========================================================================
12763
+ */
12764
+ KTSelect._instances = new Map();
12765
+ return KTSelect;
12766
+ }(component_1.default));
12767
+ exports.KTSelect = KTSelect;
12768
+
12769
+
12770
+ /***/ }),
12771
+
12772
+ /***/ 8069:
12773
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
12774
+
12775
+
12776
+ /**
12777
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
12778
+ * Copyright 2025 by Keenthemes Inc
12779
+ */
12780
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
12781
+ exports.KTTooltip = void 0;
12782
+ var tooltip_1 = __webpack_require__(1850);
12783
+ Object.defineProperty(exports, "KTTooltip", ({ enumerable: true, get: function () { return tooltip_1.KTTooltip; } }));
12784
+
12785
+
12953
12786
  /***/ }),
12954
12787
 
12955
12788
  /***/ 8151:
@@ -13503,7 +13336,7 @@ exports.KTDatepickerKeyboard = KTDatepickerKeyboard;
13503
13336
  * Copyright 2025 by Keenthemes Inc
13504
13337
  */
13505
13338
  Object.defineProperty(exports, "__esModule", ({ value: true }));
13506
- exports.KTSelect = exports.KTDatepicker = exports.KTDataTable = exports.KTTogglePassword = exports.KTImageInput = exports.KTThemeSwitch = exports.KTStepper = exports.KTTooltip = exports.KTToggle = exports.KTReparent = exports.KTSticky = exports.KTScrollto = exports.KTScrollable = exports.KTScrollspy = exports.KTAccordion = exports.KTTabs = exports.KTDismiss = exports.KTCollapse = exports.KTDrawer = exports.KTModal = exports.KTDropdown = void 0;
13339
+ exports.KTToast = exports.KTSelect = exports.KTDatepicker = exports.KTDataTable = exports.KTTogglePassword = exports.KTImageInput = exports.KTThemeSwitch = exports.KTStepper = exports.KTTooltip = exports.KTToggle = exports.KTReparent = exports.KTSticky = exports.KTScrollto = exports.KTScrollable = exports.KTScrollspy = exports.KTAccordion = exports.KTTabs = exports.KTDismiss = exports.KTCollapse = exports.KTDrawer = exports.KTModal = exports.KTDropdown = void 0;
13507
13340
  var dom_1 = __webpack_require__(9010);
13508
13341
  var dropdown_1 = __webpack_require__(5071);
13509
13342
  var modal_1 = __webpack_require__(3395);
@@ -13526,6 +13359,7 @@ var toggle_password_1 = __webpack_require__(2232);
13526
13359
  var datatable_1 = __webpack_require__(2626);
13527
13360
  var datepicker_1 = __webpack_require__(5116);
13528
13361
  var select_1 = __webpack_require__(494);
13362
+ var toast_1 = __webpack_require__(6265);
13529
13363
  var dropdown_2 = __webpack_require__(5071);
13530
13364
  Object.defineProperty(exports, "KTDropdown", ({ enumerable: true, get: function () { return dropdown_2.KTDropdown; } }));
13531
13365
  var modal_2 = __webpack_require__(3395);
@@ -13568,6 +13402,8 @@ var datepicker_2 = __webpack_require__(5116);
13568
13402
  Object.defineProperty(exports, "KTDatepicker", ({ enumerable: true, get: function () { return datepicker_2.KTDatepicker; } }));
13569
13403
  var select_2 = __webpack_require__(494);
13570
13404
  Object.defineProperty(exports, "KTSelect", ({ enumerable: true, get: function () { return select_2.KTSelect; } }));
13405
+ var toast_2 = __webpack_require__(6265);
13406
+ Object.defineProperty(exports, "KTToast", ({ enumerable: true, get: function () { return toast_2.KTToast; } }));
13571
13407
  var KTComponents = {
13572
13408
  init: function () {
13573
13409
  dropdown_1.KTDropdown.init();
@@ -13591,6 +13427,7 @@ var KTComponents = {
13591
13427
  datatable_1.KTDataTable.init();
13592
13428
  datepicker_1.KTDatepicker.init();
13593
13429
  select_1.KTSelect.init();
13430
+ toast_1.KTToast.init();
13594
13431
  },
13595
13432
  };
13596
13433
  exports["default"] = KTComponents;
@@ -14789,85 +14626,616 @@ var KTSelectTags = /** @class */ (function () {
14789
14626
  */
14790
14627
  KTSelectTags.prototype.updateTagsDisplay = function (selectedOptions) {
14791
14628
  var _this = this;
14792
- // Clear existing content
14793
- this._valueDisplayElement.innerHTML = '';
14794
- // If no options selected, show placeholder
14629
+ // Remove any existing tag elements
14630
+ var wrapper = this._valueDisplayElement.parentElement;
14631
+ if (!wrapper)
14632
+ return;
14633
+ // Remove all previous tags
14634
+ Array.from(wrapper.querySelectorAll('[data-kt-select-tag]')).forEach(function (tag) { return tag.remove(); });
14635
+ // If no options selected, do nothing (let display show placeholder)
14795
14636
  if (selectedOptions.length === 0) {
14796
- this._valueDisplayElement.textContent = this._config.placeholder || '';
14797
14637
  return;
14798
14638
  }
14799
- // Create and append a tag element for each selected option
14639
+ // Insert each tag before the display element
14800
14640
  selectedOptions.forEach(function (optionValue) {
14801
- var tagElement = _this._createTagElement(optionValue);
14802
- _this._valueDisplayElement.appendChild(tagElement);
14641
+ // Find the original option element (in dropdown or select)
14642
+ var optionElement = null;
14643
+ var optionElements = _this._select.getOptionsElement();
14644
+ for (var _i = 0, _a = Array.from(optionElements); _i < _a.length; _i++) {
14645
+ var opt = _a[_i];
14646
+ if (opt.dataset.value === optionValue) {
14647
+ optionElement = opt;
14648
+ break;
14649
+ }
14650
+ }
14651
+ if (!optionElement) {
14652
+ var originalOptions = _this._select.getElement().querySelectorAll('option');
14653
+ for (var _b = 0, _c = Array.from(originalOptions); _b < _c.length; _b++) {
14654
+ var opt = _c[_b];
14655
+ if (opt.value === optionValue) {
14656
+ optionElement = opt;
14657
+ break;
14658
+ }
14659
+ }
14660
+ }
14661
+ var tag = templates_1.defaultTemplates.tag(optionElement, _this._config);
14662
+ // Add event listener to the close button
14663
+ var closeButton = tag.querySelector('[data-kt-select-remove-button]');
14664
+ if (closeButton) {
14665
+ _this._eventManager.addListener(closeButton, 'click', function (event) {
14666
+ event.stopPropagation();
14667
+ _this._removeTag(optionValue);
14668
+ });
14669
+ }
14670
+ // Insert tag before the display element
14671
+ wrapper.insertBefore(tag, _this._valueDisplayElement);
14803
14672
  });
14804
14673
  };
14805
14674
  /**
14806
- * Create tag element for a selected option
14675
+ * Remove a tag and its selection
14807
14676
  */
14808
- KTSelectTags.prototype._createTagElement = function (optionValue) {
14677
+ KTSelectTags.prototype._removeTag = function (optionValue) {
14678
+ // Delegate to the select component to handle state changes
14679
+ this._select.toggleSelection(optionValue);
14680
+ };
14681
+ /**
14682
+ * Clean up resources used by this module
14683
+ */
14684
+ KTSelectTags.prototype.destroy = function () {
14685
+ this._eventManager.removeAllListeners(null);
14686
+ };
14687
+ return KTSelectTags;
14688
+ }());
14689
+ exports.KTSelectTags = KTSelectTags;
14690
+
14691
+
14692
+ /***/ }),
14693
+
14694
+ /***/ 8834:
14695
+ /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
14696
+
14697
+
14698
+ /**
14699
+ * KTUI - Free & Open-Source Tailwind UI Components by Keenthemes
14700
+ * Copyright 2025 by Keenthemes Inc
14701
+ */
14702
+ var __extends = (this && this.__extends) || (function () {
14703
+ var extendStatics = function (d, b) {
14704
+ extendStatics = Object.setPrototypeOf ||
14705
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
14706
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
14707
+ return extendStatics(d, b);
14708
+ };
14709
+ return function (d, b) {
14710
+ if (typeof b !== "function" && b !== null)
14711
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
14712
+ extendStatics(d, b);
14713
+ function __() { this.constructor = d; }
14714
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
14715
+ };
14716
+ })();
14717
+ var __assign = (this && this.__assign) || function () {
14718
+ __assign = Object.assign || function(t) {
14719
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
14720
+ s = arguments[i];
14721
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
14722
+ t[p] = s[p];
14723
+ }
14724
+ return t;
14725
+ };
14726
+ return __assign.apply(this, arguments);
14727
+ };
14728
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
14729
+ exports.KTToast = void 0;
14730
+ var component_1 = __webpack_require__(2658);
14731
+ var data_1 = __webpack_require__(8716);
14732
+ var DEFAULT_CONFIG = {
14733
+ position: 'top-end',
14734
+ duration: 4000,
14735
+ className: '',
14736
+ maxToasts: 5,
14737
+ offset: 15,
14738
+ gap: 10,
14739
+ };
14740
+ var DEFAULT_TOAST_OPTIONS = {
14741
+ appearance: 'solid',
14742
+ progress: false,
14743
+ size: 'md',
14744
+ action: false,
14745
+ cancel: false,
14746
+ dismiss: true,
14747
+ };
14748
+ var KTToast = /** @class */ (function (_super) {
14749
+ __extends(KTToast, _super);
14750
+ /**
14751
+ * Creates a new KTToast instance for a specific element (not commonly used; most use static API).
14752
+ * @param element The target HTML element.
14753
+ * @param config Optional toast config for this instance.
14754
+ */
14755
+ function KTToast(element, config) {
14756
+ var _this = _super.call(this) || this;
14757
+ _this._name = 'toast';
14758
+ _this._defaultConfig = DEFAULT_CONFIG;
14759
+ _this._config = DEFAULT_CONFIG;
14760
+ _this._defaultToastOptions = DEFAULT_TOAST_OPTIONS;
14761
+ if (data_1.default.has(element, _this._name))
14762
+ return _this;
14763
+ _this._init(element);
14764
+ _this._buildConfig(config);
14765
+ data_1.default.set(element, _this._name, _this);
14766
+ return _this;
14767
+ }
14768
+ /**
14769
+ * Generates the HTML content for a toast based on the provided options.
14770
+ * @param options Toast options (message, icon, actions, etc).
14771
+ * @returns The toast's HTML markup as a string.
14772
+ */
14773
+ KTToast.getContent = function (options) {
14774
+ var classNames = __assign(__assign({}, (this.globalConfig.classNames || {})), ((options === null || options === void 0 ? void 0 : options.classNames) || {}));
14775
+ if (options === null || options === void 0 ? void 0 : options.content) {
14776
+ if (typeof options.content === 'string') {
14777
+ return options.content;
14778
+ }
14779
+ else if (typeof options.content === 'function') {
14780
+ var node = options.content();
14781
+ if (node instanceof HTMLElement) {
14782
+ return node.outerHTML;
14783
+ }
14784
+ }
14785
+ else if (options.content instanceof HTMLElement) {
14786
+ return options.content.outerHTML;
14787
+ }
14788
+ }
14789
+ var template = '';
14790
+ if (options === null || options === void 0 ? void 0 : options.icon) {
14791
+ template +=
14792
+ '<div class="kt-alert-icon ' +
14793
+ (classNames.icon || '') +
14794
+ '">' +
14795
+ options.icon +
14796
+ '</div>';
14797
+ }
14798
+ if (options === null || options === void 0 ? void 0 : options.message) {
14799
+ template +=
14800
+ '<div class="kt-alert-title ' +
14801
+ (classNames.message || '') +
14802
+ '">' +
14803
+ options.message +
14804
+ '</div>';
14805
+ }
14806
+ if ((options === null || options === void 0 ? void 0 : options.action) !== false ||
14807
+ (options === null || options === void 0 ? void 0 : options.dismiss) !== false ||
14808
+ (options === null || options === void 0 ? void 0 : options.cancel) !== false) {
14809
+ template +=
14810
+ '<div class="kt-alert-toolbar ' + (classNames.toolbar || '') + '">';
14811
+ template +=
14812
+ '<div class="kt-alert-actions ' + (classNames.actions || '') + '">';
14813
+ if ((options === null || options === void 0 ? void 0 : options.action) && typeof options.action === 'object') {
14814
+ template +=
14815
+ '<button data-kt-toast-action="true" class="' +
14816
+ (options.action.className || '') +
14817
+ '">' +
14818
+ options.action.label +
14819
+ '</button>';
14820
+ }
14821
+ if ((options === null || options === void 0 ? void 0 : options.cancel) && typeof options.cancel === 'object') {
14822
+ template +=
14823
+ '<button data-kt-toast-cancel="true" class="' +
14824
+ (options.cancel.className || '') +
14825
+ '">' +
14826
+ options.cancel.label +
14827
+ '</button>';
14828
+ }
14829
+ if ((options === null || options === void 0 ? void 0 : options.dismiss) !== false) {
14830
+ template +=
14831
+ '<button data-kt-toast-dismiss="true" class="kt-alert-close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg></button>';
14832
+ }
14833
+ template += '</div>';
14834
+ template += '</div>';
14835
+ }
14836
+ template += '</div>';
14837
+ return template;
14838
+ };
14839
+ /**
14840
+ * Update all toasts in the container with smooth animation.
14841
+ *
14842
+ * @param container The toast container element.
14843
+ * @param offset Optional offset from the edge.
14844
+ */
14845
+ KTToast.update = function (container, offset) {
14809
14846
  var _this = this;
14810
- var optionLabel = this._getOptionLabel(optionValue);
14811
- // Create a mock option object to pass to the tag template
14812
- var mockOption = {
14813
- id: optionValue,
14814
- title: optionLabel,
14815
- selected: true,
14816
- };
14817
- // Use the tag template
14818
- var tag = templates_1.defaultTemplates.tag(mockOption, this._config);
14819
- // Add event listener to the close button
14820
- var closeButton = tag.querySelector("[data-kt-select-remove-button]");
14821
- if (closeButton) {
14822
- this._eventManager.addListener(closeButton, 'click', function (event) {
14823
- event.stopPropagation();
14824
- _this._removeTag(optionValue);
14847
+ var _a;
14848
+ if (!container)
14849
+ return;
14850
+ offset =
14851
+ typeof offset === 'number' ? offset : ((_a = this.globalConfig.offset) !== null && _a !== void 0 ? _a : 15);
14852
+ requestAnimationFrame(function () {
14853
+ var _a;
14854
+ var gap = (_a = _this.globalConfig.gap) !== null && _a !== void 0 ? _a : 8;
14855
+ // Group toasts by alignment (top/bottom)
14856
+ var positionGroups = {
14857
+ top: [],
14858
+ bottom: [],
14859
+ };
14860
+ var toasts = Array.from(container.children);
14861
+ toasts.forEach(function (toast) {
14862
+ if (toast.classList.contains('kt-toast-top-end') ||
14863
+ toast.classList.contains('kt-toast-top-center') ||
14864
+ toast.classList.contains('kt-toast-top-start')) {
14865
+ positionGroups.top.push(toast);
14866
+ }
14867
+ else {
14868
+ positionGroups.bottom.push(toast);
14869
+ }
14825
14870
  });
14826
- }
14827
- return tag;
14871
+ // Stack top toasts from the top down
14872
+ var currentOffset = offset;
14873
+ positionGroups.top.forEach(function (toast) {
14874
+ toast.style.top = "".concat(currentOffset, "px");
14875
+ toast.style.bottom = '';
14876
+ toast.style.transition =
14877
+ 'top 0.28s cubic-bezier(.4,0,.2,1), opacity 0.28s cubic-bezier(.4,0,.2,1)';
14878
+ currentOffset += toast.offsetHeight + gap;
14879
+ if (toast.classList.contains('kt-toast-top-start')) {
14880
+ toast.style.insetInlineStart = "".concat(offset, "px");
14881
+ }
14882
+ if (toast.classList.contains('kt-toast-top-end')) {
14883
+ toast.style.insetInlineEnd = "".concat(offset, "px");
14884
+ }
14885
+ });
14886
+ // Stack bottom toasts from the bottom up
14887
+ currentOffset = offset;
14888
+ for (var i = positionGroups.bottom.length - 1; i >= 0; i--) {
14889
+ var toast = positionGroups.bottom[i];
14890
+ toast.style.bottom = "".concat(currentOffset, "px");
14891
+ toast.style.top = '';
14892
+ toast.style.transition =
14893
+ 'bottom 0.28s cubic-bezier(.4,0,.2,1), opacity 0.28s cubic-bezier(.4,0,.2,1)';
14894
+ currentOffset += toast.offsetHeight + gap;
14895
+ if (toast.classList.contains('kt-toast-bottom-start')) {
14896
+ toast.style.insetInlineStart = "".concat(offset, "px");
14897
+ }
14898
+ if (toast.classList.contains('kt-toast-bottom-end')) {
14899
+ toast.style.insetInlineEnd = "".concat(offset, "px");
14900
+ }
14901
+ }
14902
+ });
14828
14903
  };
14829
14904
  /**
14830
- * Get the label/text for an option by its value
14905
+ * Set global toast configuration options.
14906
+ * @param options Partial toast config to merge with global config.
14831
14907
  */
14832
- KTSelectTags.prototype._getOptionLabel = function (optionValue) {
14833
- var _a, _b;
14834
- // First look for an option element in the dropdown with matching value
14835
- var optionElements = this._select.getOptionsElement();
14836
- for (var _i = 0, _c = Array.from(optionElements); _i < _c.length; _i++) {
14837
- var option = _c[_i];
14838
- if (option.dataset.value === optionValue) {
14839
- return ((_a = option.textContent) === null || _a === void 0 ? void 0 : _a.trim()) || optionValue;
14908
+ KTToast.config = function (options) {
14909
+ this.globalConfig = __assign(__assign({}, this.globalConfig), options);
14910
+ };
14911
+ /**
14912
+ * Show a toast notification.
14913
+ * @param inputOptions Toast options (message, duration, variant, etc).
14914
+ * @returns Toast instance with dismiss method, or undefined if invalid input.
14915
+ */
14916
+ KTToast.show = function (inputOptions) {
14917
+ var _a, _b, _c, _d;
14918
+ var options = __assign(__assign({}, DEFAULT_TOAST_OPTIONS), inputOptions);
14919
+ if (!options || (!options.message && !options.content)) {
14920
+ return undefined;
14921
+ }
14922
+ // Always resolve the id once and use it everywhere
14923
+ var id = "kt-toast-".concat(Date.now(), "-").concat(Math.random().toString(36).slice(2, 8));
14924
+ var position = options.position || this.globalConfig.position || 'top-end';
14925
+ var classNames = __assign(__assign({}, (this.globalConfig.classNames || {})), (options.classNames || {}));
14926
+ var container = this.containerMap.get(position);
14927
+ if (!container) {
14928
+ container = document.createElement('div');
14929
+ var classNames_1 = __assign(__assign({}, (this.globalConfig.classNames || {})), (options.classNames || {}));
14930
+ // Fallback to default hardcoded classes if not provided in options or globalConfig
14931
+ container.className =
14932
+ classNames_1.container || "kt-toast-container ".concat(position);
14933
+ document.body.appendChild(container);
14934
+ this.containerMap.set(position, container);
14935
+ }
14936
+ // Enforce maxToasts
14937
+ if (container.children.length >=
14938
+ (this.globalConfig.maxToasts || DEFAULT_CONFIG.maxToasts)) {
14939
+ var firstToast_1 = container.firstElementChild;
14940
+ if (firstToast_1) {
14941
+ firstToast_1.classList.add('kt-toast-closing');
14942
+ firstToast_1.addEventListener('animationend', function () {
14943
+ firstToast_1.remove();
14944
+ });
14840
14945
  }
14841
14946
  }
14842
- // If not found in dropdown, look in original select element
14843
- var originalOptions = this._select
14844
- .getElement()
14845
- .querySelectorAll('option');
14846
- for (var _d = 0, _e = Array.from(originalOptions); _d < _e.length; _d++) {
14847
- var option = _e[_d];
14848
- if (option.value === optionValue) {
14849
- return ((_b = option.textContent) === null || _b === void 0 ? void 0 : _b.trim()) || optionValue;
14947
+ // Create toast element
14948
+ var variantMap = {
14949
+ info: 'kt-alert-info',
14950
+ success: 'kt-alert-success',
14951
+ error: 'kt-alert-error',
14952
+ warning: 'kt-alert-warning',
14953
+ primary: 'kt-alert-primary',
14954
+ secondary: 'kt-alert-secondary',
14955
+ destructive: 'kt-alert-destructive',
14956
+ mono: 'kt-alert-mono',
14957
+ };
14958
+ var appearanceMap = {
14959
+ solid: 'kt-alert-solid',
14960
+ outline: 'kt-alert-outline',
14961
+ light: 'kt-alert-light',
14962
+ };
14963
+ var sizeMap = {
14964
+ sm: 'kt-alert-sm',
14965
+ md: 'kt-alert-md',
14966
+ lg: 'kt-alert-lg',
14967
+ };
14968
+ var toast = document.createElement('div');
14969
+ toast.className = "kt-toast kt-alert ".concat(variantMap[options.variant] || '', " ").concat(appearanceMap[options.appearance] || '', " ").concat(sizeMap[options.size] || '', " ").concat(options.className || '', " ").concat(classNames.toast || '');
14970
+ // ARIA support
14971
+ toast.setAttribute('role', options.role || 'status');
14972
+ toast.setAttribute('aria-live', 'polite');
14973
+ toast.setAttribute('aria-atomic', 'true');
14974
+ toast.setAttribute('tabindex', '0');
14975
+ // Always resolve the id once and use it everywhere
14976
+ // Always resolve id ONCE at the top, use everywhere
14977
+ // (Move this up to replace the previous const id = ... assignment)
14978
+ // Populate content via getContent
14979
+ var contentHtml = KTToast.getContent(options);
14980
+ toast.innerHTML = contentHtml;
14981
+ // Assign event handlers to buttons by data attribute
14982
+ var actionBtn = toast.querySelector('[data-kt-toast-action]');
14983
+ if (actionBtn &&
14984
+ options.action &&
14985
+ typeof options.action === 'object' &&
14986
+ options.action.onClick) {
14987
+ actionBtn.addEventListener('click', function (e) {
14988
+ e.stopPropagation();
14989
+ if (typeof options.action === 'object' && options.action.onClick) {
14990
+ options.action.onClick(id);
14991
+ KTToast.close(id);
14992
+ }
14993
+ });
14994
+ }
14995
+ var cancelBtn = toast.querySelector('[data-kt-toast-cancel]');
14996
+ if (cancelBtn && options.cancel && typeof options.cancel === 'object') {
14997
+ cancelBtn.addEventListener('click', function (e) {
14998
+ e.stopPropagation();
14999
+ if (typeof options.cancel === 'object' && options.cancel.onClick) {
15000
+ options.cancel.onClick(id);
15001
+ KTToast.close(id);
15002
+ }
15003
+ });
15004
+ }
15005
+ // Dismiss button handler
15006
+ var dismissBtn = toast.querySelector('[data-kt-toast-dismiss]');
15007
+ if (dismissBtn && options.dismiss !== false) {
15008
+ dismissBtn.addEventListener('click', function (e) {
15009
+ e.stopPropagation();
15010
+ KTToast.close(id);
15011
+ });
15012
+ }
15013
+ // If modal-like, set aria-modal
15014
+ if (options.important)
15015
+ toast.setAttribute('aria-modal', 'true');
15016
+ toast.style.pointerEvents = 'auto';
15017
+ // Progress line
15018
+ var duration = options.important
15019
+ ? null
15020
+ : ((_b = (_a = options.duration) !== null && _a !== void 0 ? _a : this.globalConfig.duration) !== null && _b !== void 0 ? _b : DEFAULT_CONFIG.duration);
15021
+ if (duration && options.progress) {
15022
+ var progress = document.createElement('div');
15023
+ progress.className = 'kt-toast-progress ' + (classNames.progress || '');
15024
+ progress.style.animationDuration = duration + 'ms';
15025
+ progress.setAttribute('data-kt-toast-progress', 'true');
15026
+ toast.appendChild(progress);
15027
+ }
15028
+ // Assign direction class to the toast itself, not the container
15029
+ var directionClassMap = {
15030
+ 'top-end': 'kt-toast-top-end',
15031
+ 'top-center': 'kt-toast-top-center',
15032
+ 'top-start': 'kt-toast-top-start',
15033
+ 'bottom-end': 'kt-toast-bottom-end',
15034
+ 'bottom-center': 'kt-toast-bottom-center',
15035
+ 'bottom-start': 'kt-toast-bottom-start',
15036
+ };
15037
+ Object.values(directionClassMap).forEach(function (cls) {
15038
+ return toast.classList.remove(cls);
15039
+ });
15040
+ var dirClass = directionClassMap[position] || 'kt-toast-top-end';
15041
+ toast.classList.add(dirClass);
15042
+ // Enforce maxToasts: remove oldest if needed
15043
+ var maxToasts = (_d = (_c = options.maxToasts) !== null && _c !== void 0 ? _c : this.globalConfig.maxToasts) !== null && _d !== void 0 ? _d : DEFAULT_CONFIG.maxToasts;
15044
+ var currentToasts = Array.from(container.children);
15045
+ if (currentToasts.length >= maxToasts && currentToasts.length > 0) {
15046
+ var oldestToast = currentToasts[currentToasts.length - 1];
15047
+ var oldestId = oldestToast.getAttribute('data-kt-toast-id');
15048
+ if (oldestId) {
15049
+ KTToast.close(oldestId);
15050
+ }
15051
+ else {
15052
+ oldestToast.remove();
15053
+ }
15054
+ }
15055
+ // Insert toast at the top
15056
+ container.insertBefore(toast, container.firstChild);
15057
+ KTToast.update(container);
15058
+ // Play beep if requested
15059
+ if (options.beep) {
15060
+ try {
15061
+ // Use Web Audio API for a short beep
15062
+ var ctx_1 = new (window.AudioContext ||
15063
+ window.webkitAudioContext)();
15064
+ var o_1 = ctx_1.createOscillator();
15065
+ var g = ctx_1.createGain();
15066
+ o_1.type = 'sine';
15067
+ o_1.frequency.value = 880;
15068
+ g.gain.value = 0.09;
15069
+ o_1.connect(g);
15070
+ g.connect(ctx_1.destination);
15071
+ o_1.start();
15072
+ setTimeout(function () {
15073
+ o_1.stop();
15074
+ ctx_1.close();
15075
+ }, 120);
15076
+ }
15077
+ catch (e) {
15078
+ /* ignore */
15079
+ }
15080
+ }
15081
+ KTToast._fireEventOnElement(toast, 'show', { id: id });
15082
+ KTToast._dispatchEventOnElement(toast, 'show', { id: id });
15083
+ var instance = { id: id, element: toast, timeoutId: 0 };
15084
+ KTToast.toasts.set(id, instance);
15085
+ // Auto-dismiss
15086
+ var timeoutId = undefined;
15087
+ var remaining = duration;
15088
+ var startTime;
15089
+ var paused = false;
15090
+ var progressEl = null;
15091
+ if (duration) {
15092
+ var startTimer_1 = function (ms) {
15093
+ startTime = Date.now();
15094
+ timeoutId = window.setTimeout(function () {
15095
+ var _a;
15096
+ (_a = options.onAutoClose) === null || _a === void 0 ? void 0 : _a.call(options, id);
15097
+ KTToast.close(id);
15098
+ }, ms);
15099
+ instance.timeoutId = timeoutId;
15100
+ };
15101
+ startTimer_1(duration);
15102
+ if (options.pauseOnHover) {
15103
+ progressEl = toast.querySelector('[data-kt-toast-progress]');
15104
+ var progressPausedAt_1 = 0;
15105
+ var pause = function () {
15106
+ if (!paused && timeoutId) {
15107
+ paused = true;
15108
+ window.clearTimeout(timeoutId);
15109
+ if (startTime) {
15110
+ remaining -= Date.now() - startTime;
15111
+ }
15112
+ // Pause progress bar
15113
+ if (progressEl) {
15114
+ var computedStyle = window.getComputedStyle(progressEl);
15115
+ var matrix = computedStyle.transform;
15116
+ var scaleX = 1;
15117
+ if (matrix && matrix !== 'none') {
15118
+ var values = matrix.match(/matrix\(([^)]+)\)/);
15119
+ if (values && values[1]) {
15120
+ scaleX = parseFloat(values[1].split(',')[0]);
15121
+ }
15122
+ }
15123
+ progressPausedAt_1 = scaleX;
15124
+ progressEl.style.animation = 'none';
15125
+ progressEl.style.transition = 'none';
15126
+ progressEl.style.transform = "scaleX(".concat(scaleX, ")");
15127
+ }
15128
+ }
15129
+ };
15130
+ var resume = function () {
15131
+ if (paused && remaining > 0) {
15132
+ paused = false;
15133
+ startTimer_1(remaining);
15134
+ // Resume progress bar
15135
+ if (progressEl) {
15136
+ progressEl.style.transition = 'transform 0ms';
15137
+ progressEl.style.transform = "scaleX(".concat(progressPausedAt_1, ")");
15138
+ progressEl.offsetHeight; // force reflow
15139
+ progressEl.style.transition = "transform ".concat(remaining, "ms linear");
15140
+ progressEl.style.transform = 'scaleX(0)';
15141
+ }
15142
+ }
15143
+ };
15144
+ toast.addEventListener('mouseenter', pause);
15145
+ toast.addEventListener('mouseleave', resume);
14850
15146
  }
14851
15147
  }
14852
- // If still not found, return the value itself
14853
- return optionValue;
15148
+ KTToast._fireEventOnElement(toast, 'shown', { id: id });
15149
+ KTToast._dispatchEventOnElement(toast, 'shown', { id: id });
15150
+ return __assign(__assign({}, instance), { dismiss: function () { return KTToast.close(id); } });
14854
15151
  };
14855
15152
  /**
14856
- * Remove a tag and its selection
15153
+ * Close and remove all active toasts.
14857
15154
  */
14858
- KTSelectTags.prototype._removeTag = function (optionValue) {
14859
- // Delegate to the select component to handle state changes
14860
- this._select.toggleSelection(optionValue);
15155
+ KTToast.clearAll = function () {
15156
+ for (var _i = 0, _a = Array.from(this.toasts.keys()); _i < _a.length; _i++) {
15157
+ var id = _a[_i];
15158
+ console.log('clearAll:', id);
15159
+ this.close(id);
15160
+ }
14861
15161
  };
14862
15162
  /**
14863
- * Clean up resources used by this module
15163
+ * Close a toast by ID or instance.
15164
+ * @param idOrInstance Toast ID string or KTToastInstance.
14864
15165
  */
14865
- KTSelectTags.prototype.destroy = function () {
14866
- this._eventManager.removeAllListeners(null);
15166
+ KTToast.close = function (idOrInstance) {
15167
+ var inst;
15168
+ var id;
15169
+ if (!idOrInstance)
15170
+ return;
15171
+ if (typeof idOrInstance === 'string') {
15172
+ id = idOrInstance;
15173
+ inst = this.toasts.get(id);
15174
+ }
15175
+ else if (typeof idOrInstance === 'object' && idOrInstance.id) {
15176
+ id = idOrInstance.id;
15177
+ inst = idOrInstance;
15178
+ }
15179
+ if (!inst || !id)
15180
+ return;
15181
+ if (inst._closing)
15182
+ return; // Prevent double-close
15183
+ inst._closing = true;
15184
+ clearTimeout(inst.timeoutId);
15185
+ KTToast._fireEventOnElement(inst.element, 'hide', { id: id });
15186
+ KTToast._dispatchEventOnElement(inst.element, 'hide', { id: id });
15187
+ // Remove progress bar instantly if present
15188
+ var progressEl = inst.element.querySelector('[data-kt-toast-progress]');
15189
+ if (progressEl)
15190
+ progressEl.remove();
15191
+ inst.element.style.animation = 'kt-toast-out 0.25s forwards';
15192
+ setTimeout(function () {
15193
+ var _a;
15194
+ var parent = inst === null || inst === void 0 ? void 0 : inst.element.parentElement;
15195
+ inst === null || inst === void 0 ? void 0 : inst.element.remove();
15196
+ KTToast.toasts.delete(id);
15197
+ // Try to call onDismiss if available in the toast instance (if stored)
15198
+ if (typeof ((_a = inst.options) === null || _a === void 0 ? void 0 : _a.onDismiss) === 'function') {
15199
+ inst.options.onDismiss(id);
15200
+ }
15201
+ KTToast._fireEventOnElement(inst.element, 'hidden', { id: id });
15202
+ KTToast._dispatchEventOnElement(inst.element, 'hidden', { id: id });
15203
+ // update toasts asynchronously after DOM update
15204
+ setTimeout(function () {
15205
+ KTToast.update(parent);
15206
+ }, 0);
15207
+ }, 250);
14867
15208
  };
14868
- return KTSelectTags;
14869
- }());
14870
- exports.KTSelectTags = KTSelectTags;
15209
+ /**
15210
+ * Dispatches a custom 'kt.toast.{eventType}' event on the given element.
15211
+ * @param element The toast element.
15212
+ * @param eventType The event type (e.g. 'show', 'hide').
15213
+ * @param payload Optional event detail payload.
15214
+ */
15215
+ KTToast._fireEventOnElement = function (element, eventType, payload) {
15216
+ var event = new CustomEvent("kt.toast.".concat(eventType), { detail: payload });
15217
+ element.dispatchEvent(event);
15218
+ };
15219
+ /**
15220
+ * Dispatches a custom event (not namespaced) on the given element.
15221
+ * @param element The toast element.
15222
+ * @param eventType The event type.
15223
+ * @param payload Optional event detail payload.
15224
+ */
15225
+ KTToast._dispatchEventOnElement = function (element, eventType, payload) {
15226
+ var event = new CustomEvent(eventType, { detail: payload });
15227
+ element.dispatchEvent(event);
15228
+ };
15229
+ /**
15230
+ * Initialize toast system (placeholder for future use).
15231
+ */
15232
+ KTToast.init = function () { };
15233
+ KTToast.containerMap = new Map();
15234
+ KTToast.toasts = new Map();
15235
+ KTToast.globalConfig = __assign({}, DEFAULT_CONFIG);
15236
+ return KTToast;
15237
+ }(component_1.default));
15238
+ exports.KTToast = KTToast;
14871
15239
 
14872
15240
 
14873
15241
  /***/ }),
@@ -15181,7 +15549,7 @@ exports["default"] = KTDom;
15181
15549
  /***/ }),
15182
15550
 
15183
15551
  /***/ 9011:
15184
- /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
15552
+ /***/ (function(__unused_webpack_module, exports) {
15185
15553
 
15186
15554
 
15187
15555
  /**
@@ -15189,13 +15557,12 @@ exports["default"] = KTDom;
15189
15557
  * Copyright 2025 by Keenthemes Inc
15190
15558
  */
15191
15559
  Object.defineProperty(exports, "__esModule", ({ value: true }));
15192
- exports.EventManager = exports.FocusManager = void 0;
15560
+ exports.TypeToSearchBuffer = exports.EventManager = exports.FocusManager = void 0;
15193
15561
  exports.formatCurrency = formatCurrency;
15194
15562
  exports.filterOptions = filterOptions;
15195
- exports.highlightTextInElement = highlightTextInElement;
15196
- exports.handleDropdownKeyNavigation = handleDropdownKeyNavigation;
15197
15563
  exports.debounce = debounce;
15198
- var templates_1 = __webpack_require__(9069);
15564
+ exports.renderTemplateString = renderTemplateString;
15565
+ exports.stringToElement = stringToElement;
15199
15566
  /**
15200
15567
  * Format a number as a currency string
15201
15568
  */
@@ -15209,144 +15576,50 @@ function formatCurrency(value) {
15209
15576
  * Filter options based on a search query
15210
15577
  */
15211
15578
  function filterOptions(options, query, config, dropdownElement, onVisibleCount) {
15212
- var _a;
15213
15579
  var visibleOptionsCount = 0;
15214
- // Clear existing "no results" messages
15215
- var noResultsElement = dropdownElement.querySelector('[data-kt-select-no-results]');
15216
- if (noResultsElement) {
15217
- noResultsElement.remove();
15218
- }
15219
- // For empty query, ensure highlights are cleared from all options
15580
+ // For empty query, make all options visible
15581
+ // The KTSelectSearch class is now responsible for restoring original content before calling this.
15220
15582
  if (!query || query.trim() === '') {
15221
- // Just make all options visible without highlighting
15222
15583
  for (var _i = 0, options_1 = options; _i < options_1.length; _i++) {
15223
15584
  var option = options_1[_i];
15224
- // Make option visible by removing hidden classes and inline styles
15225
15585
  option.classList.remove('hidden');
15226
- // Clean up any inline display styles from legacy code
15227
- if (option.hasAttribute('style') &&
15228
- option.getAttribute('style').includes('display:')) {
15229
- var styleAttr = option.getAttribute('style');
15230
- if (styleAttr.trim() === 'display: none;' ||
15231
- styleAttr.trim() === 'display: block;') {
15232
- option.removeAttribute('style');
15233
- }
15234
- else {
15235
- option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
15236
- }
15586
+ // Remove inline display style if it was used to hide
15587
+ if (option.style.display === 'none') {
15588
+ option.style.display = '';
15237
15589
  }
15590
+ // At this point, option.innerHTML should be its original.
15238
15591
  visibleOptionsCount++;
15239
15592
  }
15240
- // Call the callback with the visible count if provided
15241
15593
  if (onVisibleCount) {
15242
15594
  onVisibleCount(visibleOptionsCount);
15243
15595
  }
15244
15596
  return visibleOptionsCount;
15245
15597
  }
15246
- // Filter options based on query
15247
- for (var _b = 0, options_2 = options; _b < options_2.length; _b++) {
15248
- var option = options_2[_b];
15249
- var optionText = ((_a = option.textContent) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '';
15250
- var isMatch = optionText.includes(query.toLowerCase());
15251
- if (isMatch || query.trim() === '') {
15252
- // Show option by removing the hidden class and any display inline styles
15598
+ var queryLower = query.toLowerCase();
15599
+ for (var _a = 0, options_2 = options; _a < options_2.length; _a++) {
15600
+ var option = options_2[_a];
15601
+ // Use data-text for matching if available, otherwise fall back to textContent
15602
+ var optionText = (option.dataset.text || option.textContent || '').toLowerCase();
15603
+ var isMatch = optionText.includes(queryLower);
15604
+ if (isMatch) {
15253
15605
  option.classList.remove('hidden');
15254
- // Remove any inline display styles that might be present
15255
- if (option.hasAttribute('style') &&
15256
- option.getAttribute('style').includes('display:')) {
15257
- var styleAttr = option.getAttribute('style');
15258
- if (styleAttr.trim() === 'display: none;' ||
15259
- styleAttr.trim() === 'display: block;') {
15260
- option.removeAttribute('style');
15261
- }
15262
- else {
15263
- option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
15264
- }
15265
- }
15606
+ if (option.style.display === 'none')
15607
+ option.style.display = ''; // Ensure visible
15266
15608
  visibleOptionsCount++;
15267
- // Apply highlighting if needed - but preserve the option structure
15268
- if (isMatch && config.searchHighlight && query.trim() !== '') {
15269
- // Clone option elements that contain icons or descriptions
15270
- var hasIcon = option.querySelector('[data-kt-select-option-icon]') !== null;
15271
- var hasDescription = option.querySelector('[data-kt-select-option-description]') !== null;
15272
- if (hasIcon || hasDescription) {
15273
- // Only highlight the text part without changing structure
15274
- var titleElement = option.querySelector('[data-kt-option-title]');
15275
- if (titleElement) {
15276
- highlightTextInElement(titleElement, query, config);
15277
- }
15278
- }
15279
- else {
15280
- // Simple option with just text - standard highlighting
15281
- highlightTextInElement(option, query, config);
15282
- }
15283
- }
15284
15609
  }
15285
15610
  else {
15286
- // Hide option using hidden class
15287
15611
  option.classList.add('hidden');
15288
- // Remove any inline display styles
15289
- if (option.hasAttribute('style') &&
15290
- option.getAttribute('style').includes('display:')) {
15291
- var styleAttr = option.getAttribute('style');
15292
- if (styleAttr.trim() === 'display: none;' ||
15293
- styleAttr.trim() === 'display: block;') {
15294
- option.removeAttribute('style');
15295
- }
15296
- else {
15297
- option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
15298
- }
15299
- }
15300
- }
15301
- // Early exit if maxItems limit is reached
15302
- if (config.searchMaxItems && visibleOptionsCount >= config.searchMaxItems) {
15303
- break;
15304
15612
  }
15613
+ // Early exit if maxItems limit is reached (optional)
15614
+ // if (config.searchMaxItems && visibleOptionsCount >= config.searchMaxItems) {
15615
+ // break;
15616
+ // }
15305
15617
  }
15306
- // Call the callback with the visible count if provided
15307
15618
  if (onVisibleCount) {
15308
15619
  onVisibleCount(visibleOptionsCount);
15309
15620
  }
15310
15621
  return visibleOptionsCount;
15311
15622
  }
15312
- /**
15313
- * Highlight text only within a specific element, preserving other elements
15314
- */
15315
- function highlightTextInElement(element, query, config) {
15316
- if (!element || !query || query.trim() === '')
15317
- return;
15318
- var queryLower = query.toLowerCase();
15319
- function walk(node) {
15320
- var _a;
15321
- if (node.nodeType === Node.TEXT_NODE) {
15322
- var text = node.nodeValue || '';
15323
- var textLower = text.toLowerCase();
15324
- var matchIndex = textLower.indexOf(queryLower);
15325
- if (matchIndex !== -1) {
15326
- var before = text.slice(0, matchIndex);
15327
- var match = text.slice(matchIndex, matchIndex + query.length);
15328
- var after = text.slice(matchIndex + query.length);
15329
- var frag = document.createDocumentFragment();
15330
- if (before)
15331
- frag.appendChild(document.createTextNode(before));
15332
- // Use the highlight template, which returns an HTMLElement
15333
- var highlightSpan = templates_1.defaultTemplates.highlight(config, match);
15334
- frag.appendChild(highlightSpan);
15335
- if (after)
15336
- frag.appendChild(document.createTextNode(after));
15337
- (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(frag, node);
15338
- // Only highlight the first occurrence in this node
15339
- }
15340
- }
15341
- else if (node.nodeType === Node.ELEMENT_NODE) {
15342
- // Don't re-highlight already highlighted nodes
15343
- if (node.classList.contains('highlight'))
15344
- return;
15345
- Array.from(node.childNodes).forEach(walk);
15346
- }
15347
- }
15348
- walk(element);
15349
- }
15350
15623
  /**
15351
15624
  * Focus manager for keyboard navigation
15352
15625
  * Consolidates redundant focus management logic into shared functions
@@ -15355,16 +15628,14 @@ var FocusManager = /** @class */ (function () {
15355
15628
  function FocusManager(element, optionsSelector, config) {
15356
15629
  if (optionsSelector === void 0) { optionsSelector = '[data-kt-select-option]'; }
15357
15630
  this._focusedOptionIndex = null;
15631
+ this._onFocusChange = null;
15358
15632
  this._element = element;
15359
15633
  this._optionsSelector = optionsSelector;
15360
15634
  this._eventManager = new EventManager();
15361
- // Use config values if provided, otherwise fallback to defaults
15362
- this._focusClass = (config === null || config === void 0 ? void 0 : config.focusClass) || 'option-focused';
15363
- this._hoverClass = (config === null || config === void 0 ? void 0 : config.hoverClass) || 'hovered';
15364
- this._bgClass = (config === null || config === void 0 ? void 0 : config.bgClass) || 'bg-blue-50';
15365
- this._fontClass = (config === null || config === void 0 ? void 0 : config.fontClass) || 'font-medium';
15366
15635
  // Add click handler to update focus state when options are clicked
15367
15636
  this._setupOptionClickHandlers();
15637
+ this._focusClass = 'focus'; // or whatever your intended class is
15638
+ this._hoverClass = 'hover'; // or your intended class
15368
15639
  }
15369
15640
  /**
15370
15641
  * Set up click handlers for all options to update focus state
@@ -15376,15 +15647,6 @@ var FocusManager = /** @class */ (function () {
15376
15647
  var target = e.target;
15377
15648
  var optionElement = target.closest(_this._optionsSelector);
15378
15649
  if (optionElement) {
15379
- // First clear all focus
15380
- _this.resetFocus();
15381
- // Then update the focused index based on the clicked option
15382
- var options = _this.getVisibleOptions();
15383
- var clickedIndex = options.indexOf(optionElement);
15384
- if (clickedIndex >= 0) {
15385
- _this._focusedOptionIndex = clickedIndex;
15386
- _this.applyFocus(options[clickedIndex]);
15387
- }
15388
15650
  }
15389
15651
  });
15390
15652
  };
@@ -15406,24 +15668,89 @@ var FocusManager = /** @class */ (function () {
15406
15668
  });
15407
15669
  };
15408
15670
  /**
15409
- * Focus the next visible option
15671
+ * Focus the first visible option
15410
15672
  */
15411
- FocusManager.prototype.focusNext = function () {
15673
+ FocusManager.prototype.focusFirst = function () {
15412
15674
  var options = this.getVisibleOptions();
15413
15675
  if (options.length === 0)
15414
15676
  return null;
15415
- this.resetFocus();
15416
- if (this._focusedOptionIndex === null) {
15417
- this._focusedOptionIndex = 0;
15677
+ for (var i = 0; i < options.length; i++) {
15678
+ var option = options[i];
15679
+ if (!option.classList.contains('disabled') && option.getAttribute('aria-disabled') !== 'true') {
15680
+ this.resetFocus();
15681
+ this._focusedOptionIndex = i;
15682
+ this.applyFocus(option);
15683
+ this.scrollIntoView(option);
15684
+ return option;
15685
+ }
15418
15686
  }
15419
- else {
15420
- this._focusedOptionIndex =
15421
- (this._focusedOptionIndex + 1) % options.length;
15687
+ return null;
15688
+ };
15689
+ /**
15690
+ * Focus the last visible option
15691
+ */
15692
+ FocusManager.prototype.focusLast = function () {
15693
+ var options = this.getVisibleOptions();
15694
+ if (options.length === 0)
15695
+ return null;
15696
+ for (var i = options.length - 1; i >= 0; i--) {
15697
+ var option = options[i];
15698
+ if (!option.classList.contains('disabled') && option.getAttribute('aria-disabled') !== 'true') {
15699
+ this.resetFocus();
15700
+ this._focusedOptionIndex = i;
15701
+ this.applyFocus(option);
15702
+ this.scrollIntoView(option);
15703
+ return option;
15704
+ }
15422
15705
  }
15423
- var option = options[this._focusedOptionIndex];
15424
- this.applyFocus(option);
15425
- this.scrollIntoView(option);
15426
- return option;
15706
+ return null;
15707
+ };
15708
+ /**
15709
+ * Focus the next visible option that matches the search string
15710
+ */
15711
+ FocusManager.prototype.focusByString = function (str) {
15712
+ var _a, _b, _c;
15713
+ var options = this.getVisibleOptions();
15714
+ if (options.length === 0)
15715
+ return null;
15716
+ var lowerStr = str.toLowerCase();
15717
+ var startIdx = ((_a = this._focusedOptionIndex) !== null && _a !== void 0 ? _a : -1) + 1;
15718
+ for (var i = 0; i < options.length; i++) {
15719
+ var idx = (startIdx + i) % options.length;
15720
+ var option = options[idx];
15721
+ if (!option.classList.contains('disabled') &&
15722
+ option.getAttribute('aria-disabled') !== 'true' &&
15723
+ (((_b = option.textContent) === null || _b === void 0 ? void 0 : _b.toLowerCase().startsWith(lowerStr)) || ((_c = option.dataset.value) === null || _c === void 0 ? void 0 : _c.toLowerCase().startsWith(lowerStr)))) {
15724
+ this.resetFocus();
15725
+ this._focusedOptionIndex = idx;
15726
+ this.applyFocus(option);
15727
+ this.scrollIntoView(option);
15728
+ return option;
15729
+ }
15730
+ }
15731
+ return null;
15732
+ };
15733
+ /**
15734
+ * Focus the next visible option
15735
+ */
15736
+ FocusManager.prototype.focusNext = function () {
15737
+ var options = this.getVisibleOptions();
15738
+ if (options.length === 0)
15739
+ return null;
15740
+ var idx = this._focusedOptionIndex === null ? 0 : (this._focusedOptionIndex + 1) % options.length;
15741
+ var startIdx = idx;
15742
+ do {
15743
+ var option = options[idx];
15744
+ if (!option.classList.contains('disabled') && option.getAttribute('aria-disabled') !== 'true') {
15745
+ this.resetFocus();
15746
+ this._focusedOptionIndex = idx;
15747
+ this.applyFocus(option);
15748
+ this.scrollIntoView(option);
15749
+ return option;
15750
+ }
15751
+ idx = (idx + 1) % options.length;
15752
+ } while (idx !== startIdx);
15753
+ return null;
15427
15754
  };
15428
15755
  /**
15429
15756
  * Focus the previous visible option
@@ -15432,18 +15759,20 @@ var FocusManager = /** @class */ (function () {
15432
15759
  var options = this.getVisibleOptions();
15433
15760
  if (options.length === 0)
15434
15761
  return null;
15435
- this.resetFocus();
15436
- if (this._focusedOptionIndex === null) {
15437
- this._focusedOptionIndex = options.length - 1;
15438
- }
15439
- else {
15440
- this._focusedOptionIndex =
15441
- (this._focusedOptionIndex - 1 + options.length) % options.length;
15442
- }
15443
- var option = options[this._focusedOptionIndex];
15444
- this.applyFocus(option);
15445
- this.scrollIntoView(option);
15446
- return option;
15762
+ var idx = this._focusedOptionIndex === null ? options.length - 1 : (this._focusedOptionIndex - 1 + options.length) % options.length;
15763
+ var startIdx = idx;
15764
+ do {
15765
+ var option = options[idx];
15766
+ if (!option.classList.contains('disabled') && option.getAttribute('aria-disabled') !== 'true') {
15767
+ this.resetFocus();
15768
+ this._focusedOptionIndex = idx;
15769
+ this.applyFocus(option);
15770
+ this.scrollIntoView(option);
15771
+ return option;
15772
+ }
15773
+ idx = (idx - 1 + options.length) % options.length;
15774
+ } while (idx !== startIdx);
15775
+ return null;
15447
15776
  };
15448
15777
  /**
15449
15778
  * Apply focus to a specific option
@@ -15451,34 +15780,27 @@ var FocusManager = /** @class */ (function () {
15451
15780
  FocusManager.prototype.applyFocus = function (option) {
15452
15781
  if (!option)
15453
15782
  return;
15454
- // Remove focus from all options first
15455
- this.resetFocus();
15456
- // Add focus to this option
15783
+ // Ensure it's not disabled
15784
+ if (option.classList.contains('disabled') || option.getAttribute('aria-disabled') === 'true') {
15785
+ return;
15786
+ }
15787
+ // DO NOT CALL resetFocus() here. Caller's responsibility.
15457
15788
  option.classList.add(this._focusClass);
15458
15789
  option.classList.add(this._hoverClass);
15459
- option.classList.add(this._bgClass);
15460
- option.classList.add(this._fontClass);
15790
+ // _triggerFocusChange needs _focusedOptionIndex to be set by the caller before this.
15791
+ this._triggerFocusChange();
15461
15792
  };
15462
15793
  /**
15463
15794
  * Reset focus on all options
15464
15795
  */
15465
15796
  FocusManager.prototype.resetFocus = function () {
15466
15797
  var _this = this;
15467
- // Find all elements with the focus classes
15468
- var focusedElements = this._element.querySelectorAll(".".concat(this._focusClass, ", .").concat(this._hoverClass, ", .").concat(this._bgClass, ", .").concat(this._fontClass));
15469
- // Remove classes from all elements
15798
+ var focusedElements = this._element.querySelectorAll(".".concat(this._focusClass, ", .").concat(this._hoverClass));
15799
+ // Remove focus and hover classes from all options
15470
15800
  focusedElements.forEach(function (element) {
15471
- element.classList.remove(_this._focusClass);
15472
- element.classList.remove(_this._hoverClass);
15473
- element.classList.remove(_this._bgClass);
15474
- element.classList.remove(_this._fontClass);
15801
+ element.classList.remove(_this._focusClass, _this._hoverClass);
15475
15802
  });
15476
- // Reset index if visible options have changed
15477
- var visibleOptions = this.getVisibleOptions();
15478
- if (this._focusedOptionIndex !== null &&
15479
- this._focusedOptionIndex >= visibleOptions.length) {
15480
- this._focusedOptionIndex = null;
15481
- }
15803
+ this._focusedOptionIndex = null; // Always reset the index
15482
15804
  };
15483
15805
  /**
15484
15806
  * Ensure the focused option is visible in the scrollable container
@@ -15486,7 +15808,7 @@ var FocusManager = /** @class */ (function () {
15486
15808
  FocusManager.prototype.scrollIntoView = function (option) {
15487
15809
  if (!option)
15488
15810
  return;
15489
- var container = this._element.querySelector('[data-kt-select-options-container]');
15811
+ var container = this._element.querySelector('[data-kt-select-options]');
15490
15812
  if (!container)
15491
15813
  return;
15492
15814
  var optionRect = option.getBoundingClientRect();
@@ -15507,10 +15829,14 @@ var FocusManager = /** @class */ (function () {
15507
15829
  var options = this.getVisibleOptions();
15508
15830
  var index = options.findIndex(function (option) { return option.dataset.value === value; });
15509
15831
  if (index >= 0) {
15510
- this._focusedOptionIndex = index;
15511
- this.applyFocus(options[index]);
15512
- this.scrollIntoView(options[index]);
15513
- return true;
15832
+ var optionToFocus = options[index];
15833
+ if (!optionToFocus.classList.contains('disabled') && optionToFocus.getAttribute('aria-disabled') !== 'true') {
15834
+ this.resetFocus();
15835
+ this._focusedOptionIndex = index;
15836
+ this.applyFocus(optionToFocus);
15837
+ this.scrollIntoView(optionToFocus);
15838
+ return true;
15839
+ }
15514
15840
  }
15515
15841
  return false;
15516
15842
  };
@@ -15537,6 +15863,17 @@ var FocusManager = /** @class */ (function () {
15537
15863
  FocusManager.prototype.setFocusedIndex = function (index) {
15538
15864
  this._focusedOptionIndex = index;
15539
15865
  };
15866
+ /**
15867
+ * Set a callback to be called when focus changes
15868
+ */
15869
+ FocusManager.prototype.setOnFocusChange = function (cb) {
15870
+ this._onFocusChange = cb;
15871
+ };
15872
+ FocusManager.prototype._triggerFocusChange = function () {
15873
+ if (this._onFocusChange) {
15874
+ this._onFocusChange(this.getFocusedOption(), this._focusedOptionIndex);
15875
+ }
15876
+ };
15540
15877
  /**
15541
15878
  * Clean up event listeners
15542
15879
  */
@@ -15548,166 +15885,6 @@ var FocusManager = /** @class */ (function () {
15548
15885
  return FocusManager;
15549
15886
  }());
15550
15887
  exports.FocusManager = FocusManager;
15551
- /**
15552
- * Shared keyboard navigation handler for dropdown options
15553
- * Can be used by both combobox and search modules
15554
- */
15555
- function handleDropdownKeyNavigation(event, select, config, callbacks) {
15556
- try {
15557
- // Get the dropdown state
15558
- var isDropdownOpen = select._dropdownIsOpen;
15559
- // Log the event to help debug
15560
- var origin_1 = 'handleDropdownKeyNavigation';
15561
- if (select.getConfig && select.getConfig().debug)
15562
- console.log("[".concat(origin_1, "] Key: ").concat(event.key, ", Dropdown open: ").concat(isDropdownOpen));
15563
- // Handle basic keyboard navigation
15564
- switch (event.key) {
15565
- case 'ArrowDown':
15566
- if (!isDropdownOpen) {
15567
- if (select.getConfig && select.getConfig().debug)
15568
- console.log("[".concat(origin_1, "] Opening dropdown on ArrowDown"));
15569
- select.openDropdown();
15570
- // Focus the first option after opening
15571
- setTimeout(function () {
15572
- select._focusNextOption();
15573
- }, 50);
15574
- }
15575
- else if (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onArrowDown) {
15576
- if (select.getConfig && select.getConfig().debug)
15577
- console.log("[".concat(origin_1, "] Using custom onArrowDown callback"));
15578
- callbacks.onArrowDown();
15579
- }
15580
- else {
15581
- if (select.getConfig && select.getConfig().debug)
15582
- console.log("[".concat(origin_1, "] Using default _focusNextOption"));
15583
- var focusedOption = select._focusNextOption();
15584
- // Ensure we have a focused option
15585
- if (focusedOption) {
15586
- if (select.getConfig && select.getConfig().debug)
15587
- console.log("[".concat(origin_1, "] Focused next option:"), focusedOption);
15588
- }
15589
- }
15590
- event.preventDefault();
15591
- break;
15592
- case 'ArrowUp':
15593
- if (!isDropdownOpen) {
15594
- if (select.getConfig && select.getConfig().debug)
15595
- console.log("[".concat(origin_1, "] Opening dropdown on ArrowUp"));
15596
- select.openDropdown();
15597
- // Focus the last option after opening
15598
- setTimeout(function () {
15599
- select._focusPreviousOption();
15600
- }, 50);
15601
- }
15602
- else if (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onArrowUp) {
15603
- if (select.getConfig && select.getConfig().debug)
15604
- console.log("[".concat(origin_1, "] Using custom onArrowUp callback"));
15605
- callbacks.onArrowUp();
15606
- }
15607
- else {
15608
- if (select.getConfig && select.getConfig().debug)
15609
- console.log("[".concat(origin_1, "] Using default _focusPreviousOption"));
15610
- var focusedOption = select._focusPreviousOption();
15611
- // Ensure we have a focused option
15612
- if (focusedOption) {
15613
- if (select.getConfig && select.getConfig().debug)
15614
- console.log("[".concat(origin_1, "] Focused previous option:"), focusedOption);
15615
- }
15616
- }
15617
- event.preventDefault();
15618
- break;
15619
- case 'Enter':
15620
- // Prevent form submission
15621
- event.preventDefault();
15622
- if (isDropdownOpen) {
15623
- if (select.getConfig && select.getConfig().debug)
15624
- console.log("[".concat(origin_1, "] Enter pressed with dropdown open"));
15625
- // For combobox mode, ensure we update the input value directly
15626
- var isCombobox = select.getConfig().mode === 'combobox';
15627
- var comboboxModule = select._comboboxModule;
15628
- if (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onEnter) {
15629
- if (select.getConfig && select.getConfig().debug)
15630
- console.log("[".concat(origin_1, "] Using custom onEnter callback"));
15631
- callbacks.onEnter();
15632
- }
15633
- else {
15634
- if (select.getConfig && select.getConfig().debug)
15635
- console.log("[".concat(origin_1, "] Using default selectFocusedOption"));
15636
- // Make sure there is a focused option before trying to select it
15637
- if (select._focusManager &&
15638
- select._focusManager.getFocusedOption()) {
15639
- select.selectFocusedOption();
15640
- }
15641
- else {
15642
- // If no option is focused, try to focus the first one
15643
- var focusedOption = select._focusNextOption();
15644
- // Only select if an option was successfully focused
15645
- if (focusedOption) {
15646
- select.selectFocusedOption();
15647
- }
15648
- }
15649
- }
15650
- // Close dropdown after selection if not multiple and closeOnSelect is true
15651
- if (!config.multiple && config.closeOnSelect !== false) {
15652
- if (select.getConfig && select.getConfig().debug)
15653
- console.log("[".concat(origin_1, "] Closing dropdown after selection"));
15654
- select.closeDropdown();
15655
- }
15656
- }
15657
- else {
15658
- // If dropdown is closed, open it on Enter
15659
- if (select.getConfig && select.getConfig().debug)
15660
- console.log("[".concat(origin_1, "] Opening dropdown on Enter"));
15661
- select.openDropdown();
15662
- // Focus the first option after opening
15663
- setTimeout(function () {
15664
- select._focusNextOption();
15665
- }, 50);
15666
- }
15667
- break;
15668
- case 'Tab':
15669
- // Only handle tab if dropdown is open
15670
- if (isDropdownOpen) {
15671
- if (select.getConfig && select.getConfig().debug)
15672
- console.log("[".concat(origin_1, "] Closing dropdown on Tab"));
15673
- select.closeDropdown();
15674
- if (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onClose) {
15675
- callbacks.onClose();
15676
- }
15677
- // Don't prevent default tab behavior - let it move focus naturally
15678
- }
15679
- break;
15680
- case 'Escape':
15681
- // Only handle escape if dropdown is open
15682
- if (isDropdownOpen) {
15683
- if (select.getConfig && select.getConfig().debug)
15684
- console.log("[".concat(origin_1, "] Closing dropdown on Escape"));
15685
- select.closeDropdown();
15686
- if (callbacks === null || callbacks === void 0 ? void 0 : callbacks.onClose) {
15687
- callbacks.onClose();
15688
- }
15689
- event.preventDefault(); // Prevent other escape handlers
15690
- }
15691
- break;
15692
- case ' ': // Space key
15693
- // If dropdown is closed, space should open it (but not if in combobox mode)
15694
- if (!isDropdownOpen && !(select.getConfig().mode === 'combobox')) {
15695
- if (select.getConfig && select.getConfig().debug)
15696
- console.log("[".concat(origin_1, "] Opening dropdown on Space"));
15697
- select.openDropdown();
15698
- // Focus the first option after opening
15699
- setTimeout(function () {
15700
- select._focusNextOption();
15701
- }, 50);
15702
- event.preventDefault();
15703
- }
15704
- break;
15705
- }
15706
- }
15707
- catch (error) {
15708
- console.error('Error in keyboard navigation handler:', error);
15709
- }
15710
- }
15711
15888
  /**
15712
15889
  * Centralized event listener management
15713
15890
  */
@@ -15764,7 +15941,7 @@ var EventManager = /** @class */ (function () {
15764
15941
  // Go through each event type
15765
15942
  this._boundHandlers.forEach(function (eventMap, event) {
15766
15943
  // For each event type, go through each handler
15767
- eventMap.forEach(function (boundHandler, originalHandler) {
15944
+ eventMap.forEach(function (boundHandler) {
15768
15945
  element.removeEventListener(event, boundHandler);
15769
15946
  });
15770
15947
  });
@@ -15788,6 +15965,45 @@ function debounce(func, delay) {
15788
15965
  timeout = setTimeout(function () { return func.apply(void 0, args); }, delay);
15789
15966
  };
15790
15967
  }
15968
+ /**
15969
+ * Replaces all {{key}} in the template with the corresponding value from the data object.
15970
+ * If a key is missing in data, replaces with an empty string.
15971
+ */
15972
+ function renderTemplateString(template, data) {
15973
+ return template.replace(/{{(\w+)}}/g, function (_, key) {
15974
+ return data[key] !== undefined && data[key] !== null ? String(data[key]) : '';
15975
+ });
15976
+ }
15977
+ // Type-to-search buffer utility for keyboard navigation
15978
+ var TypeToSearchBuffer = /** @class */ (function () {
15979
+ function TypeToSearchBuffer(timeout) {
15980
+ if (timeout === void 0) { timeout = 500; }
15981
+ this.buffer = '';
15982
+ this.lastTime = 0;
15983
+ this.timeout = timeout;
15984
+ }
15985
+ TypeToSearchBuffer.prototype.push = function (char) {
15986
+ var now = Date.now();
15987
+ if (now - this.lastTime > this.timeout) {
15988
+ this.buffer = '';
15989
+ }
15990
+ this.buffer += char;
15991
+ this.lastTime = now;
15992
+ };
15993
+ TypeToSearchBuffer.prototype.getBuffer = function () {
15994
+ return this.buffer;
15995
+ };
15996
+ TypeToSearchBuffer.prototype.clear = function () {
15997
+ this.buffer = '';
15998
+ };
15999
+ return TypeToSearchBuffer;
16000
+ }());
16001
+ exports.TypeToSearchBuffer = TypeToSearchBuffer;
16002
+ function stringToElement(html) {
16003
+ var template = document.createElement('template');
16004
+ template.innerHTML = html.trim();
16005
+ return template.content.firstElementChild;
16006
+ }
15791
16007
 
15792
16008
 
15793
16009
  /***/ }),
@@ -15828,34 +16044,29 @@ var __assign = (this && this.__assign) || function () {
15828
16044
  return __assign.apply(this, arguments);
15829
16045
  };
15830
16046
  Object.defineProperty(exports, "__esModule", ({ value: true }));
15831
- exports.defaultTemplates = void 0;
16047
+ exports.defaultTemplates = exports.coreTemplateStrings = void 0;
15832
16048
  exports.setTemplateStrings = setTemplateStrings;
15833
16049
  exports.getTemplateStrings = getTemplateStrings;
15834
- var types_1 = __webpack_require__(8135);
16050
+ var utils_1 = __webpack_require__(9011);
15835
16051
  /**
15836
16052
  * Default HTML string templates for KTSelect. All UI structure is defined here.
15837
16053
  * Users can override any template by providing a matching key in the config.templates object.
15838
16054
  */
15839
- var defaultTemplateStrings = {
15840
- dropdownContent: "<div data-kt-select-dropdown-content class=\"kt-select-dropdown hidden\" style=\"z-index: {{zindex}};\">{{content}}</div>",
15841
- optionsContainer: "<ul role=\"listbox\" aria-label=\"{{label}}\" data-kt-select-options-container style=\"max-height: {{height}}px; overflow-y: auto;\">{{options}}</ul>",
15842
- emptyOption: "<option value=\"\">{{placeholder}}</option>",
15843
- errorOption: "<option value=\"\" disabled selected>{{errorMessage}}</option>", // Template for error <option>
15844
- loadMore: "<li class=\"py-2 px-4 text-center text-gray-600 cursor-pointer hover:bg-gray-100\" data-kt-select-load-more>{{loadMoreText}}</li>",
15845
- dropdown: "<div data-kt-select-dropdown-content class=\"absolute z-10 w-full mt-2 bg-white border border-gray-200 rounded-md shadow-md\">\n\t\t{{search}}\n\t\t<ul role=\"listbox\" aria-label=\"{{label}}\" data-kt-select-options-container style=\"max-height: {{height}}px; overflow-y: auto;\">\n\t\t\t{{options}}\n\t\t</ul>\n\t</div>",
15846
- error: "<li class=\"px-3 py-2 text-red-500\" role=\"alert\">{{errorMessage}}</li>",
15847
- highlight: "<span class=\"highlight\">{{text}}</span>",
15848
- main: "<div data-kt-select-wrapper class=\"relative\" data-kt-select-mode=\"{{mode}}\"></div>",
15849
- displayCombobox: "<div class=\"relative flex items-center w-full\">\n\t\t<input data-kt-select-search data-kt-select-display data-kt-select-value type=\"text\" class=\"flex-1 w-full items-center justify-between px-3 py-2 border border-gray-300 rounded-md cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-400\" placeholder=\"{{placeholder}}\" role=\"searchbox\" aria-label=\"{{label}}\" {{disabled}} />\n\t\t<button type=\"button\" data-kt-select-clear-button class=\"absolute right-3 hidden text-gray-400 hover:text-gray-600\" aria-label=\"Clear selection\">\n\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n\t\t\t<line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n\t\t\t<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n\t\t</svg>\n\t\t</button>\n\t</div>",
15850
- icon: "<span class=\"option-icon mr-2\"><img src=\"{{icon}}\" class=\"rounded-full w-6 h-6\" /></span>",
15851
- description: "<div class=\"option-description text-sm text-gray-500\">{{description}}</div>",
15852
- display: "<div data-kt-select-display class=\"flex items-center justify-between px-3 py-2 border border-gray-300 rounded-md cursor-pointer focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-400\" tabindex=\"{{tabindex}}\" role=\"button\" aria-haspopup=\"listbox\" aria-expanded=\"false\" aria-label=\"{{label}}\" {{disabled}}>\n\t\t<span data-kt-select-value>{{placeholder}}</span>\n\t\t<span data-kt-select-arrow class=\"ml-2\">\n\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n\t\t\t\t<polyline points=\"6 9 12 15 18 9\"></polyline>\n\t\t\t</svg>\n\t\t</span>\n\t</div>",
15853
- option: "<li data-kt-select-option data-value=\"{{value}}\" class=\"px-3 py-2 cursor-pointer hover:bg-gray-100 flex items-center{{selectedClass}}{{disabledClass}}\" role=\"option\" {{selected}} {{disabled}}>{{icon}}<div class=\"option-content\"><div class=\"option-title\" data-kt-option-title>{{text}}</div>{{description}}</div></li>",
15854
- optionGroup: "<li role=\"group\" aria-label=\"{{label}}\" class=\"py-1\"><div class=\"px-3 py-1 text-xs font-semibold text-gray-500 uppercase\">{{label}}</div><ul>{{optionsHtml}}</ul></li>",
15855
- search: "<div class=\"px-3 py-2 border-b border-gray-200\"><input type=\"text\" data-kt-select-search placeholder=\"{{searchPlaceholder}}\" class=\"w-full border-none focus:outline-none text-sm\" role=\"searchbox\" aria-label=\"{{searchPlaceholder}}\"/></div>",
15856
- noResults: "<li class=\"px-3 py-2 text-gray-500\" role=\"status\">{{searchNotFoundText}}</li>",
15857
- loading: "<li class=\"px-3 py-2 text-gray-500 italic\" role=\"status\" aria-live=\"polite\">{{loadingMessage}}</li>",
15858
- tag: "<div data-kt-select-tag class=\"inline-flex items-center bg-blue-50 border border-blue-100 rounded px-2 py-1 text-sm mr-1 mb-1\"><span>{{title}}</span><span data-kt-select-remove-button data-value=\"{{id}}\" class=\"ml-1 text-blue-400 hover:text-blue-600 cursor-pointer\" role=\"button\" aria-label=\"Remove {{safeTitle}}\" tabindex=\"0\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line></svg></span></div>",
16055
+ exports.coreTemplateStrings = {
16056
+ dropdown: "<div data-kt-select-dropdown class=\"kt-select-dropdown hidden {{class}}\" style=\"z-index: {{zindex}};\"></div>",
16057
+ options: "<ul role=\"listbox\" aria-label=\"{{label}}\" class=\"kt-select-options {{class}}\" data-kt-select-options=\"true\"></ul>",
16058
+ error: "<li class=\"kt-select-error\" role=\"alert\"></li>",
16059
+ wrapper: "<div data-kt-select-wrapper class=\"kt-select-wrapper {{class}}\"></div>",
16060
+ combobox: "\n\t\t<div data-kt-select-combobox data-kt-select-display class=\"kt-select-combobox {{class}}\">\n\t\t\t<div data-kt-select-combobox-values=\"true\" class=\"kt-select-combobox-values\"></div>\n\t\t\t<input class=\"kt-input kt-select-combobox-input\" data-kt-select-search=\"true\" type=\"text\" placeholder=\"{{placeholder}}\" role=\"searchbox\" aria-label=\"{{label}}\" {{disabled}} />\n\t\t\t<button type=\"button\" data-kt-select-clear-button=\"true\" class=\"kt-select-combobox-clear-btn\" aria-label=\"Clear selection\">\n\t\t\t\t<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n\t\t\t\t\t<line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n\t\t\t\t\t<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n\t\t\t\t</svg>\n\t\t\t</button>\n\t\t</div>\n\t",
16061
+ placeholder: "<div data-kt-select-placeholder class=\"kt-select-placeholder {{class}}\"></div>",
16062
+ display: "\n\t\t<div data-kt-select-display class=\"kt-select-display {{class}}\" tabindex=\"{{tabindex}}\" role=\"button\" data-selected=\"0\" aria-haspopup=\"listbox\" aria-expanded=\"false\" aria-label=\"{{label}}\" {{disabled}}>\n\t\t\t<div class=\"kt-select-option-text\" data-kt-text-container=\"true\">{{text}}</div>\n\t\t</div>\n\t",
16063
+ option: "\n\t\t<li data-kt-select-option data-value=\"{{value}}\" data-text=\"{{text}}\" class=\"kt-select-option {{class}}\" role=\"option\" {{selected}} {{disabled}}>\n\t\t\t<div class=\"kt-select-option-text\" data-kt-text-container=\"true\">{{text}}</div><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"size-3.5 ms-auto hidden text-primary kt-select-option-selected:block\"><path d=\"M20 6 9 17l-5-5\"/></svg>\n\t\t</li>\n\t",
16064
+ search: "<div data-kt-select-search class=\"kt-select-search {{class}}\"><input type=\"text\" data-kt-select-search=\"true\" placeholder=\"{{searchPlaceholder}}\" class=\"kt-input kt-input-ghost\" role=\"searchbox\" aria-label=\"{{searchPlaceholder}}\"/></div>",
16065
+ empty: "<li data-kt-select-empty class=\"kt-select-no-result {{class}}\" role=\"status\"></li>",
16066
+ loading: "<li class=\"kt-select-loading {{class}}\" role=\"status\" aria-live=\"polite\"></li>",
16067
+ tag: "<div data-kt-select-tag=\"true\" class=\"kt-select-tag {{class}}\"></div>",
16068
+ loadMore: "<li class=\"kt-select-load-more {{class}}\" data-kt-select-load-more=\"true\"></li>",
16069
+ tagRemoveButton: "<button type=\"button\" data-kt-select-remove-button class=\"kt-select-tag-remove\" aria-label=\"Remove tag\" tabindex=\"0\"><svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><line x1=\"3\" y1=\"3\" x2=\"9\" y2=\"9\"/><line x1=\"9\" y1=\"3\" x2=\"3\" y2=\"9\"/></svg></button>",
15859
16070
  };
15860
16071
  /**
15861
16072
  * Default templates for KTSelect component
@@ -15885,265 +16096,238 @@ function getTemplateStrings(config) {
15885
16096
  ? config.templates
15886
16097
  : undefined;
15887
16098
  if (templates) {
15888
- return __assign(__assign(__assign({}, defaultTemplateStrings), userTemplateStrings), templates);
16099
+ return __assign(__assign(__assign({}, exports.coreTemplateStrings), userTemplateStrings), templates);
15889
16100
  }
15890
- return __assign(__assign({}, defaultTemplateStrings), userTemplateStrings);
16101
+ return __assign(__assign({}, exports.coreTemplateStrings), userTemplateStrings);
15891
16102
  }
15892
16103
  /**
15893
16104
  * Default templates for KTSelect component
15894
16105
  */
15895
16106
  exports.defaultTemplates = {
15896
- /**
15897
- * Renders a highlighted text
15898
- */
15899
- highlight: function (config, text) {
15900
- var template = getTemplateStrings(config).highlight;
15901
- var html = template.replace('{{text}}', text);
15902
- return stringToElement(html);
15903
- },
15904
16107
  /**
15905
16108
  * Renders the dropdown content
15906
16109
  */
15907
- dropdownContent: function (config) {
15908
- var template = getTemplateStrings(config).dropdownContent;
16110
+ dropdown: function (config) {
16111
+ var _a;
16112
+ var template = getTemplateStrings(config).dropdown;
16113
+ // If a custom dropdownTemplate is provided, it's responsible for its own content.
16114
+ // Otherwise, the base template is used, and content is appended later.
16115
+ if (config.dropdownTemplate) {
16116
+ var renderedCustomTemplate = (0, utils_1.renderTemplateString)(config.dropdownTemplate, {
16117
+ zindex: config.zindex ? String(config.zindex) : '',
16118
+ // content: config.content || '', // No longer pass content to custom template directly here
16119
+ class: config.dropdownClass || '',
16120
+ });
16121
+ // The custom template IS the dropdown element
16122
+ var customDropdownEl = stringToElement(renderedCustomTemplate);
16123
+ if (config.zindex)
16124
+ customDropdownEl.style.zIndex = String(config.zindex);
16125
+ if (config.dropdownClass)
16126
+ (_a = customDropdownEl.classList).add.apply(_a, config.dropdownClass.split(' '));
16127
+ return customDropdownEl;
16128
+ }
15909
16129
  var html = template
15910
16130
  .replace('{{zindex}}', config.zindex ? String(config.zindex) : '')
15911
- .replace('{{content}}', config.content || '');
16131
+ // .replace('{{content}}', '') // Content is no longer part of the base template string
16132
+ .replace('{{class}}', config.dropdownClass || '');
15912
16133
  return stringToElement(html);
15913
16134
  },
15914
16135
  /**
15915
16136
  * Renders the options container for the dropdown
15916
16137
  */
15917
- optionsContainer: function (config) {
15918
- var template = getTemplateStrings(config).optionsContainer;
16138
+ options: function (config) {
16139
+ var template = getTemplateStrings(config).options;
15919
16140
  var html = template
15920
16141
  .replace('{{label}}', config.label || 'Options')
15921
16142
  .replace('{{height}}', config.height ? String(config.height) : '250')
15922
- .replace('{{options}}', config.options || '');
15923
- return stringToElement(html);
15924
- },
15925
- /**
15926
- * Renders an empty option in the dropdown
15927
- */
15928
- emptyOption: function (config) {
15929
- var template = getTemplateStrings(config).emptyOption;
15930
- var html = template.replace('{{placeholder}}', config.placeholder || 'Select...');
15931
- return stringToElement(html);
15932
- },
15933
- /**
15934
- * Renders an error option in the dropdown
15935
- */
15936
- errorOption: function (config) {
15937
- var template = getTemplateStrings(config).errorOption;
15938
- var html = template.replace('{{errorMessage}}', config.errorMessage || 'An error occurred');
16143
+ // .replace('{{options}}', '') // Options are now appended dynamically
16144
+ .replace('{{class}}', config.optionsClass || '');
15939
16145
  return stringToElement(html);
15940
16146
  },
15941
16147
  /**
15942
16148
  * Renders the load more button for pagination
15943
16149
  */
15944
16150
  loadMore: function (config) {
15945
- var html = getTemplateStrings(config).loadMore.replace('{{loadMoreText}}', config.loadMoreText || 'Load more...');
15946
- return stringToElement(html);
16151
+ var html = getTemplateStrings(config)
16152
+ .loadMore // .replace('{{loadMoreText}}', config.loadMoreText || 'Load more...') // Content is no longer in template string
16153
+ .replace('{{class}}', config.loadMoreClass || '');
16154
+ var element = stringToElement(html);
16155
+ element.textContent = config.loadMoreText || 'Load more...';
16156
+ return element;
15947
16157
  },
15948
16158
  /**
15949
16159
  * Renders an error message in the dropdown
15950
16160
  */
15951
16161
  error: function (config) {
16162
+ // Changed return type to HTMLElement
15952
16163
  var template = getTemplateStrings(config).error;
15953
- return template.replace('{{errorMessage}}', config.errorMessage || 'An error occurred');
16164
+ var html = template
16165
+ // .replace('{{errorMessage}}', config.errorMessage || 'An error occurred') // Content is no longer in template string
16166
+ .replace('{{class}}', config.errorClass || '');
16167
+ var element = stringToElement(html);
16168
+ element.textContent = config.errorMessage || 'An error occurred';
16169
+ return element;
15954
16170
  },
15955
16171
  /**
15956
16172
  * Renders the main container for the select component
15957
16173
  */
15958
- main: function (config) {
15959
- var html = getTemplateStrings(config).main.replace('{{mode}}', config.mode || '');
15960
- return stringToElement(html);
16174
+ wrapper: function (config) {
16175
+ var html = getTemplateStrings(config).wrapper.replace('{{class}}', config.wrapperClass || '');
16176
+ var element = stringToElement(html);
16177
+ element.setAttribute('data-kt-select-combobox', config.combobox ? 'true' : 'false');
16178
+ element.setAttribute('data-kt-select-tags', config.tags ? 'true' : 'false');
16179
+ return element;
15961
16180
  },
15962
16181
  /**
15963
16182
  * Renders the display element (trigger) for the select
15964
16183
  */
15965
16184
  display: function (config) {
15966
- var isCombobox = config.mode === types_1.SelectMode.COMBOBOX;
15967
- if (isCombobox) {
15968
- var html_1 = getTemplateStrings(config)
15969
- .displayCombobox.replace(/{{placeholder}}/g, config.placeholder || 'Select...')
15970
- .replace(/{{label}}/g, config.label || config.placeholder || 'Select...')
15971
- .replace('{{disabled}}', config.disabled ? 'disabled' : '');
15972
- return stringToElement(html_1);
15973
- }
15974
16185
  var html = getTemplateStrings(config)
15975
16186
  .display.replace('{{tabindex}}', config.disabled ? '-1' : '0')
15976
16187
  .replace('{{label}}', config.label || config.placeholder || 'Select...')
15977
16188
  .replace('{{disabled}}', config.disabled ? 'aria-disabled="true"' : '')
15978
- .replace('{{placeholder}}', config.placeholder || 'Select...');
15979
- return stringToElement(html);
15980
- },
15981
- /**
15982
- * Renders the dropdown content container
15983
- */
15984
- dropdown: function (config, optionsHtml) {
15985
- var isCombobox = config.mode === types_1.SelectMode.COMBOBOX;
15986
- var hasSearch = config.enableSearch && !isCombobox;
15987
- var template = getTemplateStrings(config).dropdown;
15988
- var searchHtml = '';
15989
- if (hasSearch) {
15990
- var searchElement = exports.defaultTemplates.search(config);
15991
- searchHtml = searchElement.outerHTML;
16189
+ .replace('{{placeholder}}', config.placeholder || 'Select...')
16190
+ .replace('{{class}}', config.displayClass || '');
16191
+ var element = stringToElement(html);
16192
+ // Add data-multiple attribute if in multiple select mode
16193
+ if (config.multiple) {
16194
+ element.setAttribute('data-multiple', 'true');
15992
16195
  }
15993
- var html = template
15994
- .replace('{{search}}', searchHtml)
15995
- .replace('{{options}}', optionsHtml)
15996
- .replace('{{label}}', config.label || 'Options')
15997
- .replace('{{height}}', config.height ? String(config.height) : '250');
15998
- return stringToElement(html);
16196
+ return element;
15999
16197
  },
16000
16198
  /**
16001
16199
  * Renders a single option
16002
16200
  */
16003
16201
  option: function (option, config) {
16202
+ var _a, _b;
16004
16203
  var isHtmlOption = option instanceof HTMLOptionElement;
16005
- var value = isHtmlOption ? option.value : option.id;
16006
- var text = isHtmlOption ? option.text : option.title;
16007
- var disabled = isHtmlOption
16008
- ? option.disabled
16009
- : option.disabled === true;
16010
- var selected = isHtmlOption
16011
- ? option.selected
16012
- : !!option.selected;
16013
- // Prefer data-kt-select-option (JSON) if present
16014
- var description;
16015
- var icon;
16204
+ var optionData;
16016
16205
  if (isHtmlOption) {
16017
- var json = option.getAttribute('data-kt-select-option');
16018
- if (json) {
16019
- try {
16020
- var optionData = JSON.parse(json);
16021
- description = optionData === null || optionData === void 0 ? void 0 : optionData.description;
16022
- icon = optionData === null || optionData === void 0 ? void 0 : optionData.icon;
16023
- }
16024
- catch (e) {
16025
- // fallback to legacy attributes if JSON is invalid
16026
- description =
16027
- option.getAttribute('data-kt-select-option-description') ||
16028
- undefined;
16029
- icon = option.getAttribute('data-kt-select-option-icon') || undefined;
16030
- }
16031
- }
16032
- else {
16033
- description =
16034
- option.getAttribute('data-kt-select-option-description') || undefined;
16035
- icon = option.getAttribute('data-kt-select-option-icon') || undefined;
16036
- }
16206
+ // If it's a plain HTMLOptionElement, construct data similarly to how KTSelectOption would
16207
+ // This branch might be less common if KTSelectOption instances are always used for rendering.
16208
+ var el = option;
16209
+ var textContent = el.textContent || '';
16210
+ optionData = __assign({ value: el.value, text: textContent, selected: el.selected, disabled: el.disabled, content: textContent }, (((_a = config.optionsConfig) === null || _a === void 0 ? void 0 : _a[el.value]) || {}));
16037
16211
  }
16038
16212
  else {
16039
- description = option.description;
16040
- icon = option.icon;
16213
+ // If it's a KTSelectOption class instance (from './option')
16214
+ // which should have the getOptionDataForTemplate method.
16215
+ optionData = option.getOptionDataForTemplate();
16041
16216
  }
16042
- // Build option element with proper accessibility attributes
16043
- var selectedClass = selected ? ' selected' : '';
16044
- var disabledClass = disabled ? ' disabled' : '';
16045
- var html = getTemplateStrings(config)
16046
- .option.replace('{{value}}', value)
16047
- .replace('{{selectedClass}}', selectedClass)
16048
- .replace('{{disabledClass}}', disabledClass)
16049
- .replace('{{selected}}', selected ? 'aria-selected="true"' : 'aria-selected="false"')
16050
- .replace('{{disabled}}', disabled ? 'aria-disabled="true"' : '')
16051
- .replace(/{{icon}}/g, icon ? exports.defaultTemplates.icon(icon, config).outerHTML : '')
16052
- .replace('{{text}}', text)
16053
- .replace(/{{description}}/g, description
16054
- ? exports.defaultTemplates.description(description, config).outerHTML
16055
- : '');
16056
- return stringToElement(html);
16057
- },
16058
- /**
16059
- * Renders an icon
16060
- */
16061
- icon: function (icon, config) {
16062
- var html = getTemplateStrings(config).icon.replace('{{icon}}', icon);
16063
- return stringToElement(html);
16064
- },
16065
- /**
16066
- * Renders a description
16067
- */
16068
- description: function (description, config) {
16069
- var html = getTemplateStrings(config).description.replace('{{description}}', description);
16070
- return stringToElement(html);
16071
- },
16072
- /**
16073
- * Renders an option group with header
16074
- */
16075
- optionGroup: function (label, optionsHtml, config) {
16076
- var html = getTemplateStrings(config)
16077
- .optionGroup.replace(/{{label}}/g, label)
16078
- .replace('{{optionsHtml}}', optionsHtml);
16079
- return stringToElement(html);
16217
+ var content = optionData.text; // Default content to option's text
16218
+ if (config.optionTemplate) {
16219
+ // Use the user-provided template string, rendering with the full optionData.
16220
+ // renderTemplateString will replace {{key}} with values from optionData.
16221
+ content = (0, utils_1.renderTemplateString)(config.optionTemplate, optionData);
16222
+ }
16223
+ else {
16224
+ content = optionData.text || optionData.content; // Prefer explicit text, fallback to content
16225
+ }
16226
+ // Use the core option template string as the base structure.
16227
+ var baseTemplate = getTemplateStrings(config).option;
16228
+ var optionClasses = [config.optionClass || ''];
16229
+ if (optionData.disabled) {
16230
+ optionClasses.push('disabled');
16231
+ }
16232
+ // Populate the base template for the <li> attributes.
16233
+ // The actual display content (text or custom HTML) will be set on the inner span later.
16234
+ var html = (0, utils_1.renderTemplateString)(baseTemplate, __assign(__assign({}, optionData), { class: optionClasses.join(' ').trim() || '', selected: optionData.selected
16235
+ ? 'aria-selected="true"'
16236
+ : 'aria-selected="false"', disabled: optionData.disabled ? 'aria-disabled="true"' : '', content: content }));
16237
+ var element = stringToElement(html);
16238
+ // If a custom option template is provided, replace the element's innerHTML with the content.
16239
+ if (config.optionTemplate) {
16240
+ element.innerHTML = content;
16241
+ }
16242
+ // Ensure data-text attribute is set to the original, clean text for searching/filtering
16243
+ element.setAttribute('data-text', ((_b = optionData === null || optionData === void 0 ? void 0 : optionData.text) === null || _b === void 0 ? void 0 : _b.trim()) || '');
16244
+ return element;
16080
16245
  },
16081
16246
  /**
16082
16247
  * Renders the search input
16083
16248
  */
16084
16249
  search: function (config) {
16085
- var html = getTemplateStrings(config).search.replace('{{searchPlaceholder}}', config.searchPlaceholder || 'Search...');
16250
+ var html = getTemplateStrings(config)
16251
+ .search.replace('{{searchPlaceholder}}', config.searchPlaceholder || 'Search...')
16252
+ .replace('{{class}}', config.searchClass || '');
16086
16253
  return stringToElement(html);
16087
16254
  },
16088
16255
  /**
16089
16256
  * Renders the no results message
16090
16257
  */
16091
- noResults: function (config) {
16092
- var html = getTemplateStrings(config).noResults.replace('{{searchNotFoundText}}', config.searchNotFoundText || 'No results found');
16093
- return stringToElement(html);
16258
+ empty: function (config) {
16259
+ var html = getTemplateStrings(config).empty.replace('{{class}}', config.emptyClass || '');
16260
+ var element = stringToElement(html);
16261
+ element.textContent = config.searchNotFoundText || 'No results found';
16262
+ return element;
16094
16263
  },
16095
16264
  /**
16096
16265
  * Renders the loading state
16097
16266
  */
16098
16267
  loading: function (config, loadingMessage) {
16099
- var html = getTemplateStrings(config).loading.replace('{{loadingMessage}}', loadingMessage || 'Loading options...');
16100
- return stringToElement(html);
16268
+ var html = getTemplateStrings(config).loading.replace('{{class}}', config.loadingClass || '');
16269
+ var element = stringToElement(html);
16270
+ element.textContent = loadingMessage || 'Loading options...';
16271
+ return element;
16101
16272
  },
16102
16273
  /**
16103
16274
  * Renders a tag for multi-select
16104
16275
  */
16105
16276
  tag: function (option, config) {
16106
- // Escape HTML characters for aria-label to prevent HTML injection
16107
- var escapeHTML = function (str) {
16108
- return str.replace(/[&<>"']/g, function (match) {
16109
- var escapeMap = {
16110
- '&': '&amp;',
16111
- '<': '&lt;',
16112
- '>': '&gt;',
16113
- '"': '&quot;',
16114
- "'": '&#39;',
16115
- };
16116
- return escapeMap[match];
16277
+ var _a;
16278
+ var template = getTemplateStrings(config).tag;
16279
+ var preparedContent = option.title; // Default content is the option's title
16280
+ if (config.tagTemplate) {
16281
+ var tagTemplateString_1 = config.tagTemplate;
16282
+ var optionValue = option.getAttribute('data-value') || option.value;
16283
+ // Replace all {{varname}} in option.innerHTML with values from _config.optionsConfig
16284
+ Object.entries(((_a = config.optionsConfig) === null || _a === void 0 ? void 0 : _a[optionValue]) || {}).forEach(function (_a) {
16285
+ var key = _a[0], val = _a[1];
16286
+ if (typeof val === 'string' ||
16287
+ typeof val === 'number' ||
16288
+ typeof val === 'boolean') {
16289
+ tagTemplateString_1 = tagTemplateString_1.replace(new RegExp("{{".concat(key, "}}"), 'g'), String(val));
16290
+ }
16117
16291
  });
16118
- };
16119
- // Ensure we have plain text for the aria-label
16120
- var safeTitle = escapeHTML(option.title);
16121
- var html = getTemplateStrings(config)
16122
- .tag.replace('{{title}}', option.title)
16123
- .replace('{{id}}', option.id)
16124
- .replace('{{safeTitle}}', safeTitle);
16125
- return stringToElement(html);
16292
+ // Render the custom tag template with option data
16293
+ preparedContent = (0, utils_1.renderTemplateString)(tagTemplateString_1, {
16294
+ title: option.title,
16295
+ id: option.id,
16296
+ class: config.tagClass || '', // This class is for content, not the main tag div
16297
+ // content: option.innerHTML, // Avoid direct innerHTML from option due to potential XSS
16298
+ text: option.innerText || option.textContent || '',
16299
+ value: optionValue,
16300
+ });
16301
+ }
16302
+ // Append the remove button HTML string to the prepared content
16303
+ preparedContent += getTemplateStrings(config).tagRemoveButton;
16304
+ var html = template
16305
+ // .replace('{{title}}', option.title) // Title is part of preparedContent if using custom template
16306
+ // .replace('{{id}}', option.id) // ID is part of preparedContent if using custom template
16307
+ .replace('{{class}}', config.tagClass || ''); // Class for the main tag div
16308
+ var element = stringToElement(html);
16309
+ element.innerHTML = preparedContent; // Set the fully prepared content (text/HTML + remove button)
16310
+ return element;
16126
16311
  },
16127
16312
  /**
16128
- * Formats the display of selected values
16313
+ * Renders the placeholder for the select
16129
16314
  */
16130
- selectedDisplay: function (selectedOptions, config) {
16131
- if (!selectedOptions || selectedOptions.length === 0) {
16132
- return config.placeholder || 'Select...';
16133
- }
16134
- if (config.multiple) {
16135
- if (config.renderSelected &&
16136
- typeof config.renderSelected === 'function') {
16137
- return config.renderSelected(selectedOptions);
16138
- }
16139
- if (config.showSelectedCount) {
16140
- var count = selectedOptions.length;
16141
- return "".concat(count, " ").concat(count === 1 ? 'item' : 'items', " selected");
16142
- }
16143
- return selectedOptions.map(function (option) { return option.title; }).join(', ');
16315
+ placeholder: function (config) {
16316
+ var html = getTemplateStrings(config).placeholder.replace('{{class}}', config.placeholderClass || '');
16317
+ var content = config.placeholder || 'Select...';
16318
+ if (config.placeholderTemplate) {
16319
+ content = (0, utils_1.renderTemplateString)(config.placeholderTemplate, {
16320
+ placeholder: config.placeholder || 'Select...',
16321
+ class: config.placeholderClass || '',
16322
+ });
16323
+ var element = stringToElement(html);
16324
+ element.innerHTML = content; // For templates, content can be HTML
16325
+ return element;
16144
16326
  }
16145
16327
  else {
16146
- return selectedOptions[0].title;
16328
+ var element = stringToElement(html);
16329
+ element.textContent = content; // For simple text, use textContent
16330
+ return element;
16147
16331
  }
16148
16332
  },
16149
16333
  };
@@ -17263,7 +17447,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
17263
17447
  return to.concat(ar || Array.prototype.slice.call(from));
17264
17448
  };
17265
17449
  Object.defineProperty(exports, "__esModule", ({ value: true }));
17266
- exports.SelectOptionDefaultConfig = exports.KTSelectState = exports.DefaultConfig = void 0;
17450
+ exports.KTSelectState = exports.DefaultConfig = void 0;
17267
17451
  exports.DefaultConfig = {
17268
17452
  // ...other config options
17269
17453
  loadMoreText: 'Load more...',
@@ -17283,10 +17467,6 @@ exports.DefaultConfig = {
17283
17467
  // Field Mapping
17284
17468
  dataValueField: null, // Property in the option object that contains the value (default: 'id')
17285
17469
  dataFieldText: null, // Property in the option object that contains the text (default: 'title')
17286
- dataFieldDescription: null, // Property in the option object that contains the description
17287
- dataFieldIcon: null, // Property in the option object that contains the icon
17288
- dataFieldIconWidth: null, // Property in the option object that contains the icon width
17289
- dataFieldIconHeight: null, // Property in the option object that contains the icon height
17290
17470
  // Search Configuration
17291
17471
  searchParam: '', // Query parameter for API search requests
17292
17472
  searchDebounce: 300, // Debounce delay for search (in ms)
@@ -17299,10 +17479,8 @@ exports.DefaultConfig = {
17299
17479
  // Selection Behavior
17300
17480
  multiple: false, // Enable/disable multi-select
17301
17481
  maxSelections: null, // Maximum number of selections allowed in multi-select mode (null for unlimited)
17302
- closeOnSelect: true, // Close the dropdown after selecting an option (single-select only)
17303
17482
  disabled: false, // Disable the select component
17304
17483
  isRequired: false, // Make selection required
17305
- mode: null, // Select mode: tags or combobox
17306
17484
  // Search Functionality
17307
17485
  enableSearch: false, // Enable/disable search functionality within the dropdown
17308
17486
  searchPlaceholder: 'Search...', // Placeholder text for the search input
@@ -17310,7 +17488,6 @@ exports.DefaultConfig = {
17310
17488
  searchMinLength: 0, // Minimum characters required to trigger search
17311
17489
  searchMaxItems: 50, // Maximum number of search results to display
17312
17490
  searchNotFoundText: 'No results found', // Text to display when no search results are found
17313
- searchHighlight: true, // Highlight matching search terms within the options
17314
17491
  clearSearchOnClose: true, // Clear search input when dropdown closes
17315
17492
  // Multi-Select Display
17316
17493
  selectAllText: 'Select all', // Text for the "Select All" option (if implemented)
@@ -17326,11 +17503,8 @@ exports.DefaultConfig = {
17326
17503
  dropdownPreventOverflow: false,
17327
17504
  dropdownStrategy: null,
17328
17505
  dropdownWidth: null, // Custom width for dropdown (e.g., '300px'), null to match toggle element width
17329
- // Styling
17330
- focusClass: 'option-focused',
17331
- hoverClass: 'hovered',
17332
- bgClass: 'bg-blue-50',
17333
- fontClass: 'font-medium',
17506
+ // New Config
17507
+ dropdownTemplate: '',
17334
17508
  };
17335
17509
  var KTSelectState = /** @class */ (function () {
17336
17510
  function KTSelectState(config) {
@@ -17338,7 +17512,7 @@ var KTSelectState = /** @class */ (function () {
17338
17512
  this._config = this._initDefaultConfig(config);
17339
17513
  }
17340
17514
  KTSelectState.prototype._initDefaultConfig = function (config) {
17341
- return __assign(__assign({}, exports.DefaultConfig), config);
17515
+ return __assign(__assign(__assign({}, exports.DefaultConfig), config), config.config);
17342
17516
  };
17343
17517
  KTSelectState.prototype.setItems = function (items, query) {
17344
17518
  var _this = this;
@@ -17458,10 +17632,6 @@ var KTSelectState = /** @class */ (function () {
17458
17632
  return KTSelectState;
17459
17633
  }());
17460
17634
  exports.KTSelectState = KTSelectState;
17461
- exports.SelectOptionDefaultConfig = {
17462
- description: '',
17463
- icon: null,
17464
- };
17465
17635
 
17466
17636
 
17467
17637
  /***/ }),