@keenthemes/ktui 1.1.1 → 1.1.2

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 (42) hide show
  1. package/dist/ktui.js +182 -190
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +1 -1
  5. package/lib/cjs/components/select/combobox.js +0 -2
  6. package/lib/cjs/components/select/combobox.js.map +1 -1
  7. package/lib/cjs/components/select/config.js +4 -1
  8. package/lib/cjs/components/select/config.js.map +1 -1
  9. package/lib/cjs/components/select/dropdown.js +0 -16
  10. package/lib/cjs/components/select/dropdown.js.map +1 -1
  11. package/lib/cjs/components/select/remote.js +0 -40
  12. package/lib/cjs/components/select/remote.js.map +1 -1
  13. package/lib/cjs/components/select/search.js +80 -19
  14. package/lib/cjs/components/select/search.js.map +1 -1
  15. package/lib/cjs/components/select/select.js +98 -110
  16. package/lib/cjs/components/select/select.js.map +1 -1
  17. package/lib/cjs/components/select/tags.js +0 -2
  18. package/lib/cjs/components/select/tags.js.map +1 -1
  19. package/lib/esm/components/select/combobox.js +0 -2
  20. package/lib/esm/components/select/combobox.js.map +1 -1
  21. package/lib/esm/components/select/config.js +4 -1
  22. package/lib/esm/components/select/config.js.map +1 -1
  23. package/lib/esm/components/select/dropdown.js +0 -16
  24. package/lib/esm/components/select/dropdown.js.map +1 -1
  25. package/lib/esm/components/select/remote.js +0 -40
  26. package/lib/esm/components/select/remote.js.map +1 -1
  27. package/lib/esm/components/select/search.js +80 -19
  28. package/lib/esm/components/select/search.js.map +1 -1
  29. package/lib/esm/components/select/select.js +98 -110
  30. package/lib/esm/components/select/select.js.map +1 -1
  31. package/lib/esm/components/select/tags.js +0 -2
  32. package/lib/esm/components/select/tags.js.map +1 -1
  33. package/package.json +3 -3
  34. package/src/components/datatable/__tests__/race-conditions.test.ts +5 -5
  35. package/src/components/select/__tests__/ux-behaviors.test.ts +619 -0
  36. package/src/components/select/combobox.ts +0 -1
  37. package/src/components/select/config.ts +7 -1
  38. package/src/components/select/dropdown.ts +0 -24
  39. package/src/components/select/remote.ts +0 -49
  40. package/src/components/select/search.ts +85 -21
  41. package/src/components/select/select.ts +118 -149
  42. package/src/components/select/tags.ts +0 -1
@@ -35,6 +35,9 @@ export class KTSelect extends KTComponent {
35
35
  // Static global configuration
36
36
  private static globalConfig: Partial<KTSelectConfigInterface> = {};
37
37
 
38
+ // Static registry for tracking open dropdowns (global dropdown management)
39
+ private static openDropdowns: Set<KTSelect> = new Set();
40
+
38
41
  // DOM elements
39
42
  private _wrapperElement: HTMLElement;
40
43
  private _displayElement: HTMLElement;
@@ -91,8 +94,6 @@ export class KTSelect extends KTComponent {
91
94
  this._state
92
95
  .setItems()
93
96
  .then(() => {
94
- if (this._config.debug)
95
- console.log('Setting up component after remote data is loaded');
96
97
  this._setupComponent();
97
98
  })
98
99
  .catch((error) => {
@@ -137,14 +138,43 @@ export class KTSelect extends KTComponent {
137
138
  } as KTSelectConfigInterface;
138
139
  }
139
140
 
141
+ /**
142
+ * Override _dispatchEvent to also dispatch on document for global listeners (jQuery compatibility)
143
+ */
144
+ protected override _dispatchEvent(eventType: string, payload: object = null): void {
145
+ // Call parent method to dispatch on element (existing behavior)
146
+ super._dispatchEvent(eventType, payload);
147
+
148
+ // Also dispatch on document if configured
149
+ const dispatchGlobalEvents =
150
+ this._config.dispatchGlobalEvents !== false; // Default to true
151
+ if (dispatchGlobalEvents) {
152
+ // Create namespaced event name for document dispatch
153
+ const namespacedEventType = `kt-select:${eventType}`;
154
+
155
+ // Create event with same detail structure
156
+ const globalEvent = new CustomEvent(namespacedEventType, {
157
+ detail: {
158
+ payload,
159
+ instance: this, // Include component instance reference
160
+ element: this._element, // Include element reference
161
+ },
162
+ bubbles: true,
163
+ cancelable: true,
164
+ composed: true, // Allow event to cross shadow DOM boundaries
165
+ });
166
+
167
+ // Dispatch on document
168
+ document.dispatchEvent(globalEvent);
169
+ }
170
+ }
171
+
140
172
  /**
141
173
  * Initialize remote data fetching
142
174
  */
143
175
  private _initializeRemoteData() {
144
176
  if (!this._remoteModule || !this._config.remote) return;
145
177
 
146
- if (this._config.debug)
147
- console.log('Initializing remote data with URL:', this._config.dataUrl);
148
178
 
149
179
  // For remote data, we need to create the HTML structure first
150
180
  // so that the component can be properly initialized
@@ -158,7 +188,6 @@ export class KTSelect extends KTComponent {
158
188
  this._remoteModule
159
189
  .fetchData()
160
190
  .then((items) => {
161
- if (this._config.debug) console.log('Remote data fetched:', items);
162
191
 
163
192
  // Remove placeholder/loading options before setting new items
164
193
  this._clearExistingOptions();
@@ -170,8 +199,6 @@ export class KTSelect extends KTComponent {
170
199
  // Generate options from the fetched data
171
200
  this._generateOptionsHtml(this._element);
172
201
 
173
- if (this._config.debug)
174
- console.log('Generating options HTML from remote data');
175
202
 
176
203
  // Update the dropdown to show the new options
177
204
  this._updateDropdownWithNewOptions();
@@ -208,12 +235,6 @@ export class KTSelect extends KTComponent {
208
235
 
209
236
  if (selectedOptions.length > 0) {
210
237
  this._preSelectedValues = selectedOptions.map((opt) => opt.value);
211
- if (this._config.debug) {
212
- console.log(
213
- 'Captured pre-selected values before clearing:',
214
- this._preSelectedValues,
215
- );
216
- }
217
238
  }
218
239
 
219
240
  // Keep only the empty/placeholder option and remove the rest
@@ -288,9 +309,6 @@ export class KTSelect extends KTComponent {
288
309
  '[data-kt-select-option]',
289
310
  ) as NodeListOf<HTMLElement>;
290
311
 
291
- if (this._config.debug) {
292
- console.log(`Rendered ${optionsData.length} options in dropdown`);
293
- }
294
312
  }
295
313
 
296
314
  /**
@@ -322,12 +340,6 @@ export class KTSelect extends KTComponent {
322
340
 
323
341
  // Apply pre-selected values captured before remote data was loaded
324
342
  if (this._preSelectedValues.length > 0) {
325
- if (this._config.debug) {
326
- console.log(
327
- 'Applying pre-selected values after remote data loaded:',
328
- this._preSelectedValues,
329
- );
330
- }
331
343
 
332
344
  // Get all available option values from the loaded remote data
333
345
  const availableValues = Array.from(
@@ -345,9 +357,6 @@ export class KTSelect extends KTComponent {
345
357
  ? validPreSelectedValues
346
358
  : [validPreSelectedValues[0]];
347
359
 
348
- if (this._config.debug) {
349
- console.log('Selecting matched values:', valuesToSelect);
350
- }
351
360
 
352
361
  // Get any existing selections from _preSelectOptions (e.g., data-kt-select-pre-selected)
353
362
  const existingSelections = this._state.getSelectedOptions();
@@ -370,11 +379,6 @@ export class KTSelect extends KTComponent {
370
379
  // Update the visual display
371
380
  this.updateSelectedOptionDisplay();
372
381
  this._updateSelectedOptionClass();
373
- } else if (this._config.debug) {
374
- console.log(
375
- 'None of the pre-selected values matched remote data:',
376
- this._preSelectedValues,
377
- );
378
382
  }
379
383
 
380
384
  // Clear the pre-selected values array after processing
@@ -492,7 +496,6 @@ export class KTSelect extends KTComponent {
492
496
  this._showDropdownMessage('error', message);
493
497
 
494
498
  if (!this._wrapperElement) {
495
- if (this._config.debug) console.log('Setting up component after error');
496
499
  this._setupComponent();
497
500
  }
498
501
  }
@@ -626,8 +629,6 @@ export class KTSelect extends KTComponent {
626
629
  `[data-kt-select-option]`,
627
630
  ) as NodeListOf<HTMLElement>;
628
631
 
629
- if (this._config.debug)
630
- console.log(`Added ${newItems.length} more options to dropdown`);
631
632
  }
632
633
 
633
634
  /**
@@ -831,13 +832,28 @@ export class KTSelect extends KTComponent {
831
832
  }
832
833
 
833
834
  // Get search input element - this is used for the search functionality
835
+ // First try to find the actual input element (not the wrapper div)
834
836
  this._searchInputElement = this._dropdownContentElement.querySelector(
835
- `[data-kt-select-search]`,
837
+ `input[data-kt-select-search]`,
836
838
  ) as HTMLInputElement;
837
839
 
838
- // If not found in dropdown, check if it's the display element itself
840
+ // If not found, try the wrapper selector (for backward compatibility)
839
841
  if (!this._searchInputElement) {
840
- this._searchInputElement = this._displayElement as HTMLInputElement;
842
+ const searchWrapper = this._dropdownContentElement.querySelector(
843
+ `[data-kt-select-search]`,
844
+ ) as HTMLElement;
845
+ if (searchWrapper) {
846
+ this._searchInputElement = searchWrapper.querySelector(
847
+ 'input',
848
+ ) as HTMLInputElement;
849
+ }
850
+ }
851
+
852
+ // If still not found in dropdown, check if it's the display element itself (combobox mode)
853
+ if (!this._searchInputElement) {
854
+ this._searchInputElement = this._displayElement.querySelector(
855
+ 'input[data-kt-select-search]',
856
+ ) as HTMLInputElement;
841
857
  }
842
858
 
843
859
  this._selectAllButton = this._wrapperElement.querySelector(
@@ -937,8 +953,6 @@ export class KTSelect extends KTComponent {
937
953
  private _generateOptionsHtml(element: HTMLElement) {
938
954
  const items = this._state.getItems() || [];
939
955
 
940
- if (this._config.debug)
941
- console.log(`Generating options HTML from ${items.length} items`);
942
956
 
943
957
  // Only modify options if we have items to replace them with
944
958
  if (items && items.length > 0) {
@@ -975,9 +989,6 @@ export class KTSelect extends KTComponent {
975
989
  extractedLabel !== null ? String(extractedLabel) : 'Unnamed option';
976
990
  }
977
991
 
978
- // Log the extracted values for debugging
979
- if (this._config.debug)
980
- console.log(`Option: value=${value}, label=${label}`);
981
992
 
982
993
  // Set option attributes
983
994
  optionElement.value = value;
@@ -990,10 +1001,6 @@ export class KTSelect extends KTComponent {
990
1001
  element.appendChild(optionElement);
991
1002
  });
992
1003
 
993
- if (this._config.debug)
994
- console.log(`Added ${items.length} options to select element`);
995
- } else {
996
- if (this._config.debug) console.log('No items to generate options from');
997
1004
  }
998
1005
  }
999
1006
 
@@ -1008,10 +1015,6 @@ export class KTSelect extends KTComponent {
1008
1015
  .split('.')
1009
1016
  .reduce((o, k) => (o && o[k] !== undefined ? o[k] : null), obj);
1010
1017
 
1011
- if (this._config.debug)
1012
- console.log(
1013
- `Extracting [${key}] from object => ${result !== null ? JSON.stringify(result) : 'null'}`,
1014
- );
1015
1018
  return result;
1016
1019
  }
1017
1020
 
@@ -1052,42 +1055,57 @@ export class KTSelect extends KTComponent {
1052
1055
  */
1053
1056
  public openDropdown() {
1054
1057
  if (this._config.disabled) {
1055
- if (this._config.debug)
1056
- console.log('openDropdown: select is disabled, not opening');
1057
1058
  return;
1058
1059
  }
1059
- if (this._config.debug)
1060
- console.log(
1061
- 'openDropdown called, dropdownModule exists:',
1062
- !!this._dropdownModule,
1063
- );
1064
1060
 
1065
1061
  if (!this._dropdownModule) {
1066
- if (this._config.debug)
1067
- console.log('Early return from openDropdown - module missing');
1068
1062
  return;
1069
1063
  }
1070
1064
 
1071
1065
  // Don't open dropdown if the select is disabled
1072
1066
  if (this._config.disabled) {
1073
- if (this._config.debug)
1074
- console.log('Early return from openDropdown - select is disabled');
1075
1067
  return;
1076
1068
  }
1077
1069
 
1078
- if (this._config.debug)
1079
- console.log('Opening dropdown via dropdownModule...');
1070
+ // Global dropdown management: close other open dropdowns if configured
1071
+ const closeOnOtherOpen =
1072
+ this._config.closeOnOtherOpen !== false; // Default to true
1073
+ if (closeOnOtherOpen) {
1074
+ // Close all other open dropdowns
1075
+ const otherSelectsToClose: KTSelect[] = [];
1076
+ KTSelect.openDropdowns.forEach((otherSelect) => {
1077
+ const isOther = otherSelect !== this;
1078
+ const isOpen = otherSelect._dropdownIsOpen;
1079
+ if (isOther && isOpen) {
1080
+ otherSelectsToClose.push(otherSelect);
1081
+ }
1082
+ });
1083
+ otherSelectsToClose.forEach((otherSelect) => {
1084
+ otherSelect.closeDropdown();
1085
+ });
1086
+ }
1087
+
1080
1088
 
1081
1089
  // Set our internal flag to match what we're doing
1082
1090
  this._dropdownIsOpen = true;
1083
1091
 
1092
+ // Add to registry
1093
+ KTSelect.openDropdowns.add(this);
1094
+
1084
1095
  // Open the dropdown via the module
1085
1096
  this._dropdownModule.open();
1086
1097
 
1087
- // Dispatch custom event
1098
+ // Dispatch custom events
1088
1099
  this._dispatchEvent('show');
1089
1100
  this._fireEvent('show');
1090
1101
 
1102
+ // Dispatch dropdown.show event on wrapper for search module
1103
+ const dropdownShowEvent = new CustomEvent('dropdown.show', {
1104
+ bubbles: true,
1105
+ cancelable: true,
1106
+ });
1107
+ this._wrapperElement.dispatchEvent(dropdownShowEvent);
1108
+
1091
1109
  // Update ARIA states
1092
1110
  this._setAriaAttributes();
1093
1111
 
@@ -1102,23 +1120,11 @@ export class KTSelect extends KTComponent {
1102
1120
  * Close the dropdown
1103
1121
  */
1104
1122
  public closeDropdown() {
1105
- if (this._config.debug)
1106
- console.log(
1107
- 'closeDropdown called, dropdownModule exists:',
1108
- !!this._dropdownModule,
1109
- );
1110
-
1111
1123
  // Only check if dropdown module exists, not dropdownIsOpen flag
1112
1124
  if (!this._dropdownModule) {
1113
- if (this._config.debug)
1114
- console.log('Early return from closeDropdown - module missing');
1115
1125
  return;
1116
1126
  }
1117
1127
 
1118
- // Always close by delegating to the dropdown module, which is the source of truth
1119
- if (this._config.debug)
1120
- console.log('Closing dropdown via dropdownModule...');
1121
-
1122
1128
  // Clear search input if the dropdown is closing
1123
1129
  if (this._searchModule && this._searchInputElement) {
1124
1130
  // Clear search input if configured to do so
@@ -1133,6 +1139,9 @@ export class KTSelect extends KTComponent {
1133
1139
  // Set our internal flag to match what we're doing
1134
1140
  this._dropdownIsOpen = false;
1135
1141
 
1142
+ // Remove from registry
1143
+ KTSelect.openDropdowns.delete(this);
1144
+
1136
1145
  // Call the dropdown module's close method
1137
1146
  this._dropdownModule.close();
1138
1147
 
@@ -1145,9 +1154,15 @@ export class KTSelect extends KTComponent {
1145
1154
  this._dispatchEvent('close');
1146
1155
  this._fireEvent('close');
1147
1156
 
1157
+ // Dispatch dropdown.close event on wrapper for search module
1158
+ const dropdownCloseEvent = new CustomEvent('dropdown.close', {
1159
+ bubbles: true,
1160
+ cancelable: true,
1161
+ });
1162
+ this._wrapperElement.dispatchEvent(dropdownCloseEvent);
1163
+
1148
1164
  // Update ARIA states
1149
1165
  this._setAriaAttributes();
1150
- if (this._config.debug) console.log('closeDropdown complete');
1151
1166
  }
1152
1167
 
1153
1168
  /**
@@ -1187,8 +1202,6 @@ export class KTSelect extends KTComponent {
1187
1202
  private _selectOption(value: string) {
1188
1203
  // Prevent selection if the option is disabled (in dropdown or original select)
1189
1204
  if (this._isOptionDisabled(value)) {
1190
- if (this._config.debug)
1191
- console.log('_selectOption: Option is disabled, ignoring selection');
1192
1205
  return;
1193
1206
  }
1194
1207
 
@@ -1338,11 +1351,6 @@ export class KTSelect extends KTComponent {
1338
1351
  typeof this._config.maxSelections === 'number' &&
1339
1352
  selectedValues.length >= this._config.maxSelections;
1340
1353
 
1341
- if (this._config.debug)
1342
- console.log(
1343
- 'Updating selected classes for options, selected values:',
1344
- selectedValues,
1345
- );
1346
1354
 
1347
1355
  allOptions.forEach((option) => {
1348
1356
  const optionValue = option.getAttribute('data-value');
@@ -1462,8 +1470,6 @@ export class KTSelect extends KTComponent {
1462
1470
  * Handle clicking on an option in the dropdown
1463
1471
  */
1464
1472
  private _handleOptionClick(event: Event) {
1465
- if (this._config.debug)
1466
- console.log('_handleOptionClick called', event.target);
1467
1473
  event.preventDefault();
1468
1474
  event.stopPropagation();
1469
1475
 
@@ -1473,31 +1479,22 @@ export class KTSelect extends KTComponent {
1473
1479
  ) as HTMLElement;
1474
1480
 
1475
1481
  if (!clickedOption) {
1476
- if (this._config.debug) console.log('No clicked option found');
1477
1482
  return;
1478
1483
  }
1479
1484
 
1480
1485
  // Check if the option is disabled
1481
1486
  if (clickedOption.getAttribute('aria-disabled') === 'true') {
1482
- if (this._config.debug) console.log('Option is disabled, ignoring click');
1483
1487
  return;
1484
1488
  }
1485
1489
 
1486
1490
  // Use dataset.value to get the option value
1487
1491
  const optionValue = clickedOption.dataset.value;
1488
1492
  if (optionValue === undefined) {
1489
- if (this._config.debug) console.log('Option value is undefined');
1490
1493
  return;
1491
1494
  }
1492
1495
 
1493
- if (this._config.debug) console.log('Option clicked:', optionValue);
1494
-
1495
1496
  // If in single-select mode and the clicked option is already selected, just close the dropdown.
1496
1497
  if (!this._config.multiple && this._state.isSelected(optionValue)) {
1497
- if (this._config.debug)
1498
- console.log(
1499
- 'Single select mode: clicked already selected option. Closing dropdown.',
1500
- );
1501
1498
  this.closeDropdown();
1502
1499
  return;
1503
1500
  }
@@ -1654,32 +1651,17 @@ export class KTSelect extends KTComponent {
1654
1651
  public toggleSelection(value: string): void {
1655
1652
  // Prevent selection if the option is disabled (in dropdown or original select)
1656
1653
  if (this._isOptionDisabled(value)) {
1657
- if (this._config.debug)
1658
- console.log('toggleSelection: Option is disabled, ignoring selection');
1659
1654
  return;
1660
1655
  }
1661
1656
 
1662
1657
  // Get current selection state
1663
1658
  const isSelected = this._state.isSelected(value);
1664
- if (this._config.debug)
1665
- console.log(
1666
- `toggleSelection called for value: ${value}, isSelected: ${isSelected}, multiple: ${this._config.multiple}`,
1667
- );
1668
1659
 
1669
1660
  // If already selected in single select mode, do nothing (can't deselect in single select)
1670
1661
  if (isSelected && !this._config.multiple) {
1671
- if (this._config.debug)
1672
- console.log(
1673
- 'Early return from toggleSelection - already selected in single select mode',
1674
- );
1675
1662
  return;
1676
1663
  }
1677
1664
 
1678
- if (this._config.debug)
1679
- console.log(
1680
- `Toggling selection for option: ${value}, currently selected: ${isSelected}`,
1681
- );
1682
-
1683
1665
  // Ensure any search input is cleared when selection changes
1684
1666
  if (this._searchModule) {
1685
1667
  this._searchModule.clearSearch();
@@ -1711,19 +1693,20 @@ export class KTSelect extends KTComponent {
1711
1693
  // Update option classes without re-rendering the dropdown content
1712
1694
  this._updateSelectedOptionClass();
1713
1695
 
1714
- // For single select mode, always close the dropdown after selection
1696
+ // For single select mode, close the dropdown after selection unless closeOnEnter is false
1715
1697
  // For multiple select mode, keep the dropdown open to allow multiple selections
1716
1698
  if (!this._config.multiple) {
1717
- if (this._config.debug)
1718
- console.log(
1719
- 'About to call closeDropdown() for single select mode - always close after selection',
1720
- );
1721
- this.closeDropdown();
1699
+ // Check if we should close based on closeOnEnter config
1700
+ // closeOnEnter only applies to Enter key selections, but for backward compatibility,
1701
+ // we'll respect it for all selections when explicitly set to false
1702
+ const shouldClose =
1703
+ this._config.closeOnEnter !== false; // Default to true
1704
+ if (shouldClose) {
1705
+ this.closeDropdown();
1706
+ } else {
1707
+ this.updateSelectAllButtonState();
1708
+ }
1722
1709
  } else {
1723
- if (this._config.debug)
1724
- console.log(
1725
- 'Multiple select mode - keeping dropdown open for additional selections',
1726
- );
1727
1710
  // Don't close dropdown in multiple select mode to allow multiple selections
1728
1711
  this.updateSelectAllButtonState();
1729
1712
  }
@@ -1879,12 +1862,6 @@ export class KTSelect extends KTComponent {
1879
1862
  availableValues.includes(value),
1880
1863
  );
1881
1864
 
1882
- if (this._config.debug && currentlySelected.length > 0) {
1883
- console.log(
1884
- 'update(): Preserving selections that exist in new data:',
1885
- validSelections,
1886
- );
1887
- }
1888
1865
 
1889
1866
  // Add new options from remote data and restore selection state
1890
1867
  items.forEach((item) => {
@@ -1980,12 +1957,6 @@ export class KTSelect extends KTComponent {
1980
1957
  availableValues.includes(value),
1981
1958
  );
1982
1959
 
1983
- if (this._config.debug && currentlySelected.length > 0) {
1984
- console.log(
1985
- 'reload(): Preserving selections that exist in new data:',
1986
- validSelections,
1987
- );
1988
- }
1989
1960
 
1990
1961
  // Mark preserved selections on new options
1991
1962
  validSelections.forEach((value) => {
@@ -2063,12 +2034,6 @@ export class KTSelect extends KTComponent {
2063
2034
  availableValues.includes(value),
2064
2035
  );
2065
2036
 
2066
- if (this._config.debug && currentlySelected.length > 0) {
2067
- console.log(
2068
- 'refresh(): Preserving selections that exist in new data:',
2069
- validSelections,
2070
- );
2071
- }
2072
2037
 
2073
2038
  // Add new options and restore selection state
2074
2039
  items.forEach((item) => {
@@ -2296,9 +2261,6 @@ export class KTSelect extends KTComponent {
2296
2261
  }
2297
2262
  this.updateSelectAllButtonState();
2298
2263
 
2299
- if (this._config.debug) {
2300
- console.log('Restored original options after search clear');
2301
- }
2302
2264
  }
2303
2265
 
2304
2266
  /**
@@ -2358,11 +2320,6 @@ export class KTSelect extends KTComponent {
2358
2320
  this._element.appendChild(optionElement);
2359
2321
  });
2360
2322
 
2361
- if (this._config.debug) {
2362
- console.log(
2363
- `Updated original select with ${items.length} search results`,
2364
- );
2365
- }
2366
2323
  }
2367
2324
 
2368
2325
  /**
@@ -2502,10 +2459,6 @@ export class KTSelect extends KTComponent {
2502
2459
  !this._config.multiple &&
2503
2460
  this._state.isSelected(val)
2504
2461
  ) {
2505
- if (this._config.debug)
2506
- console.log(
2507
- 'Enter on already selected item in single-select mode. Closing.',
2508
- );
2509
2462
  this.closeDropdown();
2510
2463
  event.preventDefault();
2511
2464
  break;
@@ -2728,4 +2681,20 @@ export class KTSelect extends KTComponent {
2728
2681
  ? this._config.clearAllText
2729
2682
  : this._config.selectAllText;
2730
2683
  }
2684
+
2685
+ /**
2686
+ * Destroy the component and clean up resources
2687
+ */
2688
+ public destroy(): void {
2689
+ // Remove from global dropdown registry
2690
+ KTSelect.openDropdowns.delete(this);
2691
+
2692
+ // Close dropdown if open
2693
+ if (this._dropdownIsOpen) {
2694
+ this.closeDropdown();
2695
+ }
2696
+
2697
+ // Call parent dispose method
2698
+ super.dispose();
2699
+ }
2731
2700
  }
@@ -26,7 +26,6 @@ export class KTSelectTags {
26
26
  this._valueDisplayElement = select.getValueDisplayElement();
27
27
  this._eventManager = new EventManager();
28
28
 
29
- if (this._config.debug) console.log('KTSelectTags initialized');
30
29
  }
31
30
 
32
31
  /**