@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
package/dist/ktui.js CHANGED
@@ -2678,8 +2678,6 @@ var KTSelectRemote = /** @class */ (function () {
2678
2678
  this._lastQuery = query || '';
2679
2679
  this._currentPage = page;
2680
2680
  var url = this._buildUrl(query, page);
2681
- if (this._config.debug)
2682
- console.log('Fetching remote data from:', url);
2683
2681
  // Dispatch search start event
2684
2682
  this._dispatchEvent('remoteSearchStart');
2685
2683
  return fetch(url)
@@ -2766,24 +2764,16 @@ var KTSelectRemote = /** @class */ (function () {
2766
2764
  KTSelectRemote.prototype._processData = function (data) {
2767
2765
  var _this = this;
2768
2766
  try {
2769
- if (this._config.debug)
2770
- console.log('Processing API response:', data);
2771
2767
  var processedData = data;
2772
2768
  // Extract data from the API property if specified
2773
2769
  if (this._config.apiDataProperty && data[this._config.apiDataProperty]) {
2774
- if (this._config.debug)
2775
- console.log("Extracting data from property: ".concat(this._config.apiDataProperty));
2776
2770
  // If pagination metadata is available, extract it
2777
2771
  if (this._config.pagination) {
2778
2772
  if (data.total_pages) {
2779
2773
  this._totalPages = data.total_pages;
2780
- if (this._config.debug)
2781
- console.log("Total pages found: ".concat(this._totalPages));
2782
2774
  }
2783
2775
  if (data.total) {
2784
2776
  this._totalPages = Math.ceil(data.total / (this._config.paginationLimit || 10));
2785
- if (this._config.debug)
2786
- console.log("Calculated total pages: ".concat(this._totalPages, " from total: ").concat(data.total));
2787
2777
  }
2788
2778
  }
2789
2779
  processedData = data[this._config.apiDataProperty];
@@ -2793,8 +2783,6 @@ var KTSelectRemote = /** @class */ (function () {
2793
2783
  console.warn('Remote data is not an array:', processedData);
2794
2784
  return [];
2795
2785
  }
2796
- if (this._config.debug)
2797
- console.log("Mapping ".concat(processedData.length, " items to KTSelectOptionData format"));
2798
2786
  // Map data to KTSelectOptionData format
2799
2787
  var mappedData = processedData.map(function (item) {
2800
2788
  var mappedItem = _this._mapItemToOption(item);
@@ -2820,19 +2808,13 @@ var KTSelectRemote = /** @class */ (function () {
2820
2808
  // If we found a value, verify it matches what was extracted
2821
2809
  if (nestedValue !== null && nestedValue !== undefined) {
2822
2810
  var expectedValue = String(nestedValue);
2823
- if (_this._config.debug)
2824
- console.log("Data path verification for [".concat(_this._config.dataValueField, "]: Expected: ").concat(expectedValue, ", Got: ").concat(mappedItem.id));
2825
2811
  if (mappedItem.id !== expectedValue && expectedValue) {
2826
2812
  console.warn("Value mismatch! Path: ".concat(_this._config.dataValueField, ", Expected: ").concat(expectedValue, ", Got: ").concat(mappedItem.id));
2827
2813
  }
2828
2814
  }
2829
2815
  }
2830
- if (_this._config.debug)
2831
- console.log("Mapped item: ".concat(JSON.stringify(mappedItem)));
2832
2816
  return mappedItem;
2833
2817
  });
2834
- if (this._config.debug)
2835
- console.log("Returned ".concat(mappedData.length, " mapped items"));
2836
2818
  return mappedData;
2837
2819
  }
2838
2820
  catch (error) {
@@ -2848,14 +2830,9 @@ var KTSelectRemote = /** @class */ (function () {
2848
2830
  * @returns KTSelectOptionData object
2849
2831
  */
2850
2832
  KTSelectRemote.prototype._mapItemToOption = function (item) {
2851
- var _this = this;
2852
2833
  // Get the field mapping from config with fallbacks for common field names
2853
2834
  var valueField = this._config.dataValueField || 'id';
2854
2835
  var labelField = this._config.dataFieldText || 'title';
2855
- if (this._config.debug)
2856
- console.log("Mapping fields: value=".concat(valueField, ", label=").concat(labelField));
2857
- if (this._config.debug)
2858
- console.log('Item data:', JSON.stringify(item).substring(0, 200) + '...'); // Trimmed for readability
2859
2836
  // Extract values using improved getValue function
2860
2837
  var getValue = function (obj, path) {
2861
2838
  if (!path || !obj)
@@ -2873,13 +2850,6 @@ var KTSelectRemote = /** @class */ (function () {
2873
2850
  }
2874
2851
  result_1 = result_1[part];
2875
2852
  }
2876
- // Log the extraction result
2877
- if (_this._config.debug)
2878
- console.log("Extracted [".concat(path, "] => ").concat(result_1 !== null && result_1 !== undefined
2879
- ? typeof result_1 === 'object'
2880
- ? JSON.stringify(result_1).substring(0, 50)
2881
- : String(result_1).substring(0, 50)
2882
- : 'null'));
2883
2853
  return result_1;
2884
2854
  }
2885
2855
  catch (error) {
@@ -2896,8 +2866,6 @@ var KTSelectRemote = /** @class */ (function () {
2896
2866
  var field = fallbackFields_1[_i];
2897
2867
  if (item[field] !== null && item[field] !== undefined) {
2898
2868
  id = String(item[field]);
2899
- if (this._config.debug)
2900
- console.log("Using fallback field '".concat(field, "' for ID: ").concat(id));
2901
2869
  break;
2902
2870
  }
2903
2871
  }
@@ -2908,8 +2876,6 @@ var KTSelectRemote = /** @class */ (function () {
2908
2876
  // If still no ID, generate one
2909
2877
  if (!id) {
2910
2878
  id = "option-".concat(Math.random().toString(36).substr(2, 9));
2911
- if (this._config.debug)
2912
- console.log("Generated fallback ID: ".concat(id));
2913
2879
  }
2914
2880
  // Get label with proper fallbacks
2915
2881
  var title = getValue(item, labelField);
@@ -2927,8 +2893,6 @@ var KTSelectRemote = /** @class */ (function () {
2927
2893
  var field = fallbackFields_2[_a];
2928
2894
  if (item[field] !== null && item[field] !== undefined) {
2929
2895
  title = String(item[field]);
2930
- if (this._config.debug)
2931
- console.log("Using fallback field '".concat(field, "' for title: ").concat(title));
2932
2896
  break;
2933
2897
  }
2934
2898
  }
@@ -2939,8 +2903,6 @@ var KTSelectRemote = /** @class */ (function () {
2939
2903
  // If still no title, use ID as fallback
2940
2904
  if (!title) {
2941
2905
  title = "Option ".concat(id);
2942
- if (this._config.debug)
2943
- console.log("Using ID as fallback title: ".concat(title));
2944
2906
  }
2945
2907
  // Create the option object with consistent structure
2946
2908
  var result = {
@@ -2949,8 +2911,6 @@ var KTSelectRemote = /** @class */ (function () {
2949
2911
  selected: Boolean(item.selected),
2950
2912
  disabled: Boolean(item.disabled),
2951
2913
  };
2952
- if (this._config.debug)
2953
- console.log('Final mapped item:', JSON.stringify(result));
2954
2914
  return result;
2955
2915
  };
2956
2916
  /**
@@ -6150,8 +6110,6 @@ var KTSelectCombobox = /** @class */ (function () {
6150
6110
  _this._toggleClearButtonVisibility(_this._searchInputElement.value);
6151
6111
  // this._select.showAllOptions(); // showAllOptions might be too broad, filtering is managed by typing.
6152
6112
  });
6153
- if (this._config.debug)
6154
- console.log('KTSelectCombobox initialized');
6155
6113
  }
6156
6114
  /**
6157
6115
  * Attach event listeners specific to combobox
@@ -8643,8 +8601,6 @@ var KTSelectDropdown = /** @class */ (function (_super) {
8643
8601
  event.preventDefault();
8644
8602
  event.stopPropagation();
8645
8603
  if (this._config.disabled) {
8646
- if (this._config.debug)
8647
- console.log('KTSelectDropdown._handleToggleClick: select is disabled');
8648
8604
  return;
8649
8605
  }
8650
8606
  // Call KTSelect's methods
@@ -8818,8 +8774,6 @@ var KTSelectDropdown = /** @class */ (function (_super) {
8818
8774
  KTSelectDropdown.prototype.open = function () {
8819
8775
  var _this = this;
8820
8776
  if (this._config.disabled) {
8821
- if (this._config.debug)
8822
- console.log('KTSelectDropdown.open: select is disabled, not opening');
8823
8777
  return;
8824
8778
  }
8825
8779
  if (this._isOpen || this._isTransitioning)
@@ -8876,23 +8830,15 @@ var KTSelectDropdown = /** @class */ (function (_super) {
8876
8830
  */
8877
8831
  KTSelectDropdown.prototype.close = function () {
8878
8832
  var _this = this;
8879
- if (this._config.debug)
8880
- console.log('KTSelectDropdown.close called - isOpen:', this._isOpen, 'isTransitioning:', this._isTransitioning);
8881
8833
  if (!this._isOpen || this._isTransitioning) {
8882
- if (this._config.debug)
8883
- console.log('KTSelectDropdown.close - early return: dropdown not open or is transitioning');
8884
8834
  return;
8885
8835
  }
8886
8836
  // Events and ARIA will be handled by KTSelect
8887
- if (this._config.debug)
8888
- console.log('KTSelectDropdown.close - starting transition');
8889
8837
  this._isTransitioning = true;
8890
8838
  this._dropdownElement.style.opacity = '0';
8891
8839
  var transitionComplete = false;
8892
8840
  var fallbackTimer = setTimeout(function () {
8893
8841
  if (!transitionComplete) {
8894
- if (_this._config.debug)
8895
- console.log('KTSelectDropdown.close - fallback timer triggered');
8896
8842
  completeTransition();
8897
8843
  }
8898
8844
  }, 300);
@@ -8901,8 +8847,6 @@ var KTSelectDropdown = /** @class */ (function (_super) {
8901
8847
  return;
8902
8848
  transitionComplete = true;
8903
8849
  clearTimeout(fallbackTimer);
8904
- if (_this._config.debug)
8905
- console.log('KTSelectDropdown.close - transition ended');
8906
8850
  _this._dropdownElement.classList.add('hidden');
8907
8851
  _this._dropdownElement.classList.remove('open');
8908
8852
  _this._toggleElement.classList.remove('active');
@@ -8911,8 +8855,6 @@ var KTSelectDropdown = /** @class */ (function (_super) {
8911
8855
  _this._isTransitioning = false;
8912
8856
  _this._isOpen = false;
8913
8857
  // Events will be handled by KTSelect
8914
- if (_this._config.debug)
8915
- console.log('KTSelectDropdown.close - visual part complete');
8916
8858
  };
8917
8859
  dom_1.default.transitionEnd(this._dropdownElement, completeTransition);
8918
8860
  if (dom_1.default.getCssProp(this._dropdownElement, 'transition-duration') === '0s') {
@@ -9292,8 +9234,6 @@ var KTSelectSearch = /** @class */ (function () {
9292
9234
  if (this._select.getConfig().enableSearch) {
9293
9235
  this._searchInput = this._select.getSearchInput();
9294
9236
  if (this._searchInput) {
9295
- if (this._config.debug)
9296
- console.log('Initializing search module with input:', this._searchInput);
9297
9237
  // First remove any existing listeners to prevent duplicates
9298
9238
  this._removeEventListeners();
9299
9239
  // Add the input event listener for filtering
@@ -9329,22 +9269,37 @@ var KTSelectSearch = /** @class */ (function () {
9329
9269
  .getWrapperElement()
9330
9270
  .addEventListener('dropdown.close', function () {
9331
9271
  _this._focusManager.resetFocus();
9332
- // If clearSearchOnClose is false and there's a value, the search term and filtered state should persist.
9333
- // KTSelect's closeDropdown method already calls this._searchModule.clearSearch() (which clears highlights)
9334
- // and conditionally clears the input value based on KTSelect's config.clearSearchOnClose.
9335
- // This listener in search.ts seems to unconditionally clear everything.
9336
- // For now, keeping its original behavior:
9337
- _this.clearSearch(); // Clears highlights from current options
9338
- _this._searchInput.value = ''; // Clears the search input field
9339
- _this._resetAllOptions(); // Shows all options, restores original text, removes highlights
9340
- _this._clearNoResultsMessage(); // Clears any "no results" message
9272
+ var config = _this._select.getConfig();
9273
+ // Clear highlights from current options (always do this)
9274
+ _this.clearSearch();
9275
+ // Respect clearSearchOnClose config option
9276
+ if (config.clearSearchOnClose) {
9277
+ // Clear the search input field
9278
+ _this._searchInput.value = '';
9279
+ // Reset all options to their original state
9280
+ _this._resetAllOptions();
9281
+ // Clear any "no results" message
9282
+ _this._clearNoResultsMessage();
9283
+ }
9284
+ else {
9285
+ // When clearSearchOnClose is false, preserve search text
9286
+ // The search input value is already preserved by KTSelect's closeDropdown method
9287
+ // Reset options visibility to show all (they will be re-filtered when dropdown reopens)
9288
+ _this._resetAllOptions();
9289
+ // Clear any "no results" message
9290
+ _this._clearNoResultsMessage();
9291
+ // Note: The search input value is preserved, so when dropdown reopens,
9292
+ // the dropdown.show listener will detect it and re-filter options accordingly
9293
+ }
9341
9294
  });
9342
9295
  // Clear highlights when an option is selected - ATTACH TO ORIGINAL SELECT (standard 'change' event)
9343
9296
  this._select.getElement().addEventListener('change', function () {
9344
9297
  _this.clearSearch();
9345
- // Close dropdown only for single select mode
9298
+ // Close dropdown only for single select mode, and only if closeOnEnter is not false
9346
9299
  // Keep dropdown open for multiple select mode to allow additional selections
9347
- if (!_this._select.getConfig().multiple) {
9300
+ // Also respect closeOnEnter config when it's explicitly set to false
9301
+ var config = _this._select.getConfig();
9302
+ if (!config.multiple && config.closeOnEnter !== false) {
9348
9303
  _this._select.closeDropdown();
9349
9304
  }
9350
9305
  });
@@ -9367,12 +9322,9 @@ var KTSelectSearch = /** @class */ (function () {
9367
9322
  // 2. Clear any "no results" message.
9368
9323
  _this._clearNoResultsMessage();
9369
9324
  }
9370
- // Handle autofocus for the search input (this was one of the original separate listeners)
9325
+ // Handle autofocus for the search input with retry mechanism
9371
9326
  if (_this._select.getConfig().searchAutofocus) {
9372
- setTimeout(function () {
9373
- var _a;
9374
- (_a = _this._searchInput) === null || _a === void 0 ? void 0 : _a.focus(); // Focus search input
9375
- }, 50); // Delay to ensure dropdown is visible
9327
+ _this._focusSearchInputWithRetry();
9376
9328
  }
9377
9329
  _this._select.updateSelectAllButtonState();
9378
9330
  });
@@ -9387,6 +9339,54 @@ var KTSelectSearch = /** @class */ (function () {
9387
9339
  this._eventManager.removeAllListeners(this._searchInput);
9388
9340
  }
9389
9341
  };
9342
+ /**
9343
+ * Focus the search input with retry mechanism for reliability
9344
+ * Retries up to 3 times with exponential backoff (50ms, 100ms, 200ms)
9345
+ */
9346
+ KTSelectSearch.prototype._focusSearchInputWithRetry = function (attempt) {
9347
+ var _this = this;
9348
+ if (attempt === void 0) { attempt = 0; }
9349
+ if (!this._searchInput) {
9350
+ return;
9351
+ }
9352
+ var maxAttempts = 3;
9353
+ var delays = [0, 50, 100, 200]; // Initial attempt + 3 retries
9354
+ if (attempt > maxAttempts) {
9355
+ if (this._config.debug) {
9356
+ console.warn('KTSelect: Failed to focus search input after', maxAttempts, 'attempts');
9357
+ }
9358
+ return;
9359
+ }
9360
+ var delay = delays[attempt] || 200;
9361
+ var focusAttempt = function () {
9362
+ var _a;
9363
+ try {
9364
+ (_a = _this._searchInput) === null || _a === void 0 ? void 0 : _a.focus();
9365
+ // Check if focus was successful
9366
+ var isFocused = document.activeElement === _this._searchInput || _this._searchInput === document.activeElement;
9367
+ if (isFocused) {
9368
+ // Focus successful
9369
+ return;
9370
+ }
9371
+ // Focus failed, retry if we haven't exceeded max attempts
9372
+ if (attempt < maxAttempts) {
9373
+ _this._focusSearchInputWithRetry(attempt + 1);
9374
+ }
9375
+ }
9376
+ catch (error) {
9377
+ // Focus failed with error, retry if we haven't exceeded max attempts
9378
+ if (attempt < maxAttempts) {
9379
+ _this._focusSearchInputWithRetry(attempt + 1);
9380
+ }
9381
+ }
9382
+ };
9383
+ if (delay === 0) {
9384
+ focusAttempt();
9385
+ }
9386
+ else {
9387
+ setTimeout(focusAttempt, delay);
9388
+ }
9389
+ };
9390
9390
  /**
9391
9391
  * Handles keydown events on the search input for navigation and actions.
9392
9392
  */
@@ -9414,10 +9414,13 @@ var KTSelectSearch = /** @class */ (function () {
9414
9414
  if (firstAvailableOption) {
9415
9415
  var optionValue = firstAvailableOption.getAttribute('data-value');
9416
9416
  if (optionValue) {
9417
+ // toggleSelection() already handles closing the dropdown based on closeOnEnter config
9418
+ // for single-select mode, so we don't need to call closeDropdown() here
9417
9419
  this._select.toggleSelection(optionValue);
9418
- // KTSelect.toggleSelection handles closing the dropdown based on config.closeOnSelect and config.multiple
9420
+ // If closeOnEnter is false, dropdown remains open for additional selections
9419
9421
  }
9420
9422
  }
9423
+ // If no available option, do nothing (dropdown remains open)
9421
9424
  break;
9422
9425
  case 'Escape':
9423
9426
  event.preventDefault();
@@ -9743,8 +9746,6 @@ var KTSelect = /** @class */ (function (_super) {
9743
9746
  _this._state
9744
9747
  .setItems()
9745
9748
  .then(function () {
9746
- if (_this._config.debug)
9747
- console.log('Setting up component after remote data is loaded');
9748
9749
  _this._setupComponent();
9749
9750
  })
9750
9751
  .catch(function (error) {
@@ -9779,6 +9780,33 @@ var KTSelect = /** @class */ (function (_super) {
9779
9780
  // Cast to writable to allow assignment (config is readonly but needs initialization)
9780
9781
  this._config = __assign(__assign(__assign(__assign(__assign({}, this._defaultConfig), KTSelect.globalConfig), this._getGlobalConfig()), dom_1.default.getDataAttributes(this._element, this._dataOptionPrefix + this._name)), config);
9781
9782
  };
9783
+ /**
9784
+ * Override _dispatchEvent to also dispatch on document for global listeners (jQuery compatibility)
9785
+ */
9786
+ KTSelect.prototype._dispatchEvent = function (eventType, payload) {
9787
+ if (payload === void 0) { payload = null; }
9788
+ // Call parent method to dispatch on element (existing behavior)
9789
+ _super.prototype._dispatchEvent.call(this, eventType, payload);
9790
+ // Also dispatch on document if configured
9791
+ var dispatchGlobalEvents = this._config.dispatchGlobalEvents !== false; // Default to true
9792
+ if (dispatchGlobalEvents) {
9793
+ // Create namespaced event name for document dispatch
9794
+ var namespacedEventType = "kt-select:".concat(eventType);
9795
+ // Create event with same detail structure
9796
+ var globalEvent = new CustomEvent(namespacedEventType, {
9797
+ detail: {
9798
+ payload: payload,
9799
+ instance: this, // Include component instance reference
9800
+ element: this._element, // Include element reference
9801
+ },
9802
+ bubbles: true,
9803
+ cancelable: true,
9804
+ composed: true, // Allow event to cross shadow DOM boundaries
9805
+ });
9806
+ // Dispatch on document
9807
+ document.dispatchEvent(globalEvent);
9808
+ }
9809
+ };
9782
9810
  /**
9783
9811
  * Initialize remote data fetching
9784
9812
  */
@@ -9786,8 +9814,6 @@ var KTSelect = /** @class */ (function (_super) {
9786
9814
  var _this = this;
9787
9815
  if (!this._remoteModule || !this._config.remote)
9788
9816
  return;
9789
- if (this._config.debug)
9790
- console.log('Initializing remote data with URL:', this._config.dataUrl);
9791
9817
  // For remote data, we need to create the HTML structure first
9792
9818
  // so that the component can be properly initialized
9793
9819
  this._createHtmlStructure();
@@ -9798,8 +9824,6 @@ var KTSelect = /** @class */ (function (_super) {
9798
9824
  this._remoteModule
9799
9825
  .fetchData()
9800
9826
  .then(function (items) {
9801
- if (_this._config.debug)
9802
- console.log('Remote data fetched:', items);
9803
9827
  // Remove placeholder/loading options before setting new items
9804
9828
  _this._clearExistingOptions();
9805
9829
  // Update state with fetched items
@@ -9808,8 +9832,6 @@ var KTSelect = /** @class */ (function (_super) {
9808
9832
  .then(function () {
9809
9833
  // Generate options from the fetched data
9810
9834
  _this._generateOptionsHtml(_this._element);
9811
- if (_this._config.debug)
9812
- console.log('Generating options HTML from remote data');
9813
9835
  // Update the dropdown to show the new options
9814
9836
  _this._updateDropdownWithNewOptions();
9815
9837
  // Complete the component setup with the fetched data
@@ -9837,9 +9859,6 @@ var KTSelect = /** @class */ (function (_super) {
9837
9859
  var selectedOptions = Array.from(this._element.querySelectorAll('option[selected]:not([value=""])'));
9838
9860
  if (selectedOptions.length > 0) {
9839
9861
  this._preSelectedValues = selectedOptions.map(function (opt) { return opt.value; });
9840
- if (this._config.debug) {
9841
- console.log('Captured pre-selected values before clearing:', this._preSelectedValues);
9842
- }
9843
9862
  }
9844
9863
  // Keep only the empty/placeholder option and remove the rest
9845
9864
  var options = Array.from(this._element.querySelectorAll('option:not([value=""])'));
@@ -9898,9 +9917,6 @@ var KTSelect = /** @class */ (function (_super) {
9898
9917
  optionsContainer.appendChild(fragment);
9899
9918
  // Update options NodeList
9900
9919
  this._options = this._dropdownContentElement.querySelectorAll('[data-kt-select-option]');
9901
- if (this._config.debug) {
9902
- console.log("Rendered ".concat(optionsData.length, " options in dropdown"));
9903
- }
9904
9920
  };
9905
9921
  /**
9906
9922
  * Update dropdown with new options from the original select element
@@ -9925,9 +9941,6 @@ var KTSelect = /** @class */ (function (_super) {
9925
9941
  }
9926
9942
  // Apply pre-selected values captured before remote data was loaded
9927
9943
  if (this._preSelectedValues.length > 0) {
9928
- if (this._config.debug) {
9929
- console.log('Applying pre-selected values after remote data loaded:', this._preSelectedValues);
9930
- }
9931
9944
  // Get all available option values from the loaded remote data
9932
9945
  var availableValues_1 = Array.from(this._element.querySelectorAll('option')).map(function (opt) { return opt.value; });
9933
9946
  // Filter pre-selected values to only those that exist in remote data
@@ -9939,9 +9952,6 @@ var KTSelect = /** @class */ (function (_super) {
9939
9952
  var valuesToSelect = this._config.multiple
9940
9953
  ? validPreSelectedValues
9941
9954
  : [validPreSelectedValues[0]];
9942
- if (this._config.debug) {
9943
- console.log('Selecting matched values:', valuesToSelect);
9944
- }
9945
9955
  // Get any existing selections from _preSelectOptions (e.g., data-kt-select-pre-selected)
9946
9956
  var existingSelections = this._state.getSelectedOptions();
9947
9957
  // Merge existing selections with native pre-selected values (no duplicates)
@@ -9958,9 +9968,6 @@ var KTSelect = /** @class */ (function (_super) {
9958
9968
  this.updateSelectedOptionDisplay();
9959
9969
  this._updateSelectedOptionClass();
9960
9970
  }
9961
- else if (this._config.debug) {
9962
- console.log('None of the pre-selected values matched remote data:', this._preSelectedValues);
9963
- }
9964
9971
  // Clear the pre-selected values array after processing
9965
9972
  this._preSelectedValues = [];
9966
9973
  }
@@ -10035,8 +10042,6 @@ var KTSelect = /** @class */ (function (_super) {
10035
10042
  // If dropdown is already created, show error message there
10036
10043
  this._showDropdownMessage('error', message);
10037
10044
  if (!this._wrapperElement) {
10038
- if (this._config.debug)
10039
- console.log('Setting up component after error');
10040
10045
  this._setupComponent();
10041
10046
  }
10042
10047
  };
@@ -10148,8 +10153,6 @@ var KTSelect = /** @class */ (function (_super) {
10148
10153
  });
10149
10154
  // Update options NodeList to include the new options
10150
10155
  this._options = this._dropdownContentElement.querySelectorAll("[data-kt-select-option]");
10151
- if (this._config.debug)
10152
- console.log("Added ".concat(newItems.length, " more options to dropdown"));
10153
10156
  };
10154
10157
  /**
10155
10158
  * ========================================================================
@@ -10288,10 +10291,18 @@ var KTSelect = /** @class */ (function (_super) {
10288
10291
  return;
10289
10292
  }
10290
10293
  // Get search input element - this is used for the search functionality
10291
- this._searchInputElement = this._dropdownContentElement.querySelector("[data-kt-select-search]");
10292
- // If not found in dropdown, check if it's the display element itself
10294
+ // First try to find the actual input element (not the wrapper div)
10295
+ this._searchInputElement = this._dropdownContentElement.querySelector("input[data-kt-select-search]");
10296
+ // If not found, try the wrapper selector (for backward compatibility)
10293
10297
  if (!this._searchInputElement) {
10294
- this._searchInputElement = this._displayElement;
10298
+ var searchWrapper = this._dropdownContentElement.querySelector("[data-kt-select-search]");
10299
+ if (searchWrapper) {
10300
+ this._searchInputElement = searchWrapper.querySelector('input');
10301
+ }
10302
+ }
10303
+ // If still not found in dropdown, check if it's the display element itself (combobox mode)
10304
+ if (!this._searchInputElement) {
10305
+ this._searchInputElement = this._displayElement.querySelector('input[data-kt-select-search]');
10295
10306
  }
10296
10307
  this._selectAllButton = this._wrapperElement.querySelector('[data-kt-select-select-all]');
10297
10308
  // Cache the options container for performance
@@ -10357,8 +10368,6 @@ var KTSelect = /** @class */ (function (_super) {
10357
10368
  KTSelect.prototype._generateOptionsHtml = function (element) {
10358
10369
  var _this = this;
10359
10370
  var items = this._state.getItems() || [];
10360
- if (this._config.debug)
10361
- console.log("Generating options HTML from ".concat(items.length, " items"));
10362
10371
  // Only modify options if we have items to replace them with
10363
10372
  if (items && items.length > 0) {
10364
10373
  // Clear existing options except the first empty one
@@ -10386,9 +10395,6 @@ var KTSelect = /** @class */ (function (_super) {
10386
10395
  label =
10387
10396
  extractedLabel !== null ? String(extractedLabel) : 'Unnamed option';
10388
10397
  }
10389
- // Log the extracted values for debugging
10390
- if (_this._config.debug)
10391
- console.log("Option: value=".concat(value, ", label=").concat(label));
10392
10398
  // Set option attributes
10393
10399
  optionElement.value = value;
10394
10400
  optionElement.textContent = label || 'Unnamed option';
@@ -10397,12 +10403,6 @@ var KTSelect = /** @class */ (function (_super) {
10397
10403
  }
10398
10404
  element.appendChild(optionElement);
10399
10405
  });
10400
- if (this._config.debug)
10401
- console.log("Added ".concat(items.length, " options to select element"));
10402
- }
10403
- else {
10404
- if (this._config.debug)
10405
- console.log('No items to generate options from');
10406
10406
  }
10407
10407
  };
10408
10408
  /**
@@ -10415,8 +10415,6 @@ var KTSelect = /** @class */ (function (_super) {
10415
10415
  var result = key
10416
10416
  .split('.')
10417
10417
  .reduce(function (o, k) { return (o && o[k] !== undefined ? o[k] : null); }, obj);
10418
- if (this._config.debug)
10419
- console.log("Extracting [".concat(key, "] from object => ").concat(result !== null ? JSON.stringify(result) : 'null'));
10420
10418
  return result;
10421
10419
  };
10422
10420
  /**
@@ -10449,33 +10447,48 @@ var KTSelect = /** @class */ (function (_super) {
10449
10447
  * Open the dropdown
10450
10448
  */
10451
10449
  KTSelect.prototype.openDropdown = function () {
10450
+ var _this = this;
10452
10451
  if (this._config.disabled) {
10453
- if (this._config.debug)
10454
- console.log('openDropdown: select is disabled, not opening');
10455
10452
  return;
10456
10453
  }
10457
- if (this._config.debug)
10458
- console.log('openDropdown called, dropdownModule exists:', !!this._dropdownModule);
10459
10454
  if (!this._dropdownModule) {
10460
- if (this._config.debug)
10461
- console.log('Early return from openDropdown - module missing');
10462
10455
  return;
10463
10456
  }
10464
10457
  // Don't open dropdown if the select is disabled
10465
10458
  if (this._config.disabled) {
10466
- if (this._config.debug)
10467
- console.log('Early return from openDropdown - select is disabled');
10468
10459
  return;
10469
10460
  }
10470
- if (this._config.debug)
10471
- console.log('Opening dropdown via dropdownModule...');
10461
+ // Global dropdown management: close other open dropdowns if configured
10462
+ var closeOnOtherOpen = this._config.closeOnOtherOpen !== false; // Default to true
10463
+ if (closeOnOtherOpen) {
10464
+ // Close all other open dropdowns
10465
+ var otherSelectsToClose_1 = [];
10466
+ KTSelect.openDropdowns.forEach(function (otherSelect) {
10467
+ var isOther = otherSelect !== _this;
10468
+ var isOpen = otherSelect._dropdownIsOpen;
10469
+ if (isOther && isOpen) {
10470
+ otherSelectsToClose_1.push(otherSelect);
10471
+ }
10472
+ });
10473
+ otherSelectsToClose_1.forEach(function (otherSelect) {
10474
+ otherSelect.closeDropdown();
10475
+ });
10476
+ }
10472
10477
  // Set our internal flag to match what we're doing
10473
10478
  this._dropdownIsOpen = true;
10479
+ // Add to registry
10480
+ KTSelect.openDropdowns.add(this);
10474
10481
  // Open the dropdown via the module
10475
10482
  this._dropdownModule.open();
10476
- // Dispatch custom event
10483
+ // Dispatch custom events
10477
10484
  this._dispatchEvent('show');
10478
10485
  this._fireEvent('show');
10486
+ // Dispatch dropdown.show event on wrapper for search module
10487
+ var dropdownShowEvent = new CustomEvent('dropdown.show', {
10488
+ bubbles: true,
10489
+ cancelable: true,
10490
+ });
10491
+ this._wrapperElement.dispatchEvent(dropdownShowEvent);
10479
10492
  // Update ARIA states
10480
10493
  this._setAriaAttributes();
10481
10494
  // Update select all button state
@@ -10487,17 +10500,10 @@ var KTSelect = /** @class */ (function (_super) {
10487
10500
  * Close the dropdown
10488
10501
  */
10489
10502
  KTSelect.prototype.closeDropdown = function () {
10490
- if (this._config.debug)
10491
- console.log('closeDropdown called, dropdownModule exists:', !!this._dropdownModule);
10492
10503
  // Only check if dropdown module exists, not dropdownIsOpen flag
10493
10504
  if (!this._dropdownModule) {
10494
- if (this._config.debug)
10495
- console.log('Early return from closeDropdown - module missing');
10496
10505
  return;
10497
10506
  }
10498
- // Always close by delegating to the dropdown module, which is the source of truth
10499
- if (this._config.debug)
10500
- console.log('Closing dropdown via dropdownModule...');
10501
10507
  // Clear search input if the dropdown is closing
10502
10508
  if (this._searchModule && this._searchInputElement) {
10503
10509
  // Clear search input if configured to do so
@@ -10509,6 +10515,8 @@ var KTSelect = /** @class */ (function (_super) {
10509
10515
  }
10510
10516
  // Set our internal flag to match what we're doing
10511
10517
  this._dropdownIsOpen = false;
10518
+ // Remove from registry
10519
+ KTSelect.openDropdowns.delete(this);
10512
10520
  // Call the dropdown module's close method
10513
10521
  this._dropdownModule.close();
10514
10522
  // Reset all focus states
@@ -10518,10 +10526,14 @@ var KTSelect = /** @class */ (function (_super) {
10518
10526
  // Dispatch custom events
10519
10527
  this._dispatchEvent('close');
10520
10528
  this._fireEvent('close');
10529
+ // Dispatch dropdown.close event on wrapper for search module
10530
+ var dropdownCloseEvent = new CustomEvent('dropdown.close', {
10531
+ bubbles: true,
10532
+ cancelable: true,
10533
+ });
10534
+ this._wrapperElement.dispatchEvent(dropdownCloseEvent);
10521
10535
  // Update ARIA states
10522
10536
  this._setAriaAttributes();
10523
- if (this._config.debug)
10524
- console.log('closeDropdown complete');
10525
10537
  };
10526
10538
  /**
10527
10539
  * Update dropdown position
@@ -10558,8 +10570,6 @@ var KTSelect = /** @class */ (function (_super) {
10558
10570
  KTSelect.prototype._selectOption = function (value) {
10559
10571
  // Prevent selection if the option is disabled (in dropdown or original select)
10560
10572
  if (this._isOptionDisabled(value)) {
10561
- if (this._config.debug)
10562
- console.log('_selectOption: Option is disabled, ignoring selection');
10563
10573
  return;
10564
10574
  }
10565
10575
  // Get current selection state
@@ -10688,8 +10698,6 @@ var KTSelect = /** @class */ (function (_super) {
10688
10698
  var selectedValues = this._state.getSelectedOptions();
10689
10699
  var maxReached = typeof this._config.maxSelections === 'number' &&
10690
10700
  selectedValues.length >= this._config.maxSelections;
10691
- if (this._config.debug)
10692
- console.log('Updating selected classes for options, selected values:', selectedValues);
10693
10701
  allOptions.forEach(function (option) {
10694
10702
  var optionValue = option.getAttribute('data-value');
10695
10703
  if (!optionValue)
@@ -10790,36 +10798,24 @@ var KTSelect = /** @class */ (function (_super) {
10790
10798
  * Handle clicking on an option in the dropdown
10791
10799
  */
10792
10800
  KTSelect.prototype._handleOptionClick = function (event) {
10793
- if (this._config.debug)
10794
- console.log('_handleOptionClick called', event.target);
10795
10801
  event.preventDefault();
10796
10802
  event.stopPropagation();
10797
10803
  // Find the clicked option element
10798
10804
  var clickedOption = event.target.closest("[data-kt-select-option]");
10799
10805
  if (!clickedOption) {
10800
- if (this._config.debug)
10801
- console.log('No clicked option found');
10802
10806
  return;
10803
10807
  }
10804
10808
  // Check if the option is disabled
10805
10809
  if (clickedOption.getAttribute('aria-disabled') === 'true') {
10806
- if (this._config.debug)
10807
- console.log('Option is disabled, ignoring click');
10808
10810
  return;
10809
10811
  }
10810
10812
  // Use dataset.value to get the option value
10811
10813
  var optionValue = clickedOption.dataset.value;
10812
10814
  if (optionValue === undefined) {
10813
- if (this._config.debug)
10814
- console.log('Option value is undefined');
10815
10815
  return;
10816
10816
  }
10817
- if (this._config.debug)
10818
- console.log('Option clicked:', optionValue);
10819
10817
  // If in single-select mode and the clicked option is already selected, just close the dropdown.
10820
10818
  if (!this._config.multiple && this._state.isSelected(optionValue)) {
10821
- if (this._config.debug)
10822
- console.log('Single select mode: clicked already selected option. Closing dropdown.');
10823
10819
  this.closeDropdown();
10824
10820
  return;
10825
10821
  }
@@ -10948,22 +10944,14 @@ var KTSelect = /** @class */ (function (_super) {
10948
10944
  KTSelect.prototype.toggleSelection = function (value) {
10949
10945
  // Prevent selection if the option is disabled (in dropdown or original select)
10950
10946
  if (this._isOptionDisabled(value)) {
10951
- if (this._config.debug)
10952
- console.log('toggleSelection: Option is disabled, ignoring selection');
10953
10947
  return;
10954
10948
  }
10955
10949
  // Get current selection state
10956
10950
  var isSelected = this._state.isSelected(value);
10957
- if (this._config.debug)
10958
- console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple));
10959
10951
  // If already selected in single select mode, do nothing (can't deselect in single select)
10960
10952
  if (isSelected && !this._config.multiple) {
10961
- if (this._config.debug)
10962
- console.log('Early return from toggleSelection - already selected in single select mode');
10963
10953
  return;
10964
10954
  }
10965
- if (this._config.debug)
10966
- console.log("Toggling selection for option: ".concat(value, ", currently selected: ").concat(isSelected));
10967
10955
  // Ensure any search input is cleared when selection changes
10968
10956
  if (this._searchModule) {
10969
10957
  this._searchModule.clearSearch();
@@ -10988,16 +10976,21 @@ var KTSelect = /** @class */ (function (_super) {
10988
10976
  this.updateSelectedOptionDisplay();
10989
10977
  // Update option classes without re-rendering the dropdown content
10990
10978
  this._updateSelectedOptionClass();
10991
- // For single select mode, always close the dropdown after selection
10979
+ // For single select mode, close the dropdown after selection unless closeOnEnter is false
10992
10980
  // For multiple select mode, keep the dropdown open to allow multiple selections
10993
10981
  if (!this._config.multiple) {
10994
- if (this._config.debug)
10995
- console.log('About to call closeDropdown() for single select mode - always close after selection');
10996
- this.closeDropdown();
10982
+ // Check if we should close based on closeOnEnter config
10983
+ // closeOnEnter only applies to Enter key selections, but for backward compatibility,
10984
+ // we'll respect it for all selections when explicitly set to false
10985
+ var shouldClose = this._config.closeOnEnter !== false; // Default to true
10986
+ if (shouldClose) {
10987
+ this.closeDropdown();
10988
+ }
10989
+ else {
10990
+ this.updateSelectAllButtonState();
10991
+ }
10997
10992
  }
10998
10993
  else {
10999
- if (this._config.debug)
11000
- console.log('Multiple select mode - keeping dropdown open for additional selections');
11001
10994
  // Don't close dropdown in multiple select mode to allow multiple selections
11002
10995
  this.updateSelectAllButtonState();
11003
10996
  }
@@ -11129,9 +11122,6 @@ var KTSelect = /** @class */ (function (_super) {
11129
11122
  var validSelections = currentlySelected.filter(function (value) {
11130
11123
  return availableValues.includes(value);
11131
11124
  });
11132
- if (_this._config.debug && currentlySelected.length > 0) {
11133
- console.log('update(): Preserving selections that exist in new data:', validSelections);
11134
- }
11135
11125
  // Add new options from remote data and restore selection state
11136
11126
  items.forEach(function (item) {
11137
11127
  var option = document.createElement('option');
@@ -11214,9 +11204,6 @@ var KTSelect = /** @class */ (function (_super) {
11214
11204
  var validSelections = currentlySelected.filter(function (value) {
11215
11205
  return availableValues.includes(value);
11216
11206
  });
11217
- if (_this._config.debug && currentlySelected.length > 0) {
11218
- console.log('reload(): Preserving selections that exist in new data:', validSelections);
11219
- }
11220
11207
  // Mark preserved selections on new options
11221
11208
  validSelections.forEach(function (value) {
11222
11209
  var option = Array.from(_this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
@@ -11280,9 +11267,6 @@ var KTSelect = /** @class */ (function (_super) {
11280
11267
  var validSelections = currentlySelected.filter(function (value) {
11281
11268
  return availableValues.includes(value);
11282
11269
  });
11283
- if (_this._config.debug && currentlySelected.length > 0) {
11284
- console.log('refresh(): Preserving selections that exist in new data:', validSelections);
11285
- }
11286
11270
  // Add new options and restore selection state
11287
11271
  items.forEach(function (item) {
11288
11272
  var option = document.createElement('option');
@@ -11461,9 +11445,6 @@ var KTSelect = /** @class */ (function (_super) {
11461
11445
  this._searchModule.refreshAfterSearch();
11462
11446
  }
11463
11447
  this.updateSelectAllButtonState();
11464
- if (this._config.debug) {
11465
- console.log('Restored original options after search clear');
11466
- }
11467
11448
  };
11468
11449
  /**
11469
11450
  * Update search results in the dropdown
@@ -11514,9 +11495,6 @@ var KTSelect = /** @class */ (function (_super) {
11514
11495
  }
11515
11496
  _this._element.appendChild(optionElement);
11516
11497
  });
11517
- if (this._config.debug) {
11518
- console.log("Updated original select with ".concat(items.length, " search results"));
11519
- }
11520
11498
  };
11521
11499
  /**
11522
11500
  * Check if dropdown is open
@@ -11641,8 +11619,6 @@ var KTSelect = /** @class */ (function (_super) {
11641
11619
  if (val !== undefined &&
11642
11620
  !this._config.multiple &&
11643
11621
  this._state.isSelected(val)) {
11644
- if (this._config.debug)
11645
- console.log('Enter on already selected item in single-select mode. Closing.');
11646
11622
  this.closeDropdown();
11647
11623
  event.preventDefault();
11648
11624
  break;
@@ -11826,8 +11802,23 @@ var KTSelect = /** @class */ (function (_super) {
11826
11802
  ? this._config.clearAllText
11827
11803
  : this._config.selectAllText;
11828
11804
  };
11805
+ /**
11806
+ * Destroy the component and clean up resources
11807
+ */
11808
+ KTSelect.prototype.destroy = function () {
11809
+ // Remove from global dropdown registry
11810
+ KTSelect.openDropdowns.delete(this);
11811
+ // Close dropdown if open
11812
+ if (this._dropdownIsOpen) {
11813
+ this.closeDropdown();
11814
+ }
11815
+ // Call parent dispose method
11816
+ _super.prototype.dispose.call(this);
11817
+ };
11829
11818
  // Static global configuration
11830
11819
  KTSelect.globalConfig = {};
11820
+ // Static registry for tracking open dropdowns (global dropdown management)
11821
+ KTSelect.openDropdowns = new Set();
11831
11822
  return KTSelect;
11832
11823
  }(component_1.default));
11833
11824
  exports.KTSelect = KTSelect;
@@ -12510,8 +12501,6 @@ var KTSelectTags = /** @class */ (function () {
12510
12501
  this._config = select.getConfig();
12511
12502
  this._valueDisplayElement = select.getValueDisplayElement();
12512
12503
  this._eventManager = new utils_1.EventManager();
12513
- if (this._config.debug)
12514
- console.log('KTSelectTags initialized');
12515
12504
  }
12516
12505
  /**
12517
12506
  * Update selected tags display
@@ -14358,7 +14347,8 @@ exports.DefaultConfig = {
14358
14347
  searchMinLength: 0, // Minimum characters required to trigger search
14359
14348
  searchMaxItems: 50, // Maximum number of search results to display
14360
14349
  searchEmpty: 'No results', // Text to display when no search results are found
14361
- clearSearchOnClose: true, // Clear search input when dropdown closes
14350
+ clearSearchOnClose: false, // Clear search input when dropdown closes (default: false to persist search text)
14351
+ closeOnEnter: true, // Close dropdown when Enter is pressed in search input
14362
14352
  // Multi-Select Display
14363
14353
  selectAllText: 'Select all', // Text for the "Select All" option (if implemented)
14364
14354
  clearAllText: 'Clear all', // Text for the "Clear All" option (if implemented)
@@ -14376,6 +14366,8 @@ exports.DefaultConfig = {
14376
14366
  dropdownPreventOverflow: false,
14377
14367
  dropdownStrategy: null,
14378
14368
  dropdownWidth: null, // Custom width for dropdown (e.g., '300px'), null to match toggle element width
14369
+ closeOnOtherOpen: true, // Close other open dropdowns when this one opens
14370
+ dispatchGlobalEvents: true, // Dispatch events on document for global listeners (jQuery compatibility)
14379
14371
  // New Config
14380
14372
  dropdownTemplate: '',
14381
14373
  };