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