@keenthemes/ktui 1.0.12 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/dist/ktui.js +668 -685
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +5822 -0
  5. package/examples/select/avatar.html +47 -0
  6. package/examples/select/basic-usage.html +10 -14
  7. package/examples/select/{test.html → combobox-icons_.html} +13 -48
  8. package/examples/select/country.html +43 -0
  9. package/examples/select/description.html +25 -41
  10. package/examples/select/disable-option.html +10 -16
  11. package/examples/select/disable-select.html +7 -6
  12. package/examples/select/icon-multiple.html +23 -31
  13. package/examples/select/icon.html +20 -30
  14. package/examples/select/max-selection.html +8 -9
  15. package/examples/select/modal.html +19 -17
  16. package/examples/select/multiple.html +11 -13
  17. package/examples/select/placeholder.html +9 -12
  18. package/examples/select/search.html +30 -22
  19. package/examples/select/sizes.html +94 -0
  20. package/examples/select/template-customization.html +0 -3
  21. package/lib/cjs/components/component.js +1 -1
  22. package/lib/cjs/components/component.js.map +1 -1
  23. package/lib/cjs/components/datatable/datatable.js +1 -1
  24. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  25. package/lib/cjs/components/select/combobox.js +96 -61
  26. package/lib/cjs/components/select/combobox.js.map +1 -1
  27. package/lib/cjs/components/select/config.js +1 -3
  28. package/lib/cjs/components/select/config.js.map +1 -1
  29. package/lib/cjs/components/select/dropdown.js +32 -96
  30. package/lib/cjs/components/select/dropdown.js.map +1 -1
  31. package/lib/cjs/components/select/option.js +53 -20
  32. package/lib/cjs/components/select/option.js.map +1 -1
  33. package/lib/cjs/components/select/search.js +146 -97
  34. package/lib/cjs/components/select/search.js.map +1 -1
  35. package/lib/cjs/components/select/select.js +174 -120
  36. package/lib/cjs/components/select/select.js.map +1 -1
  37. package/lib/cjs/components/select/tags.js +0 -26
  38. package/lib/cjs/components/select/tags.js.map +1 -1
  39. package/lib/cjs/components/select/templates.js +130 -103
  40. package/lib/cjs/components/select/templates.js.map +1 -1
  41. package/lib/cjs/components/select/utils.js +33 -132
  42. package/lib/cjs/components/select/utils.js.map +1 -1
  43. package/lib/cjs/helpers/dom.js +0 -24
  44. package/lib/cjs/helpers/dom.js.map +1 -1
  45. package/lib/esm/components/component.js +1 -1
  46. package/lib/esm/components/component.js.map +1 -1
  47. package/lib/esm/components/datatable/datatable.js +1 -1
  48. package/lib/esm/components/datatable/datatable.js.map +1 -1
  49. package/lib/esm/components/select/combobox.js +96 -61
  50. package/lib/esm/components/select/combobox.js.map +1 -1
  51. package/lib/esm/components/select/config.js +1 -3
  52. package/lib/esm/components/select/config.js.map +1 -1
  53. package/lib/esm/components/select/dropdown.js +32 -96
  54. package/lib/esm/components/select/dropdown.js.map +1 -1
  55. package/lib/esm/components/select/option.js +53 -20
  56. package/lib/esm/components/select/option.js.map +1 -1
  57. package/lib/esm/components/select/search.js +146 -97
  58. package/lib/esm/components/select/search.js.map +1 -1
  59. package/lib/esm/components/select/select.js +174 -120
  60. package/lib/esm/components/select/select.js.map +1 -1
  61. package/lib/esm/components/select/tags.js +0 -26
  62. package/lib/esm/components/select/tags.js.map +1 -1
  63. package/lib/esm/components/select/templates.js +130 -103
  64. package/lib/esm/components/select/templates.js.map +1 -1
  65. package/lib/esm/components/select/utils.js +32 -130
  66. package/lib/esm/components/select/utils.js.map +1 -1
  67. package/lib/esm/helpers/dom.js +0 -24
  68. package/lib/esm/helpers/dom.js.map +1 -1
  69. package/package.json +9 -6
  70. package/src/components/component.ts +0 -4
  71. package/src/components/datatable/datatable.ts +1 -1
  72. package/src/components/input/input.css +1 -1
  73. package/src/components/scrollable/scrollable.css +9 -5
  74. package/src/components/select/combobox.ts +99 -88
  75. package/src/components/select/config.ts +2 -8
  76. package/src/components/select/dropdown.ts +43 -108
  77. package/src/components/select/option.ts +44 -25
  78. package/src/components/select/search.ts +158 -117
  79. package/src/components/select/select.css +97 -27
  80. package/src/components/select/select.ts +181 -127
  81. package/src/components/select/tags.ts +1 -27
  82. package/src/components/select/templates.ts +194 -131
  83. package/src/components/select/utils.ts +30 -166
  84. package/src/helpers/dom.ts +0 -30
  85. package/webpack.config.js +6 -1
  86. package/examples/select/combobox-icons.html +0 -58
  87. package/examples/select/icon-description.html +0 -56
  88. /package/examples/select/{combobox.html → combobox_.html} +0 -0
  89. /package/examples/select/{remote-data.html → remote-data_.html} +0 -0
  90. /package/examples/select/{tags-icons.html → tags-icons_.html} +0 -0
  91. /package/examples/select/{tags-selected.html → tags-selected_.html} +0 -0
  92. /package/examples/select/{tags.html → tags_.html} +0 -0
@@ -160,15 +160,16 @@ var KTSelect = /** @class */ (function (_super) {
160
160
  var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
161
161
  if (!optionsContainer)
162
162
  return;
163
+ // Clear previous messages
164
+ optionsContainer.innerHTML = '';
163
165
  switch (type) {
164
166
  case 'error':
165
- optionsContainer.innerHTML = defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message }));
167
+ optionsContainer.appendChild(defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message })));
166
168
  break;
167
169
  case 'loading':
168
- optionsContainer.innerHTML = defaultTemplates.loading(this._config, message || 'Loading...').outerHTML;
170
+ optionsContainer.appendChild(defaultTemplates.loading(this._config, message || 'Loading...'));
169
171
  break;
170
172
  case 'empty':
171
- optionsContainer.innerHTML = '';
172
173
  optionsContainer.appendChild(defaultTemplates.empty(this._config));
173
174
  break;
174
175
  }
@@ -340,7 +341,7 @@ var KTSelect = /** @class */ (function (_super) {
340
341
  // Initialize focus manager after dropdown element is created
341
342
  this._focusManager = new FocusManager(this._dropdownContentElement, '[data-kt-select-option]', this._config);
342
343
  // Initialize dropdown module after all elements are created
343
- this._dropdownModule = new KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config);
344
+ this._dropdownModule = new KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config, this);
344
345
  // Update display and set ARIA attributes
345
346
  this._updateDisplayAndAriaAttributes();
346
347
  this.updateSelectedOptionDisplay();
@@ -348,12 +349,6 @@ var KTSelect = /** @class */ (function (_super) {
348
349
  // Attach event listeners after all modules are initialized
349
350
  this._attachEventListeners();
350
351
  };
351
- /**
352
- * Initialize options HTML from data
353
- */
354
- // private _initializeOptionsHtml() {
355
- // this._generateOptionsHtml(this._element);
356
- // }
357
352
  /**
358
353
  * Creates the HTML structure for the select component
359
354
  */
@@ -423,7 +418,6 @@ var KTSelect = /** @class */ (function (_super) {
423
418
  if (!this._searchInputElement) {
424
419
  this._searchInputElement = this._displayElement;
425
420
  }
426
- this._valueDisplayElement = this._wrapperElement.querySelector("[data-kt-select-value]");
427
421
  this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
428
422
  };
429
423
  /**
@@ -434,16 +428,10 @@ var KTSelect = /** @class */ (function (_super) {
434
428
  document.addEventListener('click', this._handleDocumentClick.bind(this));
435
429
  // Dropdown option click events
436
430
  this._eventManager.addListener(this._dropdownContentElement, 'click', this._handleDropdownOptionClick.bind(this));
437
- // Only attach click handler to display element
438
- // this._eventManager.addListener(
439
- // this._wrapperElement,
440
- // 'click',
441
- // this._handleDropdownClick.bind(this),
442
- // );
443
- // Attach centralized keyboard handler
444
- var keyboardTarget = this._searchInputElement || this._wrapperElement;
445
- if (keyboardTarget) {
446
- keyboardTarget.addEventListener('keydown', this._handleKeyboardEvent.bind(this));
431
+ // Attach centralized keyboard handler to the wrapper element.
432
+ // Events from focusable children like _displayElement or _searchInputElement (if present) will bubble up.
433
+ if (this._wrapperElement) {
434
+ this._wrapperElement.addEventListener('keydown', this._handleKeyboardEvent.bind(this));
447
435
  }
448
436
  };
449
437
  /**
@@ -586,37 +574,10 @@ var KTSelect = /** @class */ (function (_super) {
586
574
  * DROPDOWN MANAGEMENT
587
575
  * ========================================================================
588
576
  */
589
- /**
590
- * Toggle dropdown visibility
591
- * @deprecated
592
- */
593
- KTSelect.prototype.toggleDropdown = function () {
594
- if (this._config.disabled) {
595
- if (this._config.debug)
596
- console.log('toggleDropdown: select is disabled, not opening');
597
- return;
598
- }
599
- if (this._config.debug)
600
- console.log('toggleDropdown called');
601
- if (this._dropdownModule) {
602
- // Always use the dropdown module's state to determine whether to open or close
603
- if (this._dropdownModule.isOpen()) {
604
- if (this._config.debug)
605
- console.log('Dropdown is open, closing...');
606
- this.closeDropdown();
607
- }
608
- else {
609
- if (this._config.debug)
610
- console.log('Dropdown is closed, opening...');
611
- this.openDropdown();
612
- }
613
- }
614
- };
615
577
  /**
616
578
  * Open the dropdown
617
579
  */
618
580
  KTSelect.prototype.openDropdown = function () {
619
- var _this = this;
620
581
  if (this._config.disabled) {
621
582
  if (this._config.debug)
622
583
  console.log('openDropdown: select is disabled, not opening');
@@ -644,14 +605,6 @@ var KTSelect = /** @class */ (function (_super) {
644
605
  // Dispatch custom event
645
606
  this._dispatchEvent('show');
646
607
  this._fireEvent('show');
647
- // Focus search input if configured and exists
648
- if (this._config.enableSearch &&
649
- this._config.searchAutofocus &&
650
- this._searchInputElement) {
651
- setTimeout(function () {
652
- _this._searchInputElement.focus();
653
- }, 50);
654
- }
655
608
  // Update ARIA states
656
609
  this._setAriaAttributes();
657
610
  // Focus the first selected option or first option if nothing selected
@@ -672,14 +625,14 @@ var KTSelect = /** @class */ (function (_super) {
672
625
  // Always close by delegating to the dropdown module, which is the source of truth
673
626
  if (this._config.debug)
674
627
  console.log('Closing dropdown via dropdownModule...');
675
- // Clear search input and highlights if the dropdown is closing
628
+ // Clear search input if the dropdown is closing
676
629
  if (this._searchModule && this._searchInputElement) {
677
630
  // Clear search input if configured to do so
678
631
  if (this._config.clearSearchOnClose) {
679
632
  this._searchInputElement.value = '';
680
633
  }
681
- // Always clear the highlights when dropdown closes
682
- this._searchModule.clearSearchHighlights();
634
+ // Clear search input when dropdown closes
635
+ this._searchModule.clearSearch();
683
636
  }
684
637
  // Set our internal flag to match what we're doing
685
638
  this._dropdownIsOpen = false;
@@ -713,10 +666,13 @@ var KTSelect = /** @class */ (function (_super) {
713
666
  var selectedOptions = this.getSelectedOptions();
714
667
  if (selectedOptions.length === 0)
715
668
  return;
716
- // Get the first selected option element
717
- var firstSelectedValue = selectedOptions[0];
718
- // Use the FocusManager to focus on the option
719
- this._focusManager.focusOptionByValue(firstSelectedValue);
669
+ // Iterate through selected options and focus the first one that is visible
670
+ for (var _i = 0, selectedOptions_1 = selectedOptions; _i < selectedOptions_1.length; _i++) {
671
+ var value = selectedOptions_1[_i];
672
+ if (this._focusManager && this._focusManager.focusOptionByValue(value)) {
673
+ break; // Stop after focusing the first found selected and visible option
674
+ }
675
+ }
720
676
  };
721
677
  /**
722
678
  * ========================================================================
@@ -779,38 +735,90 @@ var KTSelect = /** @class */ (function (_super) {
779
735
  */
780
736
  KTSelect.prototype.updateSelectedOptionDisplay = function () {
781
737
  var selectedOptions = this.getSelectedOptions();
782
- // Tag mode: render tags if enabled
783
- if (this._config.tags && this._tagsModule) {
738
+ var tagsEnabled = this._config.tags && this._tagsModule;
739
+ var valueDisplayEl = this.getValueDisplayElement();
740
+ if (tagsEnabled) {
741
+ // Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
784
742
  this._tagsModule.updateTagsDisplay(selectedOptions);
785
- return;
786
743
  }
744
+ // Guard against valueDisplayEl being null due to template modifications
745
+ if (!valueDisplayEl) {
746
+ if (this._config.debug) {
747
+ console.warn('KTSelect: Value display element is null. Cannot update display or placeholder. Check template for [data-kt-select-value].');
748
+ }
749
+ return; // Nothing to display on if the element is missing
750
+ }
751
+ // 1. Custom render function takes highest precedence
787
752
  if (typeof this._config.renderSelected === 'function') {
788
- // Use the custom renderSelected function if provided
789
- this._valueDisplayElement.innerHTML = this._config.renderSelected(selectedOptions);
753
+ valueDisplayEl.innerHTML = this._config.renderSelected(selectedOptions);
754
+ return;
755
+ }
756
+ // 2. Custom displayTemplate string
757
+ // Check if a custom display template string is provided directly in config or via config.templates
758
+ var customDisplayTemplateString = this._config.displayTemplate || (this._config.templates && this._config.templates.display);
759
+ if (customDisplayTemplateString) {
760
+ // If tags are enabled and items are selected, the tags module handles display, so clear the main display area.
761
+ if (tagsEnabled && selectedOptions.length > 0) {
762
+ valueDisplayEl.innerHTML = '';
763
+ }
764
+ else {
765
+ // Otherwise, render the custom display template.
766
+ // If no options are selected, renderDisplayTemplateForSelected should handle showing a placeholder if the template supports it,
767
+ // or we might need a separate placeholder rendering for custom templates if they don't handle empty selection.
768
+ // For now, assume renderDisplayTemplateForSelected handles it or shows selected text.
769
+ valueDisplayEl.innerHTML = this.renderDisplayTemplateForSelected(selectedOptions);
770
+ }
771
+ return;
772
+ }
773
+ // 3. Default template behavior (no custom function or string template)
774
+ var textContainer = valueDisplayEl.querySelector('[data-kt-text-container="true"]');
775
+ if (tagsEnabled && selectedOptions.length > 0) {
776
+ // Tags are active and have content, clear the text container if it exists,
777
+ // or the whole display if it doesn't (though it should with default template).
778
+ if (textContainer) {
779
+ textContainer.innerHTML = '';
780
+ }
781
+ else {
782
+ valueDisplayEl.innerHTML = ''; // Fallback: clear entire display area
783
+ }
784
+ }
785
+ else if (selectedOptions.length === 0) {
786
+ // No options selected: display placeholder text in the text container.
787
+ var placeholderTemplate = defaultTemplates.placeholder(this._config);
788
+ var placeholderText = placeholderTemplate.textContent || ''; // Get text from placeholder element
789
+ if (textContainer) {
790
+ textContainer.innerHTML = placeholderText;
791
+ }
792
+ else {
793
+ // Fallback: If no text container, replace children of valueDisplayEl with the placeholder element itself.
794
+ // This ensures the placeholder (which might have its own structure/classes) is displayed.
795
+ valueDisplayEl.replaceChildren(placeholderTemplate);
796
+ }
790
797
  }
791
798
  else {
792
- if (selectedOptions.length === 0) {
793
- var placeholder = defaultTemplates.placeholder(this._config);
794
- this._valueDisplayElement.replaceChildren(placeholder);
799
+ // Options are selected, and tags are not enabled (or no selected options for tags):
800
+ // Render normal selected text in the text container.
801
+ var content = this.getSelectedOptionsText();
802
+ if (textContainer) {
803
+ textContainer.innerHTML = content;
795
804
  }
796
805
  else {
797
- var content = '';
798
- if (this._config.displayTemplate) {
799
- var selectedValues = this.getSelectedOptions();
800
- content = this.renderDisplayTemplateForSelected(selectedValues);
801
- }
802
- else {
803
- // If no displayTemplate is provided, use the default comma-separated list of selected options
804
- content = this.getSelectedOptionsText();
805
- }
806
- this._valueDisplayElement.innerHTML = content;
806
+ valueDisplayEl.innerHTML = content; // Fallback: set content on whole display area
807
807
  }
808
808
  }
809
809
  };
810
+ /**
811
+ * Check if an option was originally disabled in the HTML
812
+ */
813
+ KTSelect.prototype._isOptionOriginallyDisabled = function (value) {
814
+ var originalOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
815
+ return originalOption ? originalOption.disabled : false;
816
+ };
810
817
  /**
811
818
  * Update CSS classes for selected options
812
819
  */
813
820
  KTSelect.prototype._updateSelectedOptionClass = function () {
821
+ var _this = this;
814
822
  var allOptions = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
815
823
  var selectedValues = this._state.getSelectedOptions();
816
824
  var maxReached = typeof this._config.maxSelections === 'number' &&
@@ -822,9 +830,11 @@ var KTSelect = /** @class */ (function (_super) {
822
830
  if (!optionValue)
823
831
  return;
824
832
  var isSelected = selectedValues.includes(optionValue);
833
+ var isOriginallyDisabled = _this._isOptionOriginallyDisabled(optionValue);
825
834
  if (isSelected) {
826
835
  option.classList.add('selected');
827
836
  option.setAttribute('aria-selected', 'true');
837
+ // Selected options should not be visually hidden or disabled by maxSelections logic
828
838
  option.classList.remove('hidden');
829
839
  option.classList.remove('disabled');
830
840
  option.removeAttribute('aria-disabled');
@@ -832,7 +842,8 @@ var KTSelect = /** @class */ (function (_super) {
832
842
  else {
833
843
  option.classList.remove('selected');
834
844
  option.setAttribute('aria-selected', 'false');
835
- if (maxReached) {
845
+ // An option should be disabled if it was originally disabled OR if maxSelections is reached
846
+ if (isOriginallyDisabled || maxReached) {
836
847
  option.classList.add('disabled');
837
848
  option.setAttribute('aria-disabled', 'true');
838
849
  }
@@ -892,17 +903,6 @@ var KTSelect = /** @class */ (function (_super) {
892
903
  * EVENT HANDLERS
893
904
  * ========================================================================
894
905
  */
895
- /**
896
- * Handle display element click
897
- * @deprecated
898
- */
899
- KTSelect.prototype._handleDropdownClick = function (event) {
900
- if (this._config.debug)
901
- console.log('Display element clicked', event.target);
902
- event.preventDefault();
903
- event.stopPropagation(); // Prevent event bubbling
904
- this.toggleDropdown();
905
- };
906
906
  /**
907
907
  * Handle click within the dropdown
908
908
  */
@@ -943,6 +943,13 @@ var KTSelect = /** @class */ (function (_super) {
943
943
  }
944
944
  if (this._config.debug)
945
945
  console.log('Option clicked:', optionValue);
946
+ // If in single-select mode and the clicked option is already selected, just close the dropdown.
947
+ if (!this._config.multiple && this._state.isSelected(optionValue)) {
948
+ if (this._config.debug)
949
+ console.log('Single select mode: clicked already selected option. Closing dropdown.');
950
+ this.closeDropdown();
951
+ return;
952
+ }
946
953
  // Use toggleSelection instead of _selectOption to prevent re-rendering
947
954
  this.toggleSelection(optionValue);
948
955
  };
@@ -1006,7 +1013,13 @@ var KTSelect = /** @class */ (function (_super) {
1006
1013
  * Get value display element
1007
1014
  */
1008
1015
  KTSelect.prototype.getValueDisplayElement = function () {
1009
- return this._valueDisplayElement;
1016
+ return this._displayElement;
1017
+ };
1018
+ /**
1019
+ * Get wrapper element
1020
+ */
1021
+ KTSelect.prototype.getWrapperElement = function () {
1022
+ return this._wrapperElement;
1010
1023
  };
1011
1024
  /**
1012
1025
  * Show all options in the dropdown
@@ -1016,6 +1029,7 @@ var KTSelect = /** @class */ (function (_super) {
1016
1029
  var options = Array.from(this._wrapperElement.querySelectorAll("[data-kt-select-option]"));
1017
1030
  // Show all options by removing the hidden class and any inline styles
1018
1031
  options.forEach(function (option) {
1032
+ var _a;
1019
1033
  // Remove hidden class
1020
1034
  option.classList.remove('hidden');
1021
1035
  // Clean up any existing inline styles for backward compatibility
@@ -1029,7 +1043,7 @@ var KTSelect = /** @class */ (function (_super) {
1029
1043
  }
1030
1044
  else {
1031
1045
  // Otherwise, remove just the display property
1032
- option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
1046
+ option.setAttribute('style', (_a = styleAttr === null || styleAttr === void 0 ? void 0 : styleAttr.replace(/display:\s*[^;]+;?/gi, '')) === null || _a === void 0 ? void 0 : _a.trim());
1033
1047
  }
1034
1048
  }
1035
1049
  }
@@ -1039,7 +1053,7 @@ var KTSelect = /** @class */ (function (_super) {
1039
1053
  this._searchInputElement.value = '';
1040
1054
  // If we have a search module, clear any search filtering
1041
1055
  if (this._searchModule) {
1042
- this._searchModule.clearSearchHighlights();
1056
+ this._searchModule.clearSearch();
1043
1057
  }
1044
1058
  }
1045
1059
  };
@@ -1068,7 +1082,7 @@ var KTSelect = /** @class */ (function (_super) {
1068
1082
  // Get current selection state
1069
1083
  var isSelected = this._state.isSelected(value);
1070
1084
  if (this._config.debug)
1071
- console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple, ", closeOnSelect: ").concat(this._config.closeOnSelect));
1085
+ console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple));
1072
1086
  // If already selected in single select mode, do nothing (can't deselect in single select)
1073
1087
  if (isSelected && !this._config.multiple) {
1074
1088
  if (this._config.debug)
@@ -1077,9 +1091,9 @@ var KTSelect = /** @class */ (function (_super) {
1077
1091
  }
1078
1092
  if (this._config.debug)
1079
1093
  console.log("Toggling selection for option: ".concat(value, ", currently selected: ").concat(isSelected));
1080
- // Ensure any search highlights are cleared when selection changes
1094
+ // Ensure any search input is cleared when selection changes
1081
1095
  if (this._searchModule) {
1082
- this._searchModule.clearSearchHighlights();
1096
+ this._searchModule.clearSearch();
1083
1097
  }
1084
1098
  // Toggle the selection in the state
1085
1099
  this._state.toggleSelectedOptions(value);
@@ -1102,15 +1116,14 @@ var KTSelect = /** @class */ (function (_super) {
1102
1116
  // Update option classes without re-rendering the dropdown content
1103
1117
  this._updateSelectedOptionClass();
1104
1118
  // For single select mode, always close the dropdown after selection
1105
- // For multiple select mode, only close if closeOnSelect is true
1106
1119
  if (!this._config.multiple) {
1107
1120
  if (this._config.debug)
1108
1121
  console.log('About to call closeDropdown() for single select mode - always close after selection');
1109
1122
  this.closeDropdown();
1110
1123
  }
1111
- else if (this._config.closeOnSelect) {
1124
+ else {
1112
1125
  if (this._config.debug)
1113
- console.log('About to call closeDropdown() for multiple select with closeOnSelect:true');
1126
+ console.log('About to call closeDropdown() for multiple select');
1114
1127
  this.closeDropdown();
1115
1128
  }
1116
1129
  // Dispatch custom change event with additional data
@@ -1210,9 +1223,9 @@ var KTSelect = /** @class */ (function (_super) {
1210
1223
  .then(function () {
1211
1224
  // Update options in the dropdown
1212
1225
  _this._updateSearchResults(items);
1213
- // Refresh the search module's option cache if search is enabled
1214
- if (_this._searchModule && _this._config.enableSearch) {
1215
- _this._searchModule.refreshOptionCache();
1226
+ // Refresh the search module to update focus and cache
1227
+ if (_this._searchModule) {
1228
+ _this._searchModule.refreshAfterSearch();
1216
1229
  }
1217
1230
  })
1218
1231
  .catch(function (error) {
@@ -1309,19 +1322,47 @@ var KTSelect = /** @class */ (function (_super) {
1309
1322
  * Centralized keyboard event handler for all select modes
1310
1323
  */
1311
1324
  KTSelect.prototype._handleKeyboardEvent = function (event) {
1325
+ // If the event target is the search input and the event was already handled (defaultPrevented),
1326
+ // then return early to avoid duplicate processing by this broader handler.
1327
+ if (event.target === this._searchInputElement && event.defaultPrevented) {
1328
+ return;
1329
+ }
1312
1330
  var isOpen = this._dropdownIsOpen;
1313
1331
  var config = this._config;
1314
1332
  var focusManager = this._focusManager;
1315
1333
  var buffer = this._typeToSearchBuffer;
1316
- // Ignore modifier keys
1334
+ // If the event target is the search input, let it handle most typing keys naturally.
1335
+ if (event.target === this._searchInputElement) {
1336
+ // Allow navigation keys like ArrowDown, ArrowUp, Escape, Enter (for search/selection) to be handled by the logic below.
1337
+ // For other keys (characters, space, backspace, delete), let the input field process them.
1338
+ if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp' &&
1339
+ event.key !== 'Escape' && event.key !== 'Enter' && event.key !== 'Tab' &&
1340
+ event.key !== 'Home' && event.key !== 'End') {
1341
+ // If it's a character key and we are NOT type-to-searching (because search has focus)
1342
+ // then let the input field handle it for its own value.
1343
+ // The search module's 'input' event will handle filtering based on the input's value.
1344
+ buffer.clear(); // Clear type-to-search buffer when typing in search field
1345
+ return;
1346
+ }
1347
+ // For Enter specifically in search input, we might want to select the focused option or submit search.
1348
+ // This is handled later in the switch.
1349
+ }
1350
+ // Ignore modifier keys (except for specific combinations if added later)
1317
1351
  if (event.altKey || event.ctrlKey || event.metaKey)
1318
1352
  return;
1319
- // Type-to-search: only for single char keys
1320
- if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/)) {
1353
+ // Type-to-search: only for single char keys, when search input does not have focus
1354
+ if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/) && document.activeElement !== this._searchInputElement) {
1321
1355
  buffer.push(event.key);
1322
1356
  var str = buffer.getBuffer();
1323
- focusManager.focusByString(str);
1324
- return;
1357
+ if (isOpen) {
1358
+ focusManager.focusByString(str);
1359
+ }
1360
+ else {
1361
+ // If closed, type-to-search could potentially open and select.
1362
+ // For now, let's assume it only works when open or opens it first.
1363
+ // Or, we could find the matching option and set it directly without opening.
1364
+ }
1365
+ return; // Type-to-search handles the event
1325
1366
  }
1326
1367
  switch (event.key) {
1327
1368
  case 'ArrowDown':
@@ -1355,18 +1396,28 @@ var KTSelect = /** @class */ (function (_super) {
1355
1396
  case 'Enter':
1356
1397
  case ' ': // Space
1357
1398
  if (isOpen) {
1358
- var focused = focusManager.getFocusedOption();
1359
- if (focused) {
1360
- var value = focused.dataset.value;
1361
- if (value) {
1362
- this.toggleSelection(value);
1363
- if (!config.multiple && config.closeOnSelect) {
1364
- this.closeDropdown();
1365
- }
1399
+ var focusedOptionEl = this._focusManager.getFocusedOption();
1400
+ if (focusedOptionEl) {
1401
+ var val = focusedOptionEl.dataset.value;
1402
+ // If single select, and the item is already selected, just close.
1403
+ if (val !== undefined && !this._config.multiple && this._state.isSelected(val)) {
1404
+ if (this._config.debug)
1405
+ console.log('Enter on already selected item in single-select mode. Closing.');
1406
+ this.closeDropdown();
1407
+ event.preventDefault();
1408
+ break;
1366
1409
  }
1367
1410
  }
1368
- // Prevent form submit
1369
- event.preventDefault();
1411
+ // Proceed with selection if not handled above
1412
+ this.selectFocusedOption();
1413
+ // Close dropdown if configured to do so (for new selections)
1414
+ if (!this._config.multiple) {
1415
+ // This will also be true for the case handled above, but closeDropdown is idempotent.
1416
+ // However, the break above prevents this from being reached for that specific case.
1417
+ this.closeDropdown();
1418
+ }
1419
+ event.preventDefault(); // Prevent form submission or other default actions
1420
+ break;
1370
1421
  }
1371
1422
  else {
1372
1423
  this.openDropdown();
@@ -1410,6 +1461,9 @@ var KTSelect = /** @class */ (function (_super) {
1410
1461
  }).filter(Boolean)));
1411
1462
  return contentArray.join(displaySeparator);
1412
1463
  };
1464
+ KTSelect.prototype.getDisplayElement = function () {
1465
+ return this._displayElement;
1466
+ };
1413
1467
  /**
1414
1468
  * ========================================================================
1415
1469
  * STATIC METHODS