@keenthemes/ktui 1.0.12 → 1.0.14
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.
- package/dist/ktui.js +738 -700
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +5824 -0
- package/examples/select/avatar.html +47 -0
- package/examples/select/basic-usage.html +10 -14
- package/examples/select/{test.html → combobox-icons_.html} +13 -48
- package/examples/select/country.html +43 -0
- package/examples/select/description.html +25 -41
- package/examples/select/disable-option.html +10 -16
- package/examples/select/disable-select.html +7 -6
- package/examples/select/icon-multiple.html +23 -31
- package/examples/select/icon.html +20 -30
- package/examples/select/max-selection.html +8 -9
- package/examples/select/modal.html +16 -17
- package/examples/select/multiple.html +11 -13
- package/examples/select/placeholder.html +9 -12
- package/examples/select/search.html +30 -22
- package/examples/select/sizes.html +94 -0
- package/examples/select/template-customization.html +0 -3
- package/lib/cjs/components/component.js +1 -1
- package/lib/cjs/components/component.js.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +14 -11
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/select/combobox.js +96 -61
- package/lib/cjs/components/select/combobox.js.map +1 -1
- package/lib/cjs/components/select/config.js +13 -8
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js +32 -96
- package/lib/cjs/components/select/dropdown.js.map +1 -1
- package/lib/cjs/components/select/option.js +53 -20
- package/lib/cjs/components/select/option.js.map +1 -1
- package/lib/cjs/components/select/search.js +146 -97
- package/lib/cjs/components/select/search.js.map +1 -1
- package/lib/cjs/components/select/select.js +219 -118
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/tags.js +0 -26
- package/lib/cjs/components/select/tags.js.map +1 -1
- package/lib/cjs/components/select/templates.js +130 -105
- package/lib/cjs/components/select/templates.js.map +1 -1
- package/lib/cjs/components/select/utils.js +33 -132
- package/lib/cjs/components/select/utils.js.map +1 -1
- package/lib/cjs/helpers/dom.js +0 -24
- package/lib/cjs/helpers/dom.js.map +1 -1
- package/lib/esm/components/component.js +1 -1
- package/lib/esm/components/component.js.map +1 -1
- package/lib/esm/components/datatable/datatable.js +14 -11
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/select/combobox.js +96 -61
- package/lib/esm/components/select/combobox.js.map +1 -1
- package/lib/esm/components/select/config.js +13 -8
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/dropdown.js +32 -96
- package/lib/esm/components/select/dropdown.js.map +1 -1
- package/lib/esm/components/select/option.js +53 -20
- package/lib/esm/components/select/option.js.map +1 -1
- package/lib/esm/components/select/search.js +146 -97
- package/lib/esm/components/select/search.js.map +1 -1
- package/lib/esm/components/select/select.js +219 -118
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/tags.js +0 -26
- package/lib/esm/components/select/tags.js.map +1 -1
- package/lib/esm/components/select/templates.js +130 -105
- package/lib/esm/components/select/templates.js.map +1 -1
- package/lib/esm/components/select/utils.js +32 -130
- package/lib/esm/components/select/utils.js.map +1 -1
- package/lib/esm/helpers/dom.js +0 -24
- package/lib/esm/helpers/dom.js.map +1 -1
- package/package.json +9 -6
- package/src/components/component.ts +0 -4
- package/src/components/datatable/datatable.ts +14 -11
- package/src/components/input/input.css +1 -1
- package/src/components/scrollable/scrollable.css +9 -5
- package/src/components/select/combobox.ts +98 -87
- package/src/components/select/config.ts +16 -13
- package/src/components/select/dropdown.ts +43 -108
- package/src/components/select/option.ts +44 -25
- package/src/components/select/search.ts +158 -117
- package/src/components/select/select.css +99 -27
- package/src/components/select/select.ts +236 -128
- package/src/components/select/tags.ts +1 -27
- package/src/components/select/templates.ts +191 -132
- package/src/components/select/utils.ts +30 -166
- package/src/components/toast/toast.css +1 -1
- package/src/helpers/dom.ts +0 -30
- package/webpack.config.js +6 -1
- package/examples/select/combobox-icons.html +0 -58
- package/examples/select/icon-description.html +0 -56
- /package/examples/select/{combobox.html → combobox_.html} +0 -0
- /package/examples/select/{remote-data.html → remote-data_.html} +0 -0
- /package/examples/select/{tags-icons.html → tags-icons_.html} +0 -0
- /package/examples/select/{tags-selected.html → tags-selected_.html} +0 -0
- /package/examples/select/{tags.html → tags_.html} +0 -0
|
@@ -66,6 +66,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
66
66
|
_this._dropdownModule = null;
|
|
67
67
|
_this._loadMoreIndicator = null;
|
|
68
68
|
_this._typeToSearchBuffer = new TypeToSearchBuffer();
|
|
69
|
+
_this._mutationObserver = null;
|
|
69
70
|
// Search debounce timeout
|
|
70
71
|
_this._searchDebounceTimeout = null;
|
|
71
72
|
// Store original options HTML for restoring after search
|
|
@@ -160,15 +161,16 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
160
161
|
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
161
162
|
if (!optionsContainer)
|
|
162
163
|
return;
|
|
164
|
+
// Clear previous messages
|
|
165
|
+
optionsContainer.innerHTML = '';
|
|
163
166
|
switch (type) {
|
|
164
167
|
case 'error':
|
|
165
|
-
optionsContainer.
|
|
168
|
+
optionsContainer.appendChild(defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message })));
|
|
166
169
|
break;
|
|
167
170
|
case 'loading':
|
|
168
|
-
optionsContainer.
|
|
171
|
+
optionsContainer.appendChild(defaultTemplates.loading(this._config, message || 'Loading...'));
|
|
169
172
|
break;
|
|
170
173
|
case 'empty':
|
|
171
|
-
optionsContainer.innerHTML = '';
|
|
172
174
|
optionsContainer.appendChild(defaultTemplates.empty(this._config));
|
|
173
175
|
break;
|
|
174
176
|
}
|
|
@@ -340,20 +342,15 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
340
342
|
// Initialize focus manager after dropdown element is created
|
|
341
343
|
this._focusManager = new FocusManager(this._dropdownContentElement, '[data-kt-select-option]', this._config);
|
|
342
344
|
// Initialize dropdown module after all elements are created
|
|
343
|
-
this._dropdownModule = new KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config);
|
|
345
|
+
this._dropdownModule = new KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config, this);
|
|
344
346
|
// Update display and set ARIA attributes
|
|
345
347
|
this._updateDisplayAndAriaAttributes();
|
|
346
348
|
this.updateSelectedOptionDisplay();
|
|
347
349
|
this._setAriaAttributes();
|
|
348
350
|
// Attach event listeners after all modules are initialized
|
|
349
351
|
this._attachEventListeners();
|
|
352
|
+
this._observeNativeSelect();
|
|
350
353
|
};
|
|
351
|
-
/**
|
|
352
|
-
* Initialize options HTML from data
|
|
353
|
-
*/
|
|
354
|
-
// private _initializeOptionsHtml() {
|
|
355
|
-
// this._generateOptionsHtml(this._element);
|
|
356
|
-
// }
|
|
357
354
|
/**
|
|
358
355
|
* Creates the HTML structure for the select component
|
|
359
356
|
*/
|
|
@@ -368,7 +365,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
368
365
|
wrapperElement.appendChild(displayElement);
|
|
369
366
|
// Move classes from original select to display element
|
|
370
367
|
if (this._element.classList.length > 0) {
|
|
371
|
-
|
|
368
|
+
// Exclude kt-select class from being added to the wrapper element
|
|
369
|
+
var classes = Array.from(this._element.classList).filter(function (className) { return className !== 'kt-select'; });
|
|
370
|
+
(_a = wrapperElement.classList).add.apply(_a, classes);
|
|
371
|
+
// If element has class kt-select, move it to display element
|
|
372
|
+
if (this._element.classList.contains('kt-select')) {
|
|
373
|
+
displayElement.classList.add('kt-select');
|
|
374
|
+
}
|
|
372
375
|
this._element.className = '';
|
|
373
376
|
}
|
|
374
377
|
// Create an empty dropdown first (without options) using template
|
|
@@ -402,7 +405,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
402
405
|
wrapperElement.appendChild(dropdownElement);
|
|
403
406
|
// Insert after the original element
|
|
404
407
|
this._element.after(wrapperElement);
|
|
405
|
-
this._element.
|
|
408
|
+
this._element.classList.add('hidden');
|
|
406
409
|
};
|
|
407
410
|
/**
|
|
408
411
|
* Setup all element references after DOM is created
|
|
@@ -423,7 +426,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
423
426
|
if (!this._searchInputElement) {
|
|
424
427
|
this._searchInputElement = this._displayElement;
|
|
425
428
|
}
|
|
426
|
-
this._valueDisplayElement = this._wrapperElement.querySelector("[data-kt-select-value]");
|
|
427
429
|
this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
|
|
428
430
|
};
|
|
429
431
|
/**
|
|
@@ -434,16 +436,10 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
434
436
|
document.addEventListener('click', this._handleDocumentClick.bind(this));
|
|
435
437
|
// Dropdown option click events
|
|
436
438
|
this._eventManager.addListener(this._dropdownContentElement, 'click', this._handleDropdownOptionClick.bind(this));
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
|
|
440
|
-
|
|
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));
|
|
439
|
+
// Attach centralized keyboard handler to the wrapper element.
|
|
440
|
+
// Events from focusable children like _displayElement or _searchInputElement (if present) will bubble up.
|
|
441
|
+
if (this._wrapperElement) {
|
|
442
|
+
this._wrapperElement.addEventListener('keydown', this._handleKeyboardEvent.bind(this));
|
|
447
443
|
}
|
|
448
444
|
};
|
|
449
445
|
/**
|
|
@@ -586,37 +582,10 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
586
582
|
* DROPDOWN MANAGEMENT
|
|
587
583
|
* ========================================================================
|
|
588
584
|
*/
|
|
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
585
|
/**
|
|
616
586
|
* Open the dropdown
|
|
617
587
|
*/
|
|
618
588
|
KTSelect.prototype.openDropdown = function () {
|
|
619
|
-
var _this = this;
|
|
620
589
|
if (this._config.disabled) {
|
|
621
590
|
if (this._config.debug)
|
|
622
591
|
console.log('openDropdown: select is disabled, not opening');
|
|
@@ -644,14 +613,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
644
613
|
// Dispatch custom event
|
|
645
614
|
this._dispatchEvent('show');
|
|
646
615
|
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
616
|
// Update ARIA states
|
|
656
617
|
this._setAriaAttributes();
|
|
657
618
|
// Focus the first selected option or first option if nothing selected
|
|
@@ -672,14 +633,14 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
672
633
|
// Always close by delegating to the dropdown module, which is the source of truth
|
|
673
634
|
if (this._config.debug)
|
|
674
635
|
console.log('Closing dropdown via dropdownModule...');
|
|
675
|
-
// Clear search input
|
|
636
|
+
// Clear search input if the dropdown is closing
|
|
676
637
|
if (this._searchModule && this._searchInputElement) {
|
|
677
638
|
// Clear search input if configured to do so
|
|
678
639
|
if (this._config.clearSearchOnClose) {
|
|
679
640
|
this._searchInputElement.value = '';
|
|
680
641
|
}
|
|
681
|
-
//
|
|
682
|
-
this._searchModule.
|
|
642
|
+
// Clear search input when dropdown closes
|
|
643
|
+
this._searchModule.clearSearch();
|
|
683
644
|
}
|
|
684
645
|
// Set our internal flag to match what we're doing
|
|
685
646
|
this._dropdownIsOpen = false;
|
|
@@ -713,10 +674,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
713
674
|
var selectedOptions = this.getSelectedOptions();
|
|
714
675
|
if (selectedOptions.length === 0)
|
|
715
676
|
return;
|
|
716
|
-
//
|
|
717
|
-
var
|
|
718
|
-
|
|
719
|
-
|
|
677
|
+
// Iterate through selected options and focus the first one that is visible
|
|
678
|
+
for (var _i = 0, selectedOptions_1 = selectedOptions; _i < selectedOptions_1.length; _i++) {
|
|
679
|
+
var value = selectedOptions_1[_i];
|
|
680
|
+
if (this._focusManager && this._focusManager.focusOptionByValue(value)) {
|
|
681
|
+
break; // Stop after focusing the first found selected and visible option
|
|
682
|
+
}
|
|
683
|
+
}
|
|
720
684
|
};
|
|
721
685
|
/**
|
|
722
686
|
* ========================================================================
|
|
@@ -779,38 +743,62 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
779
743
|
*/
|
|
780
744
|
KTSelect.prototype.updateSelectedOptionDisplay = function () {
|
|
781
745
|
var selectedOptions = this.getSelectedOptions();
|
|
782
|
-
|
|
783
|
-
|
|
746
|
+
var tagsEnabled = this._config.tags && this._tagsModule;
|
|
747
|
+
var valueDisplayEl = this.getValueDisplayElement();
|
|
748
|
+
if (tagsEnabled) {
|
|
749
|
+
// Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
|
|
784
750
|
this._tagsModule.updateTagsDisplay(selectedOptions);
|
|
785
|
-
|
|
751
|
+
}
|
|
752
|
+
// Guard against valueDisplayEl being null due to template modifications
|
|
753
|
+
if (!valueDisplayEl) {
|
|
754
|
+
if (this._config.debug) {
|
|
755
|
+
console.warn('KTSelect: Value display element is null. Cannot update display or placeholder. Check template for [data-kt-select-value].');
|
|
756
|
+
}
|
|
757
|
+
return; // Nothing to display on if the element is missing
|
|
786
758
|
}
|
|
787
759
|
if (typeof this._config.renderSelected === 'function') {
|
|
788
|
-
|
|
789
|
-
this._valueDisplayElement.innerHTML = this._config.renderSelected(selectedOptions);
|
|
760
|
+
valueDisplayEl.innerHTML = this._config.renderSelected(selectedOptions);
|
|
790
761
|
}
|
|
791
762
|
else {
|
|
792
763
|
if (selectedOptions.length === 0) {
|
|
793
|
-
|
|
794
|
-
|
|
764
|
+
// No options selected: display placeholder.
|
|
765
|
+
// This runs if tags are off, OR if tags are on but no items are selected (tags module would have cleared tags).
|
|
766
|
+
var placeholderEl = defaultTemplates.placeholder(this._config);
|
|
767
|
+
valueDisplayEl.replaceChildren(placeholderEl);
|
|
795
768
|
}
|
|
796
769
|
else {
|
|
797
|
-
|
|
798
|
-
if (
|
|
799
|
-
|
|
800
|
-
|
|
770
|
+
// Options are selected.
|
|
771
|
+
if (tagsEnabled) {
|
|
772
|
+
// Tags are enabled AND options are selected: tags module has rendered them.
|
|
773
|
+
// Clear valueDisplayEl as tags are the primary display.
|
|
774
|
+
valueDisplayEl.innerHTML = '';
|
|
801
775
|
}
|
|
802
776
|
else {
|
|
803
|
-
//
|
|
804
|
-
content =
|
|
777
|
+
// Tags are not enabled AND options are selected: render normal text display.
|
|
778
|
+
var content = '';
|
|
779
|
+
if (this._config.displayTemplate) {
|
|
780
|
+
content = this.renderDisplayTemplateForSelected(this.getSelectedOptions());
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
content = this.getSelectedOptionsText();
|
|
784
|
+
}
|
|
785
|
+
valueDisplayEl.innerHTML = content;
|
|
805
786
|
}
|
|
806
|
-
this._valueDisplayElement.innerHTML = content;
|
|
807
787
|
}
|
|
808
788
|
}
|
|
809
789
|
};
|
|
790
|
+
/**
|
|
791
|
+
* Check if an option was originally disabled in the HTML
|
|
792
|
+
*/
|
|
793
|
+
KTSelect.prototype._isOptionOriginallyDisabled = function (value) {
|
|
794
|
+
var originalOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
|
|
795
|
+
return originalOption ? originalOption.disabled : false;
|
|
796
|
+
};
|
|
810
797
|
/**
|
|
811
798
|
* Update CSS classes for selected options
|
|
812
799
|
*/
|
|
813
800
|
KTSelect.prototype._updateSelectedOptionClass = function () {
|
|
801
|
+
var _this = this;
|
|
814
802
|
var allOptions = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
|
|
815
803
|
var selectedValues = this._state.getSelectedOptions();
|
|
816
804
|
var maxReached = typeof this._config.maxSelections === 'number' &&
|
|
@@ -822,9 +810,11 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
822
810
|
if (!optionValue)
|
|
823
811
|
return;
|
|
824
812
|
var isSelected = selectedValues.includes(optionValue);
|
|
813
|
+
var isOriginallyDisabled = _this._isOptionOriginallyDisabled(optionValue);
|
|
825
814
|
if (isSelected) {
|
|
826
815
|
option.classList.add('selected');
|
|
827
816
|
option.setAttribute('aria-selected', 'true');
|
|
817
|
+
// Selected options should not be visually hidden or disabled by maxSelections logic
|
|
828
818
|
option.classList.remove('hidden');
|
|
829
819
|
option.classList.remove('disabled');
|
|
830
820
|
option.removeAttribute('aria-disabled');
|
|
@@ -832,7 +822,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
832
822
|
else {
|
|
833
823
|
option.classList.remove('selected');
|
|
834
824
|
option.setAttribute('aria-selected', 'false');
|
|
835
|
-
if
|
|
825
|
+
// An option should be disabled if it was originally disabled OR if maxSelections is reached
|
|
826
|
+
if (isOriginallyDisabled || maxReached) {
|
|
836
827
|
option.classList.add('disabled');
|
|
837
828
|
option.setAttribute('aria-disabled', 'true');
|
|
838
829
|
}
|
|
@@ -892,17 +883,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
892
883
|
* EVENT HANDLERS
|
|
893
884
|
* ========================================================================
|
|
894
885
|
*/
|
|
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
886
|
/**
|
|
907
887
|
* Handle click within the dropdown
|
|
908
888
|
*/
|
|
@@ -943,6 +923,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
943
923
|
}
|
|
944
924
|
if (this._config.debug)
|
|
945
925
|
console.log('Option clicked:', optionValue);
|
|
926
|
+
// If in single-select mode and the clicked option is already selected, just close the dropdown.
|
|
927
|
+
if (!this._config.multiple && this._state.isSelected(optionValue)) {
|
|
928
|
+
if (this._config.debug)
|
|
929
|
+
console.log('Single select mode: clicked already selected option. Closing dropdown.');
|
|
930
|
+
this.closeDropdown();
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
946
933
|
// Use toggleSelection instead of _selectOption to prevent re-rendering
|
|
947
934
|
this.toggleSelection(optionValue);
|
|
948
935
|
};
|
|
@@ -1006,7 +993,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1006
993
|
* Get value display element
|
|
1007
994
|
*/
|
|
1008
995
|
KTSelect.prototype.getValueDisplayElement = function () {
|
|
1009
|
-
return this.
|
|
996
|
+
return this._displayElement;
|
|
997
|
+
};
|
|
998
|
+
/**
|
|
999
|
+
* Get wrapper element
|
|
1000
|
+
*/
|
|
1001
|
+
KTSelect.prototype.getWrapperElement = function () {
|
|
1002
|
+
return this._wrapperElement;
|
|
1010
1003
|
};
|
|
1011
1004
|
/**
|
|
1012
1005
|
* Show all options in the dropdown
|
|
@@ -1016,6 +1009,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1016
1009
|
var options = Array.from(this._wrapperElement.querySelectorAll("[data-kt-select-option]"));
|
|
1017
1010
|
// Show all options by removing the hidden class and any inline styles
|
|
1018
1011
|
options.forEach(function (option) {
|
|
1012
|
+
var _a;
|
|
1019
1013
|
// Remove hidden class
|
|
1020
1014
|
option.classList.remove('hidden');
|
|
1021
1015
|
// Clean up any existing inline styles for backward compatibility
|
|
@@ -1029,7 +1023,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1029
1023
|
}
|
|
1030
1024
|
else {
|
|
1031
1025
|
// Otherwise, remove just the display property
|
|
1032
|
-
option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
|
|
1026
|
+
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
1027
|
}
|
|
1034
1028
|
}
|
|
1035
1029
|
}
|
|
@@ -1039,7 +1033,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1039
1033
|
this._searchInputElement.value = '';
|
|
1040
1034
|
// If we have a search module, clear any search filtering
|
|
1041
1035
|
if (this._searchModule) {
|
|
1042
|
-
this._searchModule.
|
|
1036
|
+
this._searchModule.clearSearch();
|
|
1043
1037
|
}
|
|
1044
1038
|
}
|
|
1045
1039
|
};
|
|
@@ -1068,7 +1062,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1068
1062
|
// Get current selection state
|
|
1069
1063
|
var isSelected = this._state.isSelected(value);
|
|
1070
1064
|
if (this._config.debug)
|
|
1071
|
-
console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple
|
|
1065
|
+
console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple));
|
|
1072
1066
|
// If already selected in single select mode, do nothing (can't deselect in single select)
|
|
1073
1067
|
if (isSelected && !this._config.multiple) {
|
|
1074
1068
|
if (this._config.debug)
|
|
@@ -1077,9 +1071,9 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1077
1071
|
}
|
|
1078
1072
|
if (this._config.debug)
|
|
1079
1073
|
console.log("Toggling selection for option: ".concat(value, ", currently selected: ").concat(isSelected));
|
|
1080
|
-
// Ensure any search
|
|
1074
|
+
// Ensure any search input is cleared when selection changes
|
|
1081
1075
|
if (this._searchModule) {
|
|
1082
|
-
this._searchModule.
|
|
1076
|
+
this._searchModule.clearSearch();
|
|
1083
1077
|
}
|
|
1084
1078
|
// Toggle the selection in the state
|
|
1085
1079
|
this._state.toggleSelectedOptions(value);
|
|
@@ -1102,15 +1096,14 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1102
1096
|
// Update option classes without re-rendering the dropdown content
|
|
1103
1097
|
this._updateSelectedOptionClass();
|
|
1104
1098
|
// For single select mode, always close the dropdown after selection
|
|
1105
|
-
// For multiple select mode, only close if closeOnSelect is true
|
|
1106
1099
|
if (!this._config.multiple) {
|
|
1107
1100
|
if (this._config.debug)
|
|
1108
1101
|
console.log('About to call closeDropdown() for single select mode - always close after selection');
|
|
1109
1102
|
this.closeDropdown();
|
|
1110
1103
|
}
|
|
1111
|
-
else
|
|
1104
|
+
else {
|
|
1112
1105
|
if (this._config.debug)
|
|
1113
|
-
console.log('About to call closeDropdown() for multiple select
|
|
1106
|
+
console.log('About to call closeDropdown() for multiple select');
|
|
1114
1107
|
this.closeDropdown();
|
|
1115
1108
|
}
|
|
1116
1109
|
// Dispatch custom change event with additional data
|
|
@@ -1210,9 +1203,9 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1210
1203
|
.then(function () {
|
|
1211
1204
|
// Update options in the dropdown
|
|
1212
1205
|
_this._updateSearchResults(items);
|
|
1213
|
-
// Refresh the search module
|
|
1214
|
-
if (_this._searchModule
|
|
1215
|
-
_this._searchModule.
|
|
1206
|
+
// Refresh the search module to update focus and cache
|
|
1207
|
+
if (_this._searchModule) {
|
|
1208
|
+
_this._searchModule.refreshAfterSearch();
|
|
1216
1209
|
}
|
|
1217
1210
|
})
|
|
1218
1211
|
.catch(function (error) {
|
|
@@ -1309,19 +1302,47 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1309
1302
|
* Centralized keyboard event handler for all select modes
|
|
1310
1303
|
*/
|
|
1311
1304
|
KTSelect.prototype._handleKeyboardEvent = function (event) {
|
|
1305
|
+
// If the event target is the search input and the event was already handled (defaultPrevented),
|
|
1306
|
+
// then return early to avoid duplicate processing by this broader handler.
|
|
1307
|
+
if (event.target === this._searchInputElement && event.defaultPrevented) {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1312
1310
|
var isOpen = this._dropdownIsOpen;
|
|
1313
1311
|
var config = this._config;
|
|
1314
1312
|
var focusManager = this._focusManager;
|
|
1315
1313
|
var buffer = this._typeToSearchBuffer;
|
|
1316
|
-
//
|
|
1314
|
+
// If the event target is the search input, let it handle most typing keys naturally.
|
|
1315
|
+
if (event.target === this._searchInputElement) {
|
|
1316
|
+
// Allow navigation keys like ArrowDown, ArrowUp, Escape, Enter (for search/selection) to be handled by the logic below.
|
|
1317
|
+
// For other keys (characters, space, backspace, delete), let the input field process them.
|
|
1318
|
+
if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp' &&
|
|
1319
|
+
event.key !== 'Escape' && event.key !== 'Enter' && event.key !== 'Tab' &&
|
|
1320
|
+
event.key !== 'Home' && event.key !== 'End') {
|
|
1321
|
+
// If it's a character key and we are NOT type-to-searching (because search has focus)
|
|
1322
|
+
// then let the input field handle it for its own value.
|
|
1323
|
+
// The search module's 'input' event will handle filtering based on the input's value.
|
|
1324
|
+
buffer.clear(); // Clear type-to-search buffer when typing in search field
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
// For Enter specifically in search input, we might want to select the focused option or submit search.
|
|
1328
|
+
// This is handled later in the switch.
|
|
1329
|
+
}
|
|
1330
|
+
// Ignore modifier keys (except for specific combinations if added later)
|
|
1317
1331
|
if (event.altKey || event.ctrlKey || event.metaKey)
|
|
1318
1332
|
return;
|
|
1319
|
-
// Type-to-search: only for single char keys
|
|
1320
|
-
if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/)) {
|
|
1333
|
+
// Type-to-search: only for single char keys, when search input does not have focus
|
|
1334
|
+
if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/) && document.activeElement !== this._searchInputElement) {
|
|
1321
1335
|
buffer.push(event.key);
|
|
1322
1336
|
var str = buffer.getBuffer();
|
|
1323
|
-
|
|
1324
|
-
|
|
1337
|
+
if (isOpen) {
|
|
1338
|
+
focusManager.focusByString(str);
|
|
1339
|
+
}
|
|
1340
|
+
else {
|
|
1341
|
+
// If closed, type-to-search could potentially open and select.
|
|
1342
|
+
// For now, let's assume it only works when open or opens it first.
|
|
1343
|
+
// Or, we could find the matching option and set it directly without opening.
|
|
1344
|
+
}
|
|
1345
|
+
return; // Type-to-search handles the event
|
|
1325
1346
|
}
|
|
1326
1347
|
switch (event.key) {
|
|
1327
1348
|
case 'ArrowDown':
|
|
@@ -1355,18 +1376,28 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1355
1376
|
case 'Enter':
|
|
1356
1377
|
case ' ': // Space
|
|
1357
1378
|
if (isOpen) {
|
|
1358
|
-
var
|
|
1359
|
-
if (
|
|
1360
|
-
var
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
if (
|
|
1364
|
-
|
|
1365
|
-
|
|
1379
|
+
var focusedOptionEl = this._focusManager.getFocusedOption();
|
|
1380
|
+
if (focusedOptionEl) {
|
|
1381
|
+
var val = focusedOptionEl.dataset.value;
|
|
1382
|
+
// If single select, and the item is already selected, just close.
|
|
1383
|
+
if (val !== undefined && !this._config.multiple && this._state.isSelected(val)) {
|
|
1384
|
+
if (this._config.debug)
|
|
1385
|
+
console.log('Enter on already selected item in single-select mode. Closing.');
|
|
1386
|
+
this.closeDropdown();
|
|
1387
|
+
event.preventDefault();
|
|
1388
|
+
break;
|
|
1366
1389
|
}
|
|
1367
1390
|
}
|
|
1368
|
-
//
|
|
1369
|
-
|
|
1391
|
+
// Proceed with selection if not handled above
|
|
1392
|
+
this.selectFocusedOption();
|
|
1393
|
+
// Close dropdown if configured to do so (for new selections)
|
|
1394
|
+
if (!this._config.multiple) {
|
|
1395
|
+
// This will also be true for the case handled above, but closeDropdown is idempotent.
|
|
1396
|
+
// However, the break above prevents this from being reached for that specific case.
|
|
1397
|
+
this.closeDropdown();
|
|
1398
|
+
}
|
|
1399
|
+
event.preventDefault(); // Prevent form submission or other default actions
|
|
1400
|
+
break;
|
|
1370
1401
|
}
|
|
1371
1402
|
else {
|
|
1372
1403
|
this.openDropdown();
|
|
@@ -1410,6 +1441,76 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1410
1441
|
}).filter(Boolean)));
|
|
1411
1442
|
return contentArray.join(displaySeparator);
|
|
1412
1443
|
};
|
|
1444
|
+
KTSelect.prototype.getDisplayElement = function () {
|
|
1445
|
+
return this._displayElement;
|
|
1446
|
+
};
|
|
1447
|
+
KTSelect.prototype._observeNativeSelect = function () {
|
|
1448
|
+
var _this = this;
|
|
1449
|
+
if (this._mutationObserver)
|
|
1450
|
+
return; // Prevent double observers
|
|
1451
|
+
this._mutationObserver = new MutationObserver(function (mutations) {
|
|
1452
|
+
var needsRebuild = false;
|
|
1453
|
+
var needsSelectionSync = false;
|
|
1454
|
+
for (var _i = 0, mutations_1 = mutations; _i < mutations_1.length; _i++) {
|
|
1455
|
+
var mutation = mutations_1[_i];
|
|
1456
|
+
if (mutation.type === 'childList') {
|
|
1457
|
+
// Option(s) added or removed
|
|
1458
|
+
needsRebuild = true;
|
|
1459
|
+
}
|
|
1460
|
+
else if (mutation.type === 'attributes' && mutation.target instanceof HTMLOptionElement) {
|
|
1461
|
+
if (mutation.attributeName === 'selected') {
|
|
1462
|
+
needsSelectionSync = true;
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
if (needsRebuild) {
|
|
1467
|
+
// Rebuild the custom dropdown options
|
|
1468
|
+
_this._rebuildOptionsFromNative();
|
|
1469
|
+
}
|
|
1470
|
+
if (needsSelectionSync) {
|
|
1471
|
+
_this._syncSelectionFromNative();
|
|
1472
|
+
}
|
|
1473
|
+
});
|
|
1474
|
+
this._mutationObserver.observe(this._element, {
|
|
1475
|
+
childList: true,
|
|
1476
|
+
attributes: true,
|
|
1477
|
+
subtree: true,
|
|
1478
|
+
attributeFilter: ['selected'],
|
|
1479
|
+
});
|
|
1480
|
+
};
|
|
1481
|
+
KTSelect.prototype._rebuildOptionsFromNative = function () {
|
|
1482
|
+
var _this = this;
|
|
1483
|
+
// Remove and rebuild the custom dropdown options from the native select
|
|
1484
|
+
if (this._dropdownContentElement) {
|
|
1485
|
+
var optionsContainer_1 = this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
1486
|
+
if (optionsContainer_1) {
|
|
1487
|
+
optionsContainer_1.innerHTML = '';
|
|
1488
|
+
var options = Array.from(this._element.querySelectorAll('option'));
|
|
1489
|
+
options.forEach(function (optionElement) {
|
|
1490
|
+
if (optionElement.value === '' &&
|
|
1491
|
+
optionElement.textContent.trim() === '') {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
var selectOption = new KTSelectOption(optionElement, _this._config);
|
|
1495
|
+
var renderedOption = selectOption.render();
|
|
1496
|
+
optionsContainer_1.appendChild(renderedOption);
|
|
1497
|
+
});
|
|
1498
|
+
// Update internal references
|
|
1499
|
+
this._options = this._wrapperElement.querySelectorAll('[data-kt-select-option]');
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
// Sync selection after rebuilding
|
|
1503
|
+
this._syncSelectionFromNative();
|
|
1504
|
+
this.updateSelectedOptionDisplay();
|
|
1505
|
+
this._updateSelectedOptionClass();
|
|
1506
|
+
};
|
|
1507
|
+
KTSelect.prototype._syncSelectionFromNative = function () {
|
|
1508
|
+
// Sync internal state from the native select's selected options
|
|
1509
|
+
var selected = Array.from(this._element.querySelectorAll('option:checked')).map(function (opt) { return opt.value; });
|
|
1510
|
+
this._state.setSelectedOptions(this._config.multiple ? selected : selected[0] || '');
|
|
1511
|
+
this.updateSelectedOptionDisplay();
|
|
1512
|
+
this._updateSelectedOptionClass();
|
|
1513
|
+
};
|
|
1413
1514
|
/**
|
|
1414
1515
|
* ========================================================================
|
|
1415
1516
|
* STATIC METHODS
|