@keenthemes/ktui 1.1.1 → 1.1.3

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 (81) hide show
  1. package/dist/ktui.js +674 -225
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +13 -1
  5. package/lib/cjs/components/component.js +22 -0
  6. package/lib/cjs/components/component.js.map +1 -1
  7. package/lib/cjs/components/datatable/datatable.js +7 -1
  8. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  9. package/lib/cjs/components/drawer/drawer.js +255 -9
  10. package/lib/cjs/components/drawer/drawer.js.map +1 -1
  11. package/lib/cjs/components/dropdown/dropdown.js +55 -8
  12. package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
  13. package/lib/cjs/components/select/combobox.js +0 -2
  14. package/lib/cjs/components/select/combobox.js.map +1 -1
  15. package/lib/cjs/components/select/config.js +4 -1
  16. package/lib/cjs/components/select/config.js.map +1 -1
  17. package/lib/cjs/components/select/dropdown.js +0 -16
  18. package/lib/cjs/components/select/dropdown.js.map +1 -1
  19. package/lib/cjs/components/select/remote.js +0 -40
  20. package/lib/cjs/components/select/remote.js.map +1 -1
  21. package/lib/cjs/components/select/search.js +93 -22
  22. package/lib/cjs/components/select/search.js.map +1 -1
  23. package/lib/cjs/components/select/select.js +180 -114
  24. package/lib/cjs/components/select/select.js.map +1 -1
  25. package/lib/cjs/components/select/tags.js +0 -2
  26. package/lib/cjs/components/select/tags.js.map +1 -1
  27. package/lib/cjs/components/sticky/sticky.js +44 -5
  28. package/lib/cjs/components/sticky/sticky.js.map +1 -1
  29. package/lib/cjs/helpers/data.js +8 -0
  30. package/lib/cjs/helpers/data.js.map +1 -1
  31. package/lib/cjs/helpers/event-handler.js +6 -5
  32. package/lib/cjs/helpers/event-handler.js.map +1 -1
  33. package/lib/cjs/index.js.map +1 -1
  34. package/lib/esm/components/component.js +22 -0
  35. package/lib/esm/components/component.js.map +1 -1
  36. package/lib/esm/components/datatable/datatable.js +7 -1
  37. package/lib/esm/components/datatable/datatable.js.map +1 -1
  38. package/lib/esm/components/drawer/drawer.js +255 -9
  39. package/lib/esm/components/drawer/drawer.js.map +1 -1
  40. package/lib/esm/components/dropdown/dropdown.js +55 -8
  41. package/lib/esm/components/dropdown/dropdown.js.map +1 -1
  42. package/lib/esm/components/select/combobox.js +0 -2
  43. package/lib/esm/components/select/combobox.js.map +1 -1
  44. package/lib/esm/components/select/config.js +4 -1
  45. package/lib/esm/components/select/config.js.map +1 -1
  46. package/lib/esm/components/select/dropdown.js +0 -16
  47. package/lib/esm/components/select/dropdown.js.map +1 -1
  48. package/lib/esm/components/select/remote.js +0 -40
  49. package/lib/esm/components/select/remote.js.map +1 -1
  50. package/lib/esm/components/select/search.js +93 -22
  51. package/lib/esm/components/select/search.js.map +1 -1
  52. package/lib/esm/components/select/select.js +180 -114
  53. package/lib/esm/components/select/select.js.map +1 -1
  54. package/lib/esm/components/select/tags.js +0 -2
  55. package/lib/esm/components/select/tags.js.map +1 -1
  56. package/lib/esm/components/sticky/sticky.js +44 -5
  57. package/lib/esm/components/sticky/sticky.js.map +1 -1
  58. package/lib/esm/helpers/data.js +8 -0
  59. package/lib/esm/helpers/data.js.map +1 -1
  60. package/lib/esm/helpers/event-handler.js +6 -5
  61. package/lib/esm/helpers/event-handler.js.map +1 -1
  62. package/lib/esm/index.js.map +1 -1
  63. package/package.json +6 -4
  64. package/src/components/component.ts +26 -0
  65. package/src/components/datatable/__tests__/race-conditions.test.ts +7 -7
  66. package/src/components/datatable/datatable.ts +8 -1
  67. package/src/components/drawer/drawer.ts +266 -10
  68. package/src/components/dropdown/dropdown.ts +63 -8
  69. package/src/components/select/__tests__/ux-behaviors.test.ts +997 -0
  70. package/src/components/select/combobox.ts +0 -1
  71. package/src/components/select/config.ts +7 -1
  72. package/src/components/select/dropdown.ts +0 -24
  73. package/src/components/select/remote.ts +0 -49
  74. package/src/components/select/search.ts +97 -24
  75. package/src/components/select/select.css +5 -1
  76. package/src/components/select/select.ts +211 -153
  77. package/src/components/select/tags.ts +0 -1
  78. package/src/components/sticky/sticky.ts +55 -5
  79. package/src/helpers/data.ts +10 -0
  80. package/src/helpers/event-handler.ts +7 -6
  81. package/src/index.ts +2 -0
@@ -95,8 +95,6 @@ var KTSelect = /** @class */ (function (_super) {
95
95
  _this._state
96
96
  .setItems()
97
97
  .then(function () {
98
- if (_this._config.debug)
99
- console.log('Setting up component after remote data is loaded');
100
98
  _this._setupComponent();
101
99
  })
102
100
  .catch(function (error) {
@@ -131,6 +129,41 @@ var KTSelect = /** @class */ (function (_super) {
131
129
  // Cast to writable to allow assignment (config is readonly but needs initialization)
132
130
  this._config = __assign(__assign(__assign(__assign(__assign({}, this._defaultConfig), KTSelect.globalConfig), this._getGlobalConfig()), KTDom.getDataAttributes(this._element, this._dataOptionPrefix + this._name)), config);
133
131
  };
132
+ /**
133
+ * Override _dispatchEvent to also dispatch on document for global listeners (jQuery compatibility)
134
+ */
135
+ KTSelect.prototype._dispatchEvent = function (eventType, payload) {
136
+ if (payload === void 0) { payload = null; }
137
+ // Call parent method to dispatch on element (existing behavior)
138
+ _super.prototype._dispatchEvent.call(this, eventType, payload);
139
+ // Also dispatch on document if configured
140
+ var dispatchGlobalEvents = this._config.dispatchGlobalEvents !== false; // Default to true
141
+ if (dispatchGlobalEvents) {
142
+ // Create event detail structure
143
+ var eventDetail = {
144
+ payload: payload,
145
+ instance: this, // Include component instance reference
146
+ element: this._element, // Include element reference
147
+ };
148
+ // Dispatch non-namespaced event on document (for jQuery compatibility: $(document).on('show', ...))
149
+ var nonNamespacedEvent = new CustomEvent(eventType, {
150
+ detail: eventDetail,
151
+ bubbles: true,
152
+ cancelable: true,
153
+ composed: true, // Allow event to cross shadow DOM boundaries
154
+ });
155
+ document.dispatchEvent(nonNamespacedEvent);
156
+ // Also dispatch namespaced event on document (for namespaced listeners: $(document).on('kt-select:show', ...))
157
+ var namespacedEventType = "kt-select:".concat(eventType);
158
+ var namespacedEvent = new CustomEvent(namespacedEventType, {
159
+ detail: eventDetail,
160
+ bubbles: true,
161
+ cancelable: true,
162
+ composed: true, // Allow event to cross shadow DOM boundaries
163
+ });
164
+ document.dispatchEvent(namespacedEvent);
165
+ }
166
+ };
134
167
  /**
135
168
  * Initialize remote data fetching
136
169
  */
@@ -138,8 +171,6 @@ var KTSelect = /** @class */ (function (_super) {
138
171
  var _this = this;
139
172
  if (!this._remoteModule || !this._config.remote)
140
173
  return;
141
- if (this._config.debug)
142
- console.log('Initializing remote data with URL:', this._config.dataUrl);
143
174
  // For remote data, we need to create the HTML structure first
144
175
  // so that the component can be properly initialized
145
176
  this._createHtmlStructure();
@@ -150,8 +181,6 @@ var KTSelect = /** @class */ (function (_super) {
150
181
  this._remoteModule
151
182
  .fetchData()
152
183
  .then(function (items) {
153
- if (_this._config.debug)
154
- console.log('Remote data fetched:', items);
155
184
  // Remove placeholder/loading options before setting new items
156
185
  _this._clearExistingOptions();
157
186
  // Update state with fetched items
@@ -160,8 +189,6 @@ var KTSelect = /** @class */ (function (_super) {
160
189
  .then(function () {
161
190
  // Generate options from the fetched data
162
191
  _this._generateOptionsHtml(_this._element);
163
- if (_this._config.debug)
164
- console.log('Generating options HTML from remote data');
165
192
  // Update the dropdown to show the new options
166
193
  _this._updateDropdownWithNewOptions();
167
194
  // Complete the component setup with the fetched data
@@ -189,9 +216,6 @@ var KTSelect = /** @class */ (function (_super) {
189
216
  var selectedOptions = Array.from(this._element.querySelectorAll('option[selected]:not([value=""])'));
190
217
  if (selectedOptions.length > 0) {
191
218
  this._preSelectedValues = selectedOptions.map(function (opt) { return opt.value; });
192
- if (this._config.debug) {
193
- console.log('Captured pre-selected values before clearing:', this._preSelectedValues);
194
- }
195
219
  }
196
220
  // Keep only the empty/placeholder option and remove the rest
197
221
  var options = Array.from(this._element.querySelectorAll('option:not([value=""])'));
@@ -250,9 +274,6 @@ var KTSelect = /** @class */ (function (_super) {
250
274
  optionsContainer.appendChild(fragment);
251
275
  // Update options NodeList
252
276
  this._options = this._dropdownContentElement.querySelectorAll('[data-kt-select-option]');
253
- if (this._config.debug) {
254
- console.log("Rendered ".concat(optionsData.length, " options in dropdown"));
255
- }
256
277
  };
257
278
  /**
258
279
  * Update dropdown with new options from the original select element
@@ -277,9 +298,6 @@ var KTSelect = /** @class */ (function (_super) {
277
298
  }
278
299
  // Apply pre-selected values captured before remote data was loaded
279
300
  if (this._preSelectedValues.length > 0) {
280
- if (this._config.debug) {
281
- console.log('Applying pre-selected values after remote data loaded:', this._preSelectedValues);
282
- }
283
301
  // Get all available option values from the loaded remote data
284
302
  var availableValues_1 = Array.from(this._element.querySelectorAll('option')).map(function (opt) { return opt.value; });
285
303
  // Filter pre-selected values to only those that exist in remote data
@@ -291,9 +309,6 @@ var KTSelect = /** @class */ (function (_super) {
291
309
  var valuesToSelect = this._config.multiple
292
310
  ? validPreSelectedValues
293
311
  : [validPreSelectedValues[0]];
294
- if (this._config.debug) {
295
- console.log('Selecting matched values:', valuesToSelect);
296
- }
297
312
  // Get any existing selections from _preSelectOptions (e.g., data-kt-select-pre-selected)
298
313
  var existingSelections = this._state.getSelectedOptions();
299
314
  // Merge existing selections with native pre-selected values (no duplicates)
@@ -310,9 +325,6 @@ var KTSelect = /** @class */ (function (_super) {
310
325
  this.updateSelectedOptionDisplay();
311
326
  this._updateSelectedOptionClass();
312
327
  }
313
- else if (this._config.debug) {
314
- console.log('None of the pre-selected values matched remote data:', this._preSelectedValues);
315
- }
316
328
  // Clear the pre-selected values array after processing
317
329
  this._preSelectedValues = [];
318
330
  }
@@ -387,8 +399,6 @@ var KTSelect = /** @class */ (function (_super) {
387
399
  // If dropdown is already created, show error message there
388
400
  this._showDropdownMessage('error', message);
389
401
  if (!this._wrapperElement) {
390
- if (this._config.debug)
391
- console.log('Setting up component after error');
392
402
  this._setupComponent();
393
403
  }
394
404
  };
@@ -500,8 +510,6 @@ var KTSelect = /** @class */ (function (_super) {
500
510
  });
501
511
  // Update options NodeList to include the new options
502
512
  this._options = this._dropdownContentElement.querySelectorAll("[data-kt-select-option]");
503
- if (this._config.debug)
504
- console.log("Added ".concat(newItems.length, " more options to dropdown"));
505
513
  };
506
514
  /**
507
515
  * ========================================================================
@@ -640,10 +648,18 @@ var KTSelect = /** @class */ (function (_super) {
640
648
  return;
641
649
  }
642
650
  // Get search input element - this is used for the search functionality
643
- this._searchInputElement = this._dropdownContentElement.querySelector("[data-kt-select-search]");
644
- // If not found in dropdown, check if it's the display element itself
651
+ // First try to find the actual input element (not the wrapper div)
652
+ this._searchInputElement = this._dropdownContentElement.querySelector("input[data-kt-select-search]");
653
+ // If not found, try the wrapper selector (for backward compatibility)
654
+ if (!this._searchInputElement) {
655
+ var searchWrapper = this._dropdownContentElement.querySelector("[data-kt-select-search]");
656
+ if (searchWrapper) {
657
+ this._searchInputElement = searchWrapper.querySelector('input');
658
+ }
659
+ }
660
+ // If still not found in dropdown, check if it's the display element itself (combobox mode)
645
661
  if (!this._searchInputElement) {
646
- this._searchInputElement = this._displayElement;
662
+ this._searchInputElement = this._displayElement.querySelector('input[data-kt-select-search]');
647
663
  }
648
664
  this._selectAllButton = this._wrapperElement.querySelector('[data-kt-select-select-all]');
649
665
  // Cache the options container for performance
@@ -709,8 +725,6 @@ var KTSelect = /** @class */ (function (_super) {
709
725
  KTSelect.prototype._generateOptionsHtml = function (element) {
710
726
  var _this = this;
711
727
  var items = this._state.getItems() || [];
712
- if (this._config.debug)
713
- console.log("Generating options HTML from ".concat(items.length, " items"));
714
728
  // Only modify options if we have items to replace them with
715
729
  if (items && items.length > 0) {
716
730
  // Clear existing options except the first empty one
@@ -738,9 +752,6 @@ var KTSelect = /** @class */ (function (_super) {
738
752
  label =
739
753
  extractedLabel !== null ? String(extractedLabel) : 'Unnamed option';
740
754
  }
741
- // Log the extracted values for debugging
742
- if (_this._config.debug)
743
- console.log("Option: value=".concat(value, ", label=").concat(label));
744
755
  // Set option attributes
745
756
  optionElement.value = value;
746
757
  optionElement.textContent = label || 'Unnamed option';
@@ -749,12 +760,6 @@ var KTSelect = /** @class */ (function (_super) {
749
760
  }
750
761
  element.appendChild(optionElement);
751
762
  });
752
- if (this._config.debug)
753
- console.log("Added ".concat(items.length, " options to select element"));
754
- }
755
- else {
756
- if (this._config.debug)
757
- console.log('No items to generate options from');
758
763
  }
759
764
  };
760
765
  /**
@@ -767,8 +772,6 @@ var KTSelect = /** @class */ (function (_super) {
767
772
  var result = key
768
773
  .split('.')
769
774
  .reduce(function (o, k) { return (o && o[k] !== undefined ? o[k] : null); }, obj);
770
- if (this._config.debug)
771
- console.log("Extracting [".concat(key, "] from object => ").concat(result !== null ? JSON.stringify(result) : 'null'));
772
775
  return result;
773
776
  };
774
777
  /**
@@ -801,55 +804,79 @@ var KTSelect = /** @class */ (function (_super) {
801
804
  * Open the dropdown
802
805
  */
803
806
  KTSelect.prototype.openDropdown = function () {
807
+ var _this = this;
804
808
  if (this._config.disabled) {
805
- if (this._config.debug)
806
- console.log('openDropdown: select is disabled, not opening');
807
809
  return;
808
810
  }
809
- if (this._config.debug)
810
- console.log('openDropdown called, dropdownModule exists:', !!this._dropdownModule);
811
811
  if (!this._dropdownModule) {
812
- if (this._config.debug)
813
- console.log('Early return from openDropdown - module missing');
814
812
  return;
815
813
  }
816
814
  // Don't open dropdown if the select is disabled
817
815
  if (this._config.disabled) {
818
- if (this._config.debug)
819
- console.log('Early return from openDropdown - select is disabled');
820
816
  return;
821
817
  }
822
- if (this._config.debug)
823
- console.log('Opening dropdown via dropdownModule...');
818
+ // Global dropdown management: close other open dropdowns if configured
819
+ var closeOnOtherOpen = this._config.closeOnOtherOpen !== false; // Default to true
820
+ if (closeOnOtherOpen) {
821
+ // Close all other open dropdowns
822
+ var otherSelectsToClose_1 = [];
823
+ KTSelect.openDropdowns.forEach(function (otherSelect) {
824
+ var isOther = otherSelect !== _this;
825
+ var isOpen = otherSelect._dropdownIsOpen;
826
+ if (isOther && isOpen) {
827
+ otherSelectsToClose_1.push(otherSelect);
828
+ }
829
+ });
830
+ otherSelectsToClose_1.forEach(function (otherSelect) {
831
+ otherSelect.closeDropdown();
832
+ });
833
+ }
824
834
  // Set our internal flag to match what we're doing
825
835
  this._dropdownIsOpen = true;
836
+ // Add to registry
837
+ KTSelect.openDropdowns.add(this);
826
838
  // Open the dropdown via the module
827
839
  this._dropdownModule.open();
828
- // Dispatch custom event
840
+ // Dispatch custom events
829
841
  this._dispatchEvent('show');
830
842
  this._fireEvent('show');
843
+ // Dispatch dropdown.show event on wrapper for search module
844
+ var dropdownShowEvent = new CustomEvent('dropdown.show', {
845
+ bubbles: true,
846
+ cancelable: true,
847
+ });
848
+ this._wrapperElement.dispatchEvent(dropdownShowEvent);
831
849
  // Update ARIA states
832
850
  this._setAriaAttributes();
833
851
  // Update select all button state
834
852
  this.updateSelectAllButtonState();
835
853
  // Focus the first selected option or first option if nothing selected
836
- this._focusSelectedOption();
854
+ // BUT: Skip this if search autofocus is enabled, as we want search input to get focus
855
+ if (!(this._config.enableSearch && this._config.searchAutofocus)) {
856
+ this._focusSelectedOption();
857
+ }
858
+ // Dispatch dropdown.show event on the wrapper element for search module
859
+ // Use requestAnimationFrame to ensure dropdown is visible and transition has started
860
+ requestAnimationFrame(function () {
861
+ requestAnimationFrame(function () {
862
+ if (_this._wrapperElement) {
863
+ var dropdownShowEvent_1 = new CustomEvent('dropdown.show', {
864
+ bubbles: true,
865
+ cancelable: true,
866
+ });
867
+ _this._wrapperElement.dispatchEvent(dropdownShowEvent_1);
868
+ }
869
+ });
870
+ });
837
871
  };
838
872
  /**
839
873
  * Close the dropdown
840
874
  */
841
875
  KTSelect.prototype.closeDropdown = function () {
842
- if (this._config.debug)
843
- console.log('closeDropdown called, dropdownModule exists:', !!this._dropdownModule);
844
876
  // Only check if dropdown module exists, not dropdownIsOpen flag
845
877
  if (!this._dropdownModule) {
846
- if (this._config.debug)
847
- console.log('Early return from closeDropdown - module missing');
848
878
  return;
849
879
  }
850
- // Always close by delegating to the dropdown module, which is the source of truth
851
- if (this._config.debug)
852
- console.log('Closing dropdown via dropdownModule...');
853
880
  // Clear search input if the dropdown is closing
854
881
  if (this._searchModule && this._searchInputElement) {
855
882
  // Clear search input if configured to do so
@@ -861,19 +888,25 @@ var KTSelect = /** @class */ (function (_super) {
861
888
  }
862
889
  // Set our internal flag to match what we're doing
863
890
  this._dropdownIsOpen = false;
891
+ // Remove from registry
892
+ KTSelect.openDropdowns.delete(this);
864
893
  // Call the dropdown module's close method
865
894
  this._dropdownModule.close();
866
895
  // Reset all focus states
867
896
  if (this._focusManager) {
868
897
  this._focusManager.resetFocus();
869
898
  }
870
- // Dispatch custom events
899
+ // Dispatch custom events on the select element
871
900
  this._dispatchEvent('close');
872
901
  this._fireEvent('close');
902
+ // Dispatch dropdown.close event on wrapper for search module
903
+ var dropdownCloseEvent = new CustomEvent('dropdown.close', {
904
+ bubbles: true,
905
+ cancelable: true,
906
+ });
907
+ this._wrapperElement.dispatchEvent(dropdownCloseEvent);
873
908
  // Update ARIA states
874
909
  this._setAriaAttributes();
875
- if (this._config.debug)
876
- console.log('closeDropdown complete');
877
910
  };
878
911
  /**
879
912
  * Update dropdown position
@@ -910,8 +943,6 @@ var KTSelect = /** @class */ (function (_super) {
910
943
  KTSelect.prototype._selectOption = function (value) {
911
944
  // Prevent selection if the option is disabled (in dropdown or original select)
912
945
  if (this._isOptionDisabled(value)) {
913
- if (this._config.debug)
914
- console.log('_selectOption: Option is disabled, ignoring selection');
915
946
  return;
916
947
  }
917
948
  // Get current selection state
@@ -1040,8 +1071,6 @@ var KTSelect = /** @class */ (function (_super) {
1040
1071
  var selectedValues = this._state.getSelectedOptions();
1041
1072
  var maxReached = typeof this._config.maxSelections === 'number' &&
1042
1073
  selectedValues.length >= this._config.maxSelections;
1043
- if (this._config.debug)
1044
- console.log('Updating selected classes for options, selected values:', selectedValues);
1045
1074
  allOptions.forEach(function (option) {
1046
1075
  var optionValue = option.getAttribute('data-value');
1047
1076
  if (!optionValue)
@@ -1091,6 +1120,55 @@ var KTSelect = /** @class */ (function (_super) {
1091
1120
  this._dispatchEvent('change');
1092
1121
  this._fireEvent('change');
1093
1122
  };
1123
+ /**
1124
+ * Deselect a specific option by value
1125
+ * @param value The value of the option to deselect
1126
+ * @public
1127
+ */
1128
+ KTSelect.prototype.deselectOption = function (value) {
1129
+ // Check if the option is currently selected
1130
+ if (!this._state.isSelected(value)) {
1131
+ return; // Already deselected
1132
+ }
1133
+ // For single-select mode, check if clearing is allowed
1134
+ if (!this._config.multiple && !this._config.allowClear) {
1135
+ return; // Cannot deselect in single-select mode unless allowClear is true
1136
+ }
1137
+ // Remove from selected options
1138
+ if (this._config.multiple) {
1139
+ // For multiple select, just toggle it off
1140
+ this._state.toggleSelectedOptions(value);
1141
+ }
1142
+ else {
1143
+ // For single select, clear all selections
1144
+ this._state.setSelectedOptions([]);
1145
+ }
1146
+ // Update the native select element
1147
+ var optionEl = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
1148
+ if (optionEl) {
1149
+ optionEl.selected = false;
1150
+ }
1151
+ // For single select, clear the native select value
1152
+ if (!this._config.multiple) {
1153
+ this._element.value = '';
1154
+ }
1155
+ // Update the display
1156
+ this.updateSelectedOptionDisplay();
1157
+ this._updateSelectedOptionClass();
1158
+ // Update select all button state
1159
+ this.updateSelectAllButtonState();
1160
+ // Dispatch change event
1161
+ this._dispatchEvent('change', {
1162
+ value: value,
1163
+ selected: false,
1164
+ selectedOptions: this.getSelectedOptions(),
1165
+ });
1166
+ this._fireEvent('change', {
1167
+ value: value,
1168
+ selected: false,
1169
+ selectedOptions: this.getSelectedOptions(),
1170
+ });
1171
+ };
1094
1172
  /**
1095
1173
  * Set selected options programmatically
1096
1174
  */
@@ -1142,36 +1220,24 @@ var KTSelect = /** @class */ (function (_super) {
1142
1220
  * Handle clicking on an option in the dropdown
1143
1221
  */
1144
1222
  KTSelect.prototype._handleOptionClick = function (event) {
1145
- if (this._config.debug)
1146
- console.log('_handleOptionClick called', event.target);
1147
1223
  event.preventDefault();
1148
1224
  event.stopPropagation();
1149
1225
  // Find the clicked option element
1150
1226
  var clickedOption = event.target.closest("[data-kt-select-option]");
1151
1227
  if (!clickedOption) {
1152
- if (this._config.debug)
1153
- console.log('No clicked option found');
1154
1228
  return;
1155
1229
  }
1156
1230
  // Check if the option is disabled
1157
1231
  if (clickedOption.getAttribute('aria-disabled') === 'true') {
1158
- if (this._config.debug)
1159
- console.log('Option is disabled, ignoring click');
1160
1232
  return;
1161
1233
  }
1162
1234
  // Use dataset.value to get the option value
1163
1235
  var optionValue = clickedOption.dataset.value;
1164
1236
  if (optionValue === undefined) {
1165
- if (this._config.debug)
1166
- console.log('Option value is undefined');
1167
1237
  return;
1168
1238
  }
1169
- if (this._config.debug)
1170
- console.log('Option clicked:', optionValue);
1171
1239
  // If in single-select mode and the clicked option is already selected, just close the dropdown.
1172
1240
  if (!this._config.multiple && this._state.isSelected(optionValue)) {
1173
- if (this._config.debug)
1174
- console.log('Single select mode: clicked already selected option. Closing dropdown.');
1175
1241
  this.closeDropdown();
1176
1242
  return;
1177
1243
  }
@@ -1300,22 +1366,19 @@ var KTSelect = /** @class */ (function (_super) {
1300
1366
  KTSelect.prototype.toggleSelection = function (value) {
1301
1367
  // Prevent selection if the option is disabled (in dropdown or original select)
1302
1368
  if (this._isOptionDisabled(value)) {
1303
- if (this._config.debug)
1304
- console.log('toggleSelection: Option is disabled, ignoring selection');
1305
1369
  return;
1306
1370
  }
1307
1371
  // Get current selection state
1308
1372
  var isSelected = this._state.isSelected(value);
1309
- if (this._config.debug)
1310
- console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple));
1311
- // If already selected in single select mode, do nothing (can't deselect in single select)
1373
+ // If already selected in single select mode, allow deselecting only if allowClear is true
1312
1374
  if (isSelected && !this._config.multiple) {
1313
- if (this._config.debug)
1314
- console.log('Early return from toggleSelection - already selected in single select mode');
1315
- return;
1375
+ if (this._config.allowClear) {
1376
+ // Use the deselectOption method to handle clearing
1377
+ this.deselectOption(value);
1378
+ return;
1379
+ }
1380
+ return; // Can't deselect in single select mode when allowClear is false
1316
1381
  }
1317
- if (this._config.debug)
1318
- console.log("Toggling selection for option: ".concat(value, ", currently selected: ").concat(isSelected));
1319
1382
  // Ensure any search input is cleared when selection changes
1320
1383
  if (this._searchModule) {
1321
1384
  this._searchModule.clearSearch();
@@ -1340,16 +1403,21 @@ var KTSelect = /** @class */ (function (_super) {
1340
1403
  this.updateSelectedOptionDisplay();
1341
1404
  // Update option classes without re-rendering the dropdown content
1342
1405
  this._updateSelectedOptionClass();
1343
- // For single select mode, always close the dropdown after selection
1406
+ // For single select mode, close the dropdown after selection unless closeOnEnter is false
1344
1407
  // For multiple select mode, keep the dropdown open to allow multiple selections
1345
1408
  if (!this._config.multiple) {
1346
- if (this._config.debug)
1347
- console.log('About to call closeDropdown() for single select mode - always close after selection');
1348
- this.closeDropdown();
1409
+ // Check if we should close based on closeOnEnter config
1410
+ // closeOnEnter only applies to Enter key selections, but for backward compatibility,
1411
+ // we'll respect it for all selections when explicitly set to false
1412
+ var shouldClose = this._config.closeOnEnter !== false; // Default to true
1413
+ if (shouldClose) {
1414
+ this.closeDropdown();
1415
+ }
1416
+ else {
1417
+ this.updateSelectAllButtonState();
1418
+ }
1349
1419
  }
1350
1420
  else {
1351
- if (this._config.debug)
1352
- console.log('Multiple select mode - keeping dropdown open for additional selections');
1353
1421
  // Don't close dropdown in multiple select mode to allow multiple selections
1354
1422
  this.updateSelectAllButtonState();
1355
1423
  }
@@ -1481,9 +1549,6 @@ var KTSelect = /** @class */ (function (_super) {
1481
1549
  var validSelections = currentlySelected.filter(function (value) {
1482
1550
  return availableValues.includes(value);
1483
1551
  });
1484
- if (_this._config.debug && currentlySelected.length > 0) {
1485
- console.log('update(): Preserving selections that exist in new data:', validSelections);
1486
- }
1487
1552
  // Add new options from remote data and restore selection state
1488
1553
  items.forEach(function (item) {
1489
1554
  var option = document.createElement('option');
@@ -1566,9 +1631,6 @@ var KTSelect = /** @class */ (function (_super) {
1566
1631
  var validSelections = currentlySelected.filter(function (value) {
1567
1632
  return availableValues.includes(value);
1568
1633
  });
1569
- if (_this._config.debug && currentlySelected.length > 0) {
1570
- console.log('reload(): Preserving selections that exist in new data:', validSelections);
1571
- }
1572
1634
  // Mark preserved selections on new options
1573
1635
  validSelections.forEach(function (value) {
1574
1636
  var option = Array.from(_this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
@@ -1632,9 +1694,6 @@ var KTSelect = /** @class */ (function (_super) {
1632
1694
  var validSelections = currentlySelected.filter(function (value) {
1633
1695
  return availableValues.includes(value);
1634
1696
  });
1635
- if (_this._config.debug && currentlySelected.length > 0) {
1636
- console.log('refresh(): Preserving selections that exist in new data:', validSelections);
1637
- }
1638
1697
  // Add new options and restore selection state
1639
1698
  items.forEach(function (item) {
1640
1699
  var option = document.createElement('option');
@@ -1813,9 +1872,6 @@ var KTSelect = /** @class */ (function (_super) {
1813
1872
  this._searchModule.refreshAfterSearch();
1814
1873
  }
1815
1874
  this.updateSelectAllButtonState();
1816
- if (this._config.debug) {
1817
- console.log('Restored original options after search clear');
1818
- }
1819
1875
  };
1820
1876
  /**
1821
1877
  * Update search results in the dropdown
@@ -1866,9 +1922,6 @@ var KTSelect = /** @class */ (function (_super) {
1866
1922
  }
1867
1923
  _this._element.appendChild(optionElement);
1868
1924
  });
1869
- if (this._config.debug) {
1870
- console.log("Updated original select with ".concat(items.length, " search results"));
1871
- }
1872
1925
  };
1873
1926
  /**
1874
1927
  * Check if dropdown is open
@@ -1993,8 +2046,6 @@ var KTSelect = /** @class */ (function (_super) {
1993
2046
  if (val !== undefined &&
1994
2047
  !this._config.multiple &&
1995
2048
  this._state.isSelected(val)) {
1996
- if (this._config.debug)
1997
- console.log('Enter on already selected item in single-select mode. Closing.');
1998
2049
  this.closeDropdown();
1999
2050
  event.preventDefault();
2000
2051
  break;
@@ -2178,8 +2229,23 @@ var KTSelect = /** @class */ (function (_super) {
2178
2229
  ? this._config.clearAllText
2179
2230
  : this._config.selectAllText;
2180
2231
  };
2232
+ /**
2233
+ * Destroy the component and clean up resources
2234
+ */
2235
+ KTSelect.prototype.destroy = function () {
2236
+ // Remove from global dropdown registry
2237
+ KTSelect.openDropdowns.delete(this);
2238
+ // Close dropdown if open
2239
+ if (this._dropdownIsOpen) {
2240
+ this.closeDropdown();
2241
+ }
2242
+ // Call parent dispose method
2243
+ _super.prototype.dispose.call(this);
2244
+ };
2181
2245
  // Static global configuration
2182
2246
  KTSelect.globalConfig = {};
2247
+ // Static registry for tracking open dropdowns (global dropdown management)
2248
+ KTSelect.openDropdowns = new Set();
2183
2249
  return KTSelect;
2184
2250
  }(KTComponent));
2185
2251
  export { KTSelect };