@keenthemes/ktui 1.0.11 → 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.
- package/dist/ktui.js +1687 -1517
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +5822 -0
- package/examples/select/avatar.html +47 -0
- package/examples/select/basic-usage.html +39 -0
- package/examples/select/combobox-icons_.html +59 -0
- package/examples/select/combobox_.html +46 -0
- package/examples/select/country.html +43 -0
- package/examples/select/description.html +53 -0
- package/examples/select/disable-option.html +37 -0
- package/examples/select/disable-select.html +35 -0
- package/examples/select/icon-multiple.html +50 -0
- package/examples/select/icon.html +48 -0
- package/examples/select/max-selection.html +38 -0
- package/examples/select/modal.html +72 -0
- package/examples/select/multiple.html +40 -0
- package/examples/select/placeholder.html +40 -0
- package/examples/select/remote-data_.html +32 -0
- package/examples/select/search.html +57 -0
- package/examples/select/sizes.html +94 -0
- package/examples/select/tags-icons_.html +58 -0
- package/examples/select/tags-selected_.html +59 -0
- package/examples/select/tags_.html +58 -0
- package/examples/select/template-customization.html +62 -0
- package/examples/toast/example.html +427 -0
- package/lib/cjs/components/datatable/datatable.js +23 -7
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/select/combobox.js +94 -141
- package/lib/cjs/components/select/combobox.js.map +1 -1
- package/lib/cjs/components/select/config.js +4 -18
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js +35 -138
- package/lib/cjs/components/select/dropdown.js.map +1 -1
- package/lib/cjs/components/select/index.js +2 -1
- package/lib/cjs/components/select/index.js.map +1 -1
- package/lib/cjs/components/select/option.js +56 -6
- package/lib/cjs/components/select/option.js.map +1 -1
- package/lib/cjs/components/select/remote.js +1 -37
- package/lib/cjs/components/select/remote.js.map +1 -1
- package/lib/cjs/components/select/search.js +147 -128
- package/lib/cjs/components/select/search.js.map +1 -1
- package/lib/cjs/components/select/select.js +332 -391
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/tags.js +38 -56
- package/lib/cjs/components/select/tags.js.map +1 -1
- package/lib/cjs/components/select/templates.js +168 -200
- package/lib/cjs/components/select/templates.js.map +1 -1
- package/lib/cjs/components/select/types.js +0 -12
- package/lib/cjs/components/select/types.js.map +1 -1
- package/lib/cjs/components/select/utils.js +187 -339
- package/lib/cjs/components/select/utils.js.map +1 -1
- package/lib/cjs/components/toast/index.js +10 -0
- package/lib/cjs/components/toast/index.js.map +1 -0
- package/lib/cjs/components/toast/toast.js +543 -0
- package/lib/cjs/components/toast/toast.js.map +1 -0
- package/lib/cjs/components/toast/types.js +7 -0
- package/lib/cjs/components/toast/types.js.map +1 -0
- package/lib/cjs/index.js +5 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/esm/components/datatable/datatable.js +23 -7
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/select/combobox.js +95 -142
- package/lib/esm/components/select/combobox.js.map +1 -1
- package/lib/esm/components/select/config.js +3 -17
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/dropdown.js +35 -138
- package/lib/esm/components/select/dropdown.js.map +1 -1
- package/lib/esm/components/select/index.js +1 -1
- package/lib/esm/components/select/index.js.map +1 -1
- package/lib/esm/components/select/option.js +56 -6
- package/lib/esm/components/select/option.js.map +1 -1
- package/lib/esm/components/select/remote.js +1 -37
- package/lib/esm/components/select/remote.js.map +1 -1
- package/lib/esm/components/select/search.js +148 -129
- package/lib/esm/components/select/search.js.map +1 -1
- package/lib/esm/components/select/select.js +333 -392
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/tags.js +38 -56
- package/lib/esm/components/select/tags.js.map +1 -1
- package/lib/esm/components/select/templates.js +167 -199
- package/lib/esm/components/select/templates.js.map +1 -1
- package/lib/esm/components/select/types.js +1 -11
- package/lib/esm/components/select/types.js.map +1 -1
- package/lib/esm/components/select/utils.js +184 -336
- package/lib/esm/components/select/utils.js.map +1 -1
- package/lib/esm/components/toast/index.js +6 -0
- package/lib/esm/components/toast/index.js.map +1 -0
- package/lib/esm/components/toast/toast.js +540 -0
- package/lib/esm/components/toast/toast.js.map +1 -0
- package/lib/esm/components/toast/types.js +6 -0
- package/lib/esm/components/toast/types.js.map +1 -0
- package/lib/esm/index.js +3 -0
- package/lib/esm/index.js.map +1 -1
- package/package.json +14 -9
- package/src/components/alert/alert.css +15 -2
- package/src/components/datatable/datatable.ts +25 -17
- package/src/components/input/input.css +3 -1
- package/src/components/link/link.css +2 -2
- package/src/components/scrollable/scrollable.css +9 -5
- package/src/components/select/combobox.ts +96 -192
- package/src/components/select/config.ts +35 -36
- package/src/components/select/dropdown.ts +43 -155
- package/src/components/select/index.ts +1 -1
- package/src/components/select/option.ts +50 -10
- package/src/components/select/remote.ts +2 -42
- package/src/components/select/search.ts +159 -158
- package/src/components/select/select.css +137 -18
- package/src/components/select/select.ts +354 -506
- package/src/components/select/tags.ts +37 -60
- package/src/components/select/templates.ts +254 -328
- package/src/components/select/types.ts +0 -10
- package/src/components/select/utils.ts +190 -416
- package/src/components/textarea/textarea.css +2 -1
- package/src/components/toast/index.ts +7 -0
- package/src/components/toast/toast.css +60 -0
- package/src/components/toast/toast.ts +605 -0
- package/src/components/toast/types.ts +169 -0
- package/src/index.ts +4 -0
- package/styles/main.css +3 -0
- package/styles/vars.css +138 -0
- package/styles.css +1 -0
- package/webpack.config.js +6 -1
|
@@ -52,7 +52,6 @@ var combobox_1 = require("./combobox");
|
|
|
52
52
|
var dropdown_1 = require("./dropdown");
|
|
53
53
|
var utils_1 = require("./utils");
|
|
54
54
|
var tags_1 = require("./tags");
|
|
55
|
-
var types_1 = require("./types");
|
|
56
55
|
var KTSelect = /** @class */ (function (_super) {
|
|
57
56
|
__extends(KTSelect, _super);
|
|
58
57
|
/**
|
|
@@ -69,6 +68,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
69
68
|
_this._tagsModule = null;
|
|
70
69
|
_this._dropdownModule = null;
|
|
71
70
|
_this._loadMoreIndicator = null;
|
|
71
|
+
_this._typeToSearchBuffer = new utils_1.TypeToSearchBuffer();
|
|
72
72
|
// Search debounce timeout
|
|
73
73
|
_this._searchDebounceTimeout = null;
|
|
74
74
|
// Store original options HTML for restoring after search
|
|
@@ -153,11 +153,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
153
153
|
// Keep only the empty/placeholder option and remove the rest
|
|
154
154
|
var options = Array.from(this._element.querySelectorAll('option:not([value=""])'));
|
|
155
155
|
options.forEach(function (option) { return option.remove(); });
|
|
156
|
-
// Ensure we have at least an empty option
|
|
157
|
-
if (this._element.querySelectorAll('option').length === 0) {
|
|
158
|
-
var emptyOption = templates_1.defaultTemplates.emptyOption(__assign(__assign({}, this._config), { placeholder: this._config.placeholder }));
|
|
159
|
-
this._element.appendChild(emptyOption);
|
|
160
|
-
}
|
|
161
156
|
};
|
|
162
157
|
/**
|
|
163
158
|
* Helper to show a dropdown message (error, loading, noResults)
|
|
@@ -165,19 +160,20 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
165
160
|
KTSelect.prototype._showDropdownMessage = function (type, message) {
|
|
166
161
|
if (!this._dropdownContentElement)
|
|
167
162
|
return;
|
|
168
|
-
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options
|
|
163
|
+
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
169
164
|
if (!optionsContainer)
|
|
170
165
|
return;
|
|
166
|
+
// Clear previous messages
|
|
167
|
+
optionsContainer.innerHTML = '';
|
|
171
168
|
switch (type) {
|
|
172
169
|
case 'error':
|
|
173
|
-
optionsContainer.
|
|
170
|
+
optionsContainer.appendChild(templates_1.defaultTemplates.error(__assign(__assign({}, this._config), { errorMessage: message })));
|
|
174
171
|
break;
|
|
175
172
|
case 'loading':
|
|
176
|
-
optionsContainer.
|
|
173
|
+
optionsContainer.appendChild(templates_1.defaultTemplates.loading(this._config, message || 'Loading...'));
|
|
177
174
|
break;
|
|
178
|
-
case '
|
|
179
|
-
optionsContainer.
|
|
180
|
-
optionsContainer.appendChild(templates_1.defaultTemplates.noResults(this._config));
|
|
175
|
+
case 'empty':
|
|
176
|
+
optionsContainer.appendChild(templates_1.defaultTemplates.empty(this._config));
|
|
181
177
|
break;
|
|
182
178
|
}
|
|
183
179
|
};
|
|
@@ -196,14 +192,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
196
192
|
* @param message Error message
|
|
197
193
|
*/
|
|
198
194
|
KTSelect.prototype._renderErrorState = function (message) {
|
|
199
|
-
// Create error option if the select is empty
|
|
200
|
-
if (this._element.querySelectorAll('option').length <= 1) {
|
|
201
|
-
var loadingOptions = this._element.querySelectorAll('option[disabled]:not([value])');
|
|
202
|
-
loadingOptions.forEach(function (option) { return option.remove(); });
|
|
203
|
-
// Use template function for error option instead of hardcoded element
|
|
204
|
-
var errorOption = templates_1.defaultTemplates.errorOption(__assign(__assign({}, this._config), { errorMessage: message }));
|
|
205
|
-
this._element.appendChild(errorOption);
|
|
206
|
-
}
|
|
207
195
|
// If dropdown is already created, show error message there
|
|
208
196
|
this._showDropdownMessage('error', message);
|
|
209
197
|
if (!this._wrapperElement) {
|
|
@@ -226,7 +214,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
226
214
|
// Create load more button using template
|
|
227
215
|
this._loadMoreIndicator = templates_1.defaultTemplates.loadMore(this._config);
|
|
228
216
|
// Add to dropdown
|
|
229
|
-
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options
|
|
217
|
+
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
230
218
|
if (optionsContainer) {
|
|
231
219
|
optionsContainer.appendChild(this._loadMoreIndicator);
|
|
232
220
|
}
|
|
@@ -296,42 +284,26 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
296
284
|
* @param newItems New items to add to the dropdown
|
|
297
285
|
*/
|
|
298
286
|
KTSelect.prototype._updateOptionsInDropdown = function (newItems) {
|
|
299
|
-
var _this = this;
|
|
300
287
|
if (!this._dropdownContentElement || !newItems.length)
|
|
301
288
|
return;
|
|
302
|
-
var optionsContainer = this._dropdownContentElement.querySelector(
|
|
289
|
+
var optionsContainer = this._dropdownContentElement.querySelector("[data-kt-select-options]");
|
|
303
290
|
if (!optionsContainer)
|
|
304
291
|
return;
|
|
305
292
|
// Get the load more button
|
|
306
|
-
var loadMoreButton = optionsContainer.querySelector(
|
|
293
|
+
var loadMoreButton = optionsContainer.querySelector("[data-kt-select-load-more]");
|
|
307
294
|
// Process each new item
|
|
308
295
|
newItems.forEach(function (item) {
|
|
309
296
|
// Create option for the original select
|
|
310
|
-
var selectOption =
|
|
297
|
+
var selectOption = document.createElement('option');
|
|
311
298
|
selectOption.value = item.id || '';
|
|
312
|
-
// Add description and icon attributes if available and valid
|
|
313
|
-
if (item.description &&
|
|
314
|
-
item.description !== 'null' &&
|
|
315
|
-
item.description !== 'undefined') {
|
|
316
|
-
selectOption.setAttribute('data-kt-select-option-description', item.description);
|
|
317
|
-
}
|
|
318
|
-
if (item.icon && item.icon !== 'null' && item.icon !== 'undefined') {
|
|
319
|
-
selectOption.setAttribute('data-kt-select-option-icon', item.icon);
|
|
320
|
-
}
|
|
321
|
-
// Add the option to the original select element
|
|
322
|
-
_this._element.appendChild(selectOption);
|
|
323
|
-
// Create option element for the dropdown using the KTSelectOption class
|
|
324
|
-
// This ensures consistent option rendering
|
|
325
|
-
var ktOption = new option_1.KTSelectOption(selectOption, _this._config);
|
|
326
|
-
var renderedOption = ktOption.render();
|
|
327
299
|
// Add to dropdown container
|
|
328
300
|
if (loadMoreButton) {
|
|
329
301
|
// Insert before the load more button
|
|
330
|
-
optionsContainer.insertBefore(
|
|
302
|
+
optionsContainer.insertBefore(selectOption, loadMoreButton);
|
|
331
303
|
}
|
|
332
304
|
else {
|
|
333
305
|
// Append to the end
|
|
334
|
-
optionsContainer.appendChild(
|
|
306
|
+
optionsContainer.appendChild(selectOption);
|
|
335
307
|
}
|
|
336
308
|
});
|
|
337
309
|
// Update options NodeList to include the new options
|
|
@@ -353,7 +325,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
353
325
|
this._setupElementReferences();
|
|
354
326
|
this._initZIndex();
|
|
355
327
|
// Initialize options
|
|
356
|
-
this._initializeOptionsHtml();
|
|
328
|
+
// this._initializeOptionsHtml();
|
|
357
329
|
this._preSelectOptions(this._element);
|
|
358
330
|
// Apply disabled state if needed
|
|
359
331
|
this._applyInitialDisabledState();
|
|
@@ -362,17 +334,17 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
362
334
|
this._initializeSearchModule();
|
|
363
335
|
}
|
|
364
336
|
// Initialize combobox if enabled
|
|
365
|
-
if (this._config.
|
|
337
|
+
if (this._config.combobox) {
|
|
366
338
|
this._comboboxModule = new combobox_1.KTSelectCombobox(this);
|
|
367
339
|
}
|
|
368
340
|
// Initialize tags if enabled
|
|
369
|
-
if (this._config.
|
|
341
|
+
if (this._config.tags) {
|
|
370
342
|
this._tagsModule = new tags_1.KTSelectTags(this);
|
|
371
343
|
}
|
|
372
344
|
// Initialize focus manager after dropdown element is created
|
|
373
345
|
this._focusManager = new utils_1.FocusManager(this._dropdownContentElement, '[data-kt-select-option]', this._config);
|
|
374
346
|
// Initialize dropdown module after all elements are created
|
|
375
|
-
this._dropdownModule = new dropdown_1.KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config);
|
|
347
|
+
this._dropdownModule = new dropdown_1.KTSelectDropdown(this._wrapperElement, this._displayElement, this._dropdownContentElement, this._config, this);
|
|
376
348
|
// Update display and set ARIA attributes
|
|
377
349
|
this._updateDisplayAndAriaAttributes();
|
|
378
350
|
this.updateSelectedOptionDisplay();
|
|
@@ -380,34 +352,34 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
380
352
|
// Attach event listeners after all modules are initialized
|
|
381
353
|
this._attachEventListeners();
|
|
382
354
|
};
|
|
383
|
-
/**
|
|
384
|
-
* Initialize options HTML from data
|
|
385
|
-
*/
|
|
386
|
-
KTSelect.prototype._initializeOptionsHtml = function () {
|
|
387
|
-
this._generateOptionsHtml(this._element);
|
|
388
|
-
};
|
|
389
355
|
/**
|
|
390
356
|
* Creates the HTML structure for the select component
|
|
391
357
|
*/
|
|
392
358
|
KTSelect.prototype._createHtmlStructure = function () {
|
|
359
|
+
var _a;
|
|
393
360
|
var _this = this;
|
|
394
361
|
var options = Array.from(this._element.querySelectorAll('option'));
|
|
395
362
|
// Create wrapper and display elements
|
|
396
|
-
var wrapperElement = templates_1.defaultTemplates.
|
|
363
|
+
var wrapperElement = templates_1.defaultTemplates.wrapper(this._config);
|
|
397
364
|
var displayElement = templates_1.defaultTemplates.display(this._config);
|
|
398
365
|
// Add the display element to the wrapper
|
|
399
366
|
wrapperElement.appendChild(displayElement);
|
|
367
|
+
// Move classes from original select to display element
|
|
368
|
+
if (this._element.classList.length > 0) {
|
|
369
|
+
(_a = displayElement.classList).add.apply(_a, Array.from(this._element.classList));
|
|
370
|
+
this._element.className = '';
|
|
371
|
+
}
|
|
400
372
|
// Create an empty dropdown first (without options) using template
|
|
401
|
-
var dropdownElement = templates_1.defaultTemplates.
|
|
373
|
+
var dropdownElement = templates_1.defaultTemplates.dropdown(__assign(__assign({}, this._config), { zindex: this._config.dropdownZindex }));
|
|
402
374
|
// Add search input if needed
|
|
403
|
-
|
|
404
|
-
var hasSearch = this._config.enableSearch && !isCombobox;
|
|
405
|
-
if (hasSearch) {
|
|
375
|
+
if (this._config.enableSearch) {
|
|
406
376
|
var searchElement = templates_1.defaultTemplates.search(this._config);
|
|
407
377
|
dropdownElement.appendChild(searchElement);
|
|
408
378
|
}
|
|
409
379
|
// Create options container using template
|
|
410
|
-
var optionsContainer = templates_1.defaultTemplates.
|
|
380
|
+
var optionsContainer = templates_1.defaultTemplates.options(this._config);
|
|
381
|
+
// Clear the options container
|
|
382
|
+
optionsContainer.innerHTML = '';
|
|
411
383
|
// Add each option directly to the container
|
|
412
384
|
options.forEach(function (optionElement) {
|
|
413
385
|
// Skip empty placeholder options (only if BOTH value AND text are empty)
|
|
@@ -438,21 +410,17 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
438
410
|
// Get display element
|
|
439
411
|
this._displayElement = this._wrapperElement.querySelector("[data-kt-select-display]");
|
|
440
412
|
// Get dropdown content element - this is critical for dropdown functionality
|
|
441
|
-
this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown
|
|
413
|
+
this._dropdownContentElement = this._wrapperElement.querySelector("[data-kt-select-dropdown]");
|
|
442
414
|
if (!this._dropdownContentElement) {
|
|
415
|
+
console.log(this._element);
|
|
443
416
|
console.error('Dropdown content element not found', this._wrapperElement);
|
|
444
417
|
}
|
|
445
418
|
// Get search input element - this is used for the search functionality
|
|
446
|
-
// First check if it's in dropdown, then check if it's in display (for combobox)
|
|
447
419
|
this._searchInputElement = this._dropdownContentElement.querySelector("[data-kt-select-search]");
|
|
448
|
-
// If not found in dropdown, check if it's the display element itself
|
|
449
|
-
if (!this._searchInputElement
|
|
450
|
-
this._config.mode === types_1.SelectMode.COMBOBOX) {
|
|
420
|
+
// If not found in dropdown, check if it's the display element itself
|
|
421
|
+
if (!this._searchInputElement) {
|
|
451
422
|
this._searchInputElement = this._displayElement;
|
|
452
423
|
}
|
|
453
|
-
if (this._config.debug)
|
|
454
|
-
console.log('Search input found:', this._searchInputElement ? 'Yes' : 'No', 'Mode:', this._config.mode, 'EnableSearch:', this._config.enableSearch);
|
|
455
|
-
this._valueDisplayElement = this._wrapperElement.querySelector("[data-kt-select-value]");
|
|
456
424
|
this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
|
|
457
425
|
};
|
|
458
426
|
/**
|
|
@@ -461,17 +429,12 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
461
429
|
KTSelect.prototype._attachEventListeners = function () {
|
|
462
430
|
// Document level event listeners
|
|
463
431
|
document.addEventListener('click', this._handleDocumentClick.bind(this));
|
|
464
|
-
document.addEventListener('keydown', this._handleEscKey.bind(this));
|
|
465
432
|
// Dropdown option click events
|
|
466
433
|
this._eventManager.addListener(this._dropdownContentElement, 'click', this._handleDropdownOptionClick.bind(this));
|
|
467
|
-
//
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if (this._config.mode !== types_1.SelectMode.COMBOBOX) {
|
|
472
|
-
if (this._config.debug)
|
|
473
|
-
console.log('Attaching keyboard navigation to display element (non-combobox mode)');
|
|
474
|
-
this._eventManager.addListener(this._displayElement, 'keydown', this._handleDropdownKeyDown.bind(this));
|
|
434
|
+
// Attach centralized keyboard handler to the wrapper element.
|
|
435
|
+
// Events from focusable children like _displayElement or _searchInputElement (if present) will bubble up.
|
|
436
|
+
if (this._wrapperElement) {
|
|
437
|
+
this._wrapperElement.addEventListener('keydown', this._handleKeyboardEvent.bind(this));
|
|
475
438
|
}
|
|
476
439
|
};
|
|
477
440
|
/**
|
|
@@ -541,52 +504,12 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
541
504
|
label =
|
|
542
505
|
extractedLabel !== null ? String(extractedLabel) : 'Unnamed option';
|
|
543
506
|
}
|
|
544
|
-
// Get description - skip if null, undefined, or "null" string
|
|
545
|
-
var description = null;
|
|
546
|
-
if (item.description !== undefined &&
|
|
547
|
-
item.description !== null &&
|
|
548
|
-
String(item.description) !== 'null' &&
|
|
549
|
-
String(item.description) !== 'undefined') {
|
|
550
|
-
description = String(item.description);
|
|
551
|
-
}
|
|
552
|
-
else if (_this._config.dataFieldDescription) {
|
|
553
|
-
var extractedDesc = _this._getValueByKey(item, _this._config.dataFieldDescription);
|
|
554
|
-
if (extractedDesc !== null &&
|
|
555
|
-
extractedDesc !== undefined &&
|
|
556
|
-
String(extractedDesc) !== 'null' &&
|
|
557
|
-
String(extractedDesc) !== 'undefined') {
|
|
558
|
-
description = String(extractedDesc);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
// Get icon - skip if null, undefined, or "null" string
|
|
562
|
-
var icon = null;
|
|
563
|
-
if (item.icon !== undefined &&
|
|
564
|
-
item.icon !== null &&
|
|
565
|
-
String(item.icon) !== 'null' &&
|
|
566
|
-
String(item.icon) !== 'undefined') {
|
|
567
|
-
icon = String(item.icon);
|
|
568
|
-
}
|
|
569
|
-
else if (_this._config.dataFieldIcon) {
|
|
570
|
-
var extractedIcon = _this._getValueByKey(item, _this._config.dataFieldIcon);
|
|
571
|
-
if (extractedIcon !== null &&
|
|
572
|
-
extractedIcon !== undefined &&
|
|
573
|
-
String(extractedIcon) !== 'null' &&
|
|
574
|
-
String(extractedIcon) !== 'undefined') {
|
|
575
|
-
icon = String(extractedIcon);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
507
|
// Log the extracted values for debugging
|
|
579
508
|
if (_this._config.debug)
|
|
580
|
-
console.log("Option: value=".concat(value, ", label=").concat(label
|
|
509
|
+
console.log("Option: value=".concat(value, ", label=").concat(label));
|
|
581
510
|
// Set option attributes
|
|
582
511
|
optionElement.value = value;
|
|
583
512
|
optionElement.textContent = label || 'Unnamed option';
|
|
584
|
-
if (description) {
|
|
585
|
-
optionElement.setAttribute('data-kt-select-option-description', description);
|
|
586
|
-
}
|
|
587
|
-
if (icon) {
|
|
588
|
-
optionElement.setAttribute('data-kt-select-option-icon', icon);
|
|
589
|
-
}
|
|
590
513
|
if (item.selected) {
|
|
591
514
|
optionElement.setAttribute('selected', 'selected');
|
|
592
515
|
}
|
|
@@ -654,31 +577,15 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
654
577
|
* DROPDOWN MANAGEMENT
|
|
655
578
|
* ========================================================================
|
|
656
579
|
*/
|
|
657
|
-
/**
|
|
658
|
-
* Toggle dropdown visibility
|
|
659
|
-
*/
|
|
660
|
-
KTSelect.prototype.toggleDropdown = function () {
|
|
661
|
-
if (this._config.debug)
|
|
662
|
-
console.log('toggleDropdown called');
|
|
663
|
-
if (this._dropdownModule) {
|
|
664
|
-
// Always use the dropdown module's state to determine whether to open or close
|
|
665
|
-
if (this._dropdownModule.isOpen()) {
|
|
666
|
-
if (this._config.debug)
|
|
667
|
-
console.log('Dropdown is open, closing...');
|
|
668
|
-
this.closeDropdown();
|
|
669
|
-
}
|
|
670
|
-
else {
|
|
671
|
-
if (this._config.debug)
|
|
672
|
-
console.log('Dropdown is closed, opening...');
|
|
673
|
-
this.openDropdown();
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
};
|
|
677
580
|
/**
|
|
678
581
|
* Open the dropdown
|
|
679
582
|
*/
|
|
680
583
|
KTSelect.prototype.openDropdown = function () {
|
|
681
|
-
|
|
584
|
+
if (this._config.disabled) {
|
|
585
|
+
if (this._config.debug)
|
|
586
|
+
console.log('openDropdown: select is disabled, not opening');
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
682
589
|
if (this._config.debug)
|
|
683
590
|
console.log('openDropdown called, dropdownModule exists:', !!this._dropdownModule);
|
|
684
591
|
if (!this._dropdownModule) {
|
|
@@ -701,14 +608,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
701
608
|
// Dispatch custom event
|
|
702
609
|
this._dispatchEvent('show');
|
|
703
610
|
this._fireEvent('show');
|
|
704
|
-
// Focus search input if configured and exists
|
|
705
|
-
if (this._config.enableSearch &&
|
|
706
|
-
this._config.searchAutofocus &&
|
|
707
|
-
this._searchInputElement) {
|
|
708
|
-
setTimeout(function () {
|
|
709
|
-
_this._searchInputElement.focus();
|
|
710
|
-
}, 50);
|
|
711
|
-
}
|
|
712
611
|
// Update ARIA states
|
|
713
612
|
this._setAriaAttributes();
|
|
714
613
|
// Focus the first selected option or first option if nothing selected
|
|
@@ -729,14 +628,14 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
729
628
|
// Always close by delegating to the dropdown module, which is the source of truth
|
|
730
629
|
if (this._config.debug)
|
|
731
630
|
console.log('Closing dropdown via dropdownModule...');
|
|
732
|
-
// Clear search input
|
|
631
|
+
// Clear search input if the dropdown is closing
|
|
733
632
|
if (this._searchModule && this._searchInputElement) {
|
|
734
633
|
// Clear search input if configured to do so
|
|
735
634
|
if (this._config.clearSearchOnClose) {
|
|
736
635
|
this._searchInputElement.value = '';
|
|
737
636
|
}
|
|
738
|
-
//
|
|
739
|
-
this._searchModule.
|
|
637
|
+
// Clear search input when dropdown closes
|
|
638
|
+
this._searchModule.clearSearch();
|
|
740
639
|
}
|
|
741
640
|
// Set our internal flag to match what we're doing
|
|
742
641
|
this._dropdownIsOpen = false;
|
|
@@ -770,10 +669,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
770
669
|
var selectedOptions = this.getSelectedOptions();
|
|
771
670
|
if (selectedOptions.length === 0)
|
|
772
671
|
return;
|
|
773
|
-
//
|
|
774
|
-
var
|
|
775
|
-
|
|
776
|
-
|
|
672
|
+
// Iterate through selected options and focus the first one that is visible
|
|
673
|
+
for (var _i = 0, selectedOptions_1 = selectedOptions; _i < selectedOptions_1.length; _i++) {
|
|
674
|
+
var value = selectedOptions_1[_i];
|
|
675
|
+
if (this._focusManager && this._focusManager.focusOptionByValue(value)) {
|
|
676
|
+
break; // Stop after focusing the first found selected and visible option
|
|
677
|
+
}
|
|
678
|
+
}
|
|
777
679
|
};
|
|
778
680
|
/**
|
|
779
681
|
* ========================================================================
|
|
@@ -784,6 +686,12 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
784
686
|
* Select an option by value
|
|
785
687
|
*/
|
|
786
688
|
KTSelect.prototype._selectOption = function (value) {
|
|
689
|
+
// Prevent selection if the option is disabled (in dropdown or original select)
|
|
690
|
+
if (this._isOptionDisabled(value)) {
|
|
691
|
+
if (this._config.debug)
|
|
692
|
+
console.log('_selectOption: Option is disabled, ignoring selection');
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
787
695
|
// Get current selection state
|
|
788
696
|
var isSelected = this._state.isSelected(value);
|
|
789
697
|
// Toggle selection in state
|
|
@@ -829,109 +737,91 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
829
737
|
* Update selected option display value
|
|
830
738
|
*/
|
|
831
739
|
KTSelect.prototype.updateSelectedOptionDisplay = function () {
|
|
832
|
-
var _this = this;
|
|
833
740
|
var selectedOptions = this.getSelectedOptions();
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
741
|
+
var tagsEnabled = this._config.tags && this._tagsModule;
|
|
742
|
+
var valueDisplayEl = this.getValueDisplayElement();
|
|
743
|
+
if (tagsEnabled) {
|
|
744
|
+
// Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
|
|
745
|
+
this._tagsModule.updateTagsDisplay(selectedOptions);
|
|
746
|
+
}
|
|
747
|
+
// Guard against valueDisplayEl being null due to template modifications
|
|
748
|
+
if (!valueDisplayEl) {
|
|
749
|
+
if (this._config.debug) {
|
|
750
|
+
console.warn('KTSelect: Value display element is null. Cannot update display or placeholder. Check template for [data-kt-select-value].');
|
|
751
|
+
}
|
|
752
|
+
return; // Nothing to display on if the element is missing
|
|
837
753
|
}
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
754
|
+
// 1. Custom render function takes highest precedence
|
|
755
|
+
if (typeof this._config.renderSelected === 'function') {
|
|
756
|
+
valueDisplayEl.innerHTML = this._config.renderSelected(selectedOptions);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
// 2. Custom displayTemplate string
|
|
760
|
+
// Check if a custom display template string is provided directly in config or via config.templates
|
|
761
|
+
var customDisplayTemplateString = this._config.displayTemplate || (this._config.templates && this._config.templates.display);
|
|
762
|
+
if (customDisplayTemplateString) {
|
|
763
|
+
// If tags are enabled and items are selected, the tags module handles display, so clear the main display area.
|
|
764
|
+
if (tagsEnabled && selectedOptions.length > 0) {
|
|
765
|
+
valueDisplayEl.innerHTML = '';
|
|
843
766
|
}
|
|
844
|
-
else
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
this._updateValueDisplay(displayText);
|
|
861
|
-
}
|
|
767
|
+
else {
|
|
768
|
+
// Otherwise, render the custom display template.
|
|
769
|
+
// If no options are selected, renderDisplayTemplateForSelected should handle showing a placeholder if the template supports it,
|
|
770
|
+
// or we might need a separate placeholder rendering for custom templates if they don't handle empty selection.
|
|
771
|
+
// For now, assume renderDisplayTemplateForSelected handles it or shows selected text.
|
|
772
|
+
valueDisplayEl.innerHTML = this.renderDisplayTemplateForSelected(selectedOptions);
|
|
773
|
+
}
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
// 3. Default template behavior (no custom function or string template)
|
|
777
|
+
var textContainer = valueDisplayEl.querySelector('[data-kt-text-container="true"]');
|
|
778
|
+
if (tagsEnabled && selectedOptions.length > 0) {
|
|
779
|
+
// Tags are active and have content, clear the text container if it exists,
|
|
780
|
+
// or the whole display if it doesn't (though it should with default template).
|
|
781
|
+
if (textContainer) {
|
|
782
|
+
textContainer.innerHTML = '';
|
|
862
783
|
}
|
|
863
784
|
else {
|
|
864
|
-
|
|
865
|
-
if (selectedOption) {
|
|
866
|
-
var selectedText = this._getOptionInnerHtml(selectedOption);
|
|
867
|
-
this._updateValueDisplay(selectedText);
|
|
868
|
-
// Update combobox input value if in combobox mode
|
|
869
|
-
if (this._config.mode === types_1.SelectMode.COMBOBOX &&
|
|
870
|
-
this._comboboxModule) {
|
|
871
|
-
this._comboboxModule.updateSelectedValue(selectedText);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
else {
|
|
875
|
-
this._updateValueDisplay(this._config.placeholder);
|
|
876
|
-
}
|
|
785
|
+
valueDisplayEl.innerHTML = ''; // Fallback: clear entire display area
|
|
877
786
|
}
|
|
878
787
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
this._valueDisplayElement.value = value;
|
|
788
|
+
else if (selectedOptions.length === 0) {
|
|
789
|
+
// No options selected: display placeholder text in the text container.
|
|
790
|
+
var placeholderTemplate = templates_1.defaultTemplates.placeholder(this._config);
|
|
791
|
+
var placeholderText = placeholderTemplate.textContent || ''; // Get text from placeholder element
|
|
792
|
+
if (textContainer) {
|
|
793
|
+
textContainer.innerHTML = placeholderText;
|
|
794
|
+
}
|
|
795
|
+
else {
|
|
796
|
+
// Fallback: If no text container, replace children of valueDisplayEl with the placeholder element itself.
|
|
797
|
+
// This ensures the placeholder (which might have its own structure/classes) is displayed.
|
|
798
|
+
valueDisplayEl.replaceChildren(placeholderTemplate);
|
|
891
799
|
}
|
|
892
800
|
}
|
|
893
801
|
else {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
var selectId = this.getElement().id;
|
|
903
|
-
if (selectId) {
|
|
904
|
-
var debugElement = document.getElementById("".concat(selectId, "-value"));
|
|
905
|
-
if (debugElement) {
|
|
906
|
-
var selectedOptions = this.getSelectedOptions();
|
|
907
|
-
// Format display based on selection mode
|
|
908
|
-
if (this._config.multiple) {
|
|
909
|
-
// For multiple selection, show comma-separated list
|
|
910
|
-
debugElement.textContent =
|
|
911
|
-
selectedOptions.length > 0 ? selectedOptions.join(', ') : 'None';
|
|
912
|
-
}
|
|
913
|
-
else {
|
|
914
|
-
// For single selection, show just the one value
|
|
915
|
-
debugElement.textContent =
|
|
916
|
-
selectedOptions.length > 0 ? selectedOptions[0] : 'None';
|
|
917
|
-
}
|
|
802
|
+
// Options are selected, and tags are not enabled (or no selected options for tags):
|
|
803
|
+
// Render normal selected text in the text container.
|
|
804
|
+
var content = this.getSelectedOptionsText();
|
|
805
|
+
if (textContainer) {
|
|
806
|
+
textContainer.innerHTML = content;
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
valueDisplayEl.innerHTML = content; // Fallback: set content on whole display area
|
|
918
810
|
}
|
|
919
811
|
}
|
|
920
812
|
};
|
|
921
813
|
/**
|
|
922
|
-
*
|
|
814
|
+
* Check if an option was originally disabled in the HTML
|
|
923
815
|
*/
|
|
924
|
-
KTSelect.prototype.
|
|
925
|
-
var
|
|
926
|
-
|
|
927
|
-
return option.textContent;
|
|
928
|
-
}
|
|
929
|
-
return option.innerHTML; // Get the entire HTML content of the option
|
|
816
|
+
KTSelect.prototype._isOptionOriginallyDisabled = function (value) {
|
|
817
|
+
var originalOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
|
|
818
|
+
return originalOption ? originalOption.disabled : false;
|
|
930
819
|
};
|
|
931
820
|
/**
|
|
932
821
|
* Update CSS classes for selected options
|
|
933
822
|
*/
|
|
934
823
|
KTSelect.prototype._updateSelectedOptionClass = function () {
|
|
824
|
+
var _this = this;
|
|
935
825
|
var allOptions = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
|
|
936
826
|
var selectedValues = this._state.getSelectedOptions();
|
|
937
827
|
var maxReached = typeof this._config.maxSelections === 'number' &&
|
|
@@ -943,9 +833,11 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
943
833
|
if (!optionValue)
|
|
944
834
|
return;
|
|
945
835
|
var isSelected = selectedValues.includes(optionValue);
|
|
836
|
+
var isOriginallyDisabled = _this._isOptionOriginallyDisabled(optionValue);
|
|
946
837
|
if (isSelected) {
|
|
947
838
|
option.classList.add('selected');
|
|
948
839
|
option.setAttribute('aria-selected', 'true');
|
|
840
|
+
// Selected options should not be visually hidden or disabled by maxSelections logic
|
|
949
841
|
option.classList.remove('hidden');
|
|
950
842
|
option.classList.remove('disabled');
|
|
951
843
|
option.removeAttribute('aria-disabled');
|
|
@@ -953,7 +845,8 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
953
845
|
else {
|
|
954
846
|
option.classList.remove('selected');
|
|
955
847
|
option.setAttribute('aria-selected', 'false');
|
|
956
|
-
if
|
|
848
|
+
// An option should be disabled if it was originally disabled OR if maxSelections is reached
|
|
849
|
+
if (isOriginallyDisabled || maxReached) {
|
|
957
850
|
option.classList.add('disabled');
|
|
958
851
|
option.setAttribute('aria-disabled', 'true');
|
|
959
852
|
}
|
|
@@ -972,17 +865,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
972
865
|
this._state.setSelectedOptions([]);
|
|
973
866
|
this.updateSelectedOptionDisplay();
|
|
974
867
|
this._updateSelectedOptionClass();
|
|
975
|
-
// For combobox, also clear the input value
|
|
976
|
-
if (this._config.mode === types_1.SelectMode.COMBOBOX) {
|
|
977
|
-
if (this._searchInputElement) {
|
|
978
|
-
this._searchInputElement.value = '';
|
|
979
|
-
}
|
|
980
|
-
// If combobox has a clear button, hide it
|
|
981
|
-
if (this._comboboxModule) {
|
|
982
|
-
// The combobox module will handle hiding the clear button
|
|
983
|
-
this._comboboxModule.resetInputValueToSelection();
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
868
|
// Dispatch change event
|
|
987
869
|
this._dispatchEvent('change');
|
|
988
870
|
this._fireEvent('change');
|
|
@@ -994,49 +876,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
994
876
|
var values = Array.from(options).map(function (option) { return option.value; });
|
|
995
877
|
this._state.setSelectedOptions(values);
|
|
996
878
|
};
|
|
997
|
-
/**
|
|
998
|
-
* ========================================================================
|
|
999
|
-
* KEYBOARD NAVIGATION
|
|
1000
|
-
* ========================================================================
|
|
1001
|
-
*/
|
|
1002
|
-
/**
|
|
1003
|
-
* Handle dropdown key down events for keyboard navigation
|
|
1004
|
-
* Only used for standard (non-combobox) dropdowns
|
|
1005
|
-
*/
|
|
1006
|
-
KTSelect.prototype._handleDropdownKeyDown = function (event) {
|
|
1007
|
-
// Log event for debugging
|
|
1008
|
-
if (this._config.debug)
|
|
1009
|
-
console.log('Standard dropdown keydown:', event.key);
|
|
1010
|
-
// Use the shared handler
|
|
1011
|
-
(0, utils_1.handleDropdownKeyNavigation)(event, this, {
|
|
1012
|
-
multiple: this._config.multiple,
|
|
1013
|
-
closeOnSelect: this._config.closeOnSelect,
|
|
1014
|
-
});
|
|
1015
|
-
};
|
|
1016
|
-
/**
|
|
1017
|
-
* Focus next option in dropdown
|
|
1018
|
-
*/
|
|
1019
|
-
KTSelect.prototype._focusNextOption = function () {
|
|
1020
|
-
return this._focusManager.focusNext();
|
|
1021
|
-
};
|
|
1022
|
-
/**
|
|
1023
|
-
* Focus previous option in dropdown
|
|
1024
|
-
*/
|
|
1025
|
-
KTSelect.prototype._focusPreviousOption = function () {
|
|
1026
|
-
return this._focusManager.focusPrevious();
|
|
1027
|
-
};
|
|
1028
|
-
/**
|
|
1029
|
-
* Apply hover/focus state to focused option
|
|
1030
|
-
*/
|
|
1031
|
-
KTSelect.prototype._hoverFocusedOption = function (option) {
|
|
1032
|
-
this._focusManager.applyFocus(option);
|
|
1033
|
-
};
|
|
1034
|
-
/**
|
|
1035
|
-
* Scroll option into view when navigating
|
|
1036
|
-
*/
|
|
1037
|
-
KTSelect.prototype._scrollOptionIntoView = function (option) {
|
|
1038
|
-
this._focusManager.scrollIntoView(option);
|
|
1039
|
-
};
|
|
1040
879
|
/**
|
|
1041
880
|
* Select the currently focused option
|
|
1042
881
|
*/
|
|
@@ -1060,60 +899,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1060
899
|
if (selectedValue) {
|
|
1061
900
|
this._selectOption(selectedValue);
|
|
1062
901
|
}
|
|
1063
|
-
// For combobox mode, update input value AFTER selection to ensure consistency
|
|
1064
|
-
if (this._config.mode === types_1.SelectMode.COMBOBOX && this._comboboxModule) {
|
|
1065
|
-
this._comboboxModule.updateSelectedValue(selectedText);
|
|
1066
|
-
// Also directly update the input value for immediate visual feedback
|
|
1067
|
-
if (this._searchInputElement) {
|
|
1068
|
-
this._searchInputElement.value = selectedText;
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
902
|
}
|
|
1072
903
|
};
|
|
1073
|
-
/**
|
|
1074
|
-
* ========================================================================
|
|
1075
|
-
* COMBOBOX SPECIFIC METHODS
|
|
1076
|
-
* ========================================================================
|
|
1077
|
-
*/
|
|
1078
|
-
/**
|
|
1079
|
-
* Handle combobox input events
|
|
1080
|
-
*/
|
|
1081
|
-
KTSelect.prototype._handleComboboxInput = function (event) {
|
|
1082
|
-
if (this._comboboxModule) {
|
|
1083
|
-
return;
|
|
1084
|
-
}
|
|
1085
|
-
var inputElement = event.target;
|
|
1086
|
-
var query = inputElement.value.toLowerCase();
|
|
1087
|
-
// If dropdown isn't open, open it when user starts typing
|
|
1088
|
-
if (!this._dropdownIsOpen) {
|
|
1089
|
-
this.openDropdown();
|
|
1090
|
-
}
|
|
1091
|
-
// Filter options based on input
|
|
1092
|
-
this._filterOptionsForCombobox(query);
|
|
1093
|
-
};
|
|
1094
|
-
/**
|
|
1095
|
-
* Filter options for combobox based on input query
|
|
1096
|
-
* Uses the shared filterOptions function
|
|
1097
|
-
*/
|
|
1098
|
-
KTSelect.prototype._filterOptionsForCombobox = function (query) {
|
|
1099
|
-
var options = Array.from(this._dropdownContentElement.querySelectorAll('[data-kt-select-option]'));
|
|
1100
|
-
(0, utils_1.filterOptions)(options, query, this._config, this._dropdownContentElement);
|
|
1101
|
-
};
|
|
1102
904
|
/**
|
|
1103
905
|
* ========================================================================
|
|
1104
906
|
* EVENT HANDLERS
|
|
1105
907
|
* ========================================================================
|
|
1106
908
|
*/
|
|
1107
|
-
/**
|
|
1108
|
-
* Handle display element click
|
|
1109
|
-
*/
|
|
1110
|
-
KTSelect.prototype._handleDropdownClick = function (event) {
|
|
1111
|
-
if (this._config.debug)
|
|
1112
|
-
console.log('Display element clicked', event.target);
|
|
1113
|
-
event.preventDefault();
|
|
1114
|
-
event.stopPropagation(); // Prevent event bubbling
|
|
1115
|
-
this.toggleDropdown();
|
|
1116
|
-
};
|
|
1117
909
|
/**
|
|
1118
910
|
* Handle click within the dropdown
|
|
1119
911
|
*/
|
|
@@ -1154,6 +946,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1154
946
|
}
|
|
1155
947
|
if (this._config.debug)
|
|
1156
948
|
console.log('Option clicked:', optionValue);
|
|
949
|
+
// If in single-select mode and the clicked option is already selected, just close the dropdown.
|
|
950
|
+
if (!this._config.multiple && this._state.isSelected(optionValue)) {
|
|
951
|
+
if (this._config.debug)
|
|
952
|
+
console.log('Single select mode: clicked already selected option. Closing dropdown.');
|
|
953
|
+
this.closeDropdown();
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
1157
956
|
// Use toggleSelection instead of _selectOption to prevent re-rendering
|
|
1158
957
|
this.toggleSelection(optionValue);
|
|
1159
958
|
};
|
|
@@ -1167,14 +966,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1167
966
|
this.closeDropdown();
|
|
1168
967
|
}
|
|
1169
968
|
};
|
|
1170
|
-
/**
|
|
1171
|
-
* Handle escape key press
|
|
1172
|
-
*/
|
|
1173
|
-
KTSelect.prototype._handleEscKey = function (event) {
|
|
1174
|
-
if (event.key === 'Escape' && this._dropdownIsOpen) {
|
|
1175
|
-
this.closeDropdown();
|
|
1176
|
-
}
|
|
1177
|
-
};
|
|
1178
969
|
/**
|
|
1179
970
|
* ========================================================================
|
|
1180
971
|
* ACCESSIBILITY METHODS
|
|
@@ -1186,18 +977,6 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1186
977
|
KTSelect.prototype._setAriaAttributes = function () {
|
|
1187
978
|
this._displayElement.setAttribute('aria-expanded', this._dropdownIsOpen.toString());
|
|
1188
979
|
};
|
|
1189
|
-
/**
|
|
1190
|
-
* Handle focus events
|
|
1191
|
-
*/
|
|
1192
|
-
KTSelect.prototype._handleFocus = function () {
|
|
1193
|
-
// Implementation pending
|
|
1194
|
-
};
|
|
1195
|
-
/**
|
|
1196
|
-
* Handle blur events
|
|
1197
|
-
*/
|
|
1198
|
-
KTSelect.prototype._handleBlur = function () {
|
|
1199
|
-
// Implementation pending
|
|
1200
|
-
};
|
|
1201
980
|
/**
|
|
1202
981
|
* ========================================================================
|
|
1203
982
|
* PUBLIC API
|
|
@@ -1237,7 +1016,13 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1237
1016
|
* Get value display element
|
|
1238
1017
|
*/
|
|
1239
1018
|
KTSelect.prototype.getValueDisplayElement = function () {
|
|
1240
|
-
return this.
|
|
1019
|
+
return this._displayElement;
|
|
1020
|
+
};
|
|
1021
|
+
/**
|
|
1022
|
+
* Get wrapper element
|
|
1023
|
+
*/
|
|
1024
|
+
KTSelect.prototype.getWrapperElement = function () {
|
|
1025
|
+
return this._wrapperElement;
|
|
1241
1026
|
};
|
|
1242
1027
|
/**
|
|
1243
1028
|
* Show all options in the dropdown
|
|
@@ -1247,6 +1032,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1247
1032
|
var options = Array.from(this._wrapperElement.querySelectorAll("[data-kt-select-option]"));
|
|
1248
1033
|
// Show all options by removing the hidden class and any inline styles
|
|
1249
1034
|
options.forEach(function (option) {
|
|
1035
|
+
var _a;
|
|
1250
1036
|
// Remove hidden class
|
|
1251
1037
|
option.classList.remove('hidden');
|
|
1252
1038
|
// Clean up any existing inline styles for backward compatibility
|
|
@@ -1260,17 +1046,17 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1260
1046
|
}
|
|
1261
1047
|
else {
|
|
1262
1048
|
// Otherwise, remove just the display property
|
|
1263
|
-
option.setAttribute('style', styleAttr.replace(/display:\s*[^;]+;?/gi, '').trim());
|
|
1049
|
+
option.setAttribute('style', (_a = styleAttr === null || styleAttr === void 0 ? void 0 : styleAttr.replace(/display:\s*[^;]+;?/gi, '')) === null || _a === void 0 ? void 0 : _a.trim());
|
|
1264
1050
|
}
|
|
1265
1051
|
}
|
|
1266
1052
|
}
|
|
1267
1053
|
});
|
|
1268
1054
|
// If search input exists, clear it
|
|
1269
|
-
if (this._searchInputElement
|
|
1055
|
+
if (this._searchInputElement) {
|
|
1270
1056
|
this._searchInputElement.value = '';
|
|
1271
1057
|
// If we have a search module, clear any search filtering
|
|
1272
1058
|
if (this._searchModule) {
|
|
1273
|
-
this._searchModule.
|
|
1059
|
+
this._searchModule.clearSearch();
|
|
1274
1060
|
}
|
|
1275
1061
|
}
|
|
1276
1062
|
};
|
|
@@ -1290,10 +1076,16 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1290
1076
|
* Toggle the selection of an option
|
|
1291
1077
|
*/
|
|
1292
1078
|
KTSelect.prototype.toggleSelection = function (value) {
|
|
1079
|
+
// Prevent selection if the option is disabled (in dropdown or original select)
|
|
1080
|
+
if (this._isOptionDisabled(value)) {
|
|
1081
|
+
if (this._config.debug)
|
|
1082
|
+
console.log('toggleSelection: Option is disabled, ignoring selection');
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1293
1085
|
// Get current selection state
|
|
1294
1086
|
var isSelected = this._state.isSelected(value);
|
|
1295
1087
|
if (this._config.debug)
|
|
1296
|
-
console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple
|
|
1088
|
+
console.log("toggleSelection called for value: ".concat(value, ", isSelected: ").concat(isSelected, ", multiple: ").concat(this._config.multiple));
|
|
1297
1089
|
// If already selected in single select mode, do nothing (can't deselect in single select)
|
|
1298
1090
|
if (isSelected && !this._config.multiple) {
|
|
1299
1091
|
if (this._config.debug)
|
|
@@ -1302,9 +1094,9 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1302
1094
|
}
|
|
1303
1095
|
if (this._config.debug)
|
|
1304
1096
|
console.log("Toggling selection for option: ".concat(value, ", currently selected: ").concat(isSelected));
|
|
1305
|
-
// Ensure any search
|
|
1097
|
+
// Ensure any search input is cleared when selection changes
|
|
1306
1098
|
if (this._searchModule) {
|
|
1307
|
-
this._searchModule.
|
|
1099
|
+
this._searchModule.clearSearch();
|
|
1308
1100
|
}
|
|
1309
1101
|
// Toggle the selection in the state
|
|
1310
1102
|
this._state.toggleSelectedOptions(value);
|
|
@@ -1327,15 +1119,14 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1327
1119
|
// Update option classes without re-rendering the dropdown content
|
|
1328
1120
|
this._updateSelectedOptionClass();
|
|
1329
1121
|
// For single select mode, always close the dropdown after selection
|
|
1330
|
-
// For multiple select mode, only close if closeOnSelect is true
|
|
1331
1122
|
if (!this._config.multiple) {
|
|
1332
1123
|
if (this._config.debug)
|
|
1333
1124
|
console.log('About to call closeDropdown() for single select mode - always close after selection');
|
|
1334
1125
|
this.closeDropdown();
|
|
1335
1126
|
}
|
|
1336
|
-
else
|
|
1127
|
+
else {
|
|
1337
1128
|
if (this._config.debug)
|
|
1338
|
-
console.log('About to call closeDropdown() for multiple select
|
|
1129
|
+
console.log('About to call closeDropdown() for multiple select');
|
|
1339
1130
|
this.closeDropdown();
|
|
1340
1131
|
}
|
|
1341
1132
|
// Dispatch custom change event with additional data
|
|
@@ -1435,9 +1226,9 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1435
1226
|
.then(function () {
|
|
1436
1227
|
// Update options in the dropdown
|
|
1437
1228
|
_this._updateSearchResults(items);
|
|
1438
|
-
// Refresh the search module
|
|
1439
|
-
if (_this._searchModule
|
|
1440
|
-
_this._searchModule.
|
|
1229
|
+
// Refresh the search module to update focus and cache
|
|
1230
|
+
if (_this._searchModule) {
|
|
1231
|
+
_this._searchModule.refreshAfterSearch();
|
|
1441
1232
|
}
|
|
1442
1233
|
})
|
|
1443
1234
|
.catch(function (error) {
|
|
@@ -1457,7 +1248,7 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1457
1248
|
*/
|
|
1458
1249
|
KTSelect.prototype._renderSearchLoadingState = function () {
|
|
1459
1250
|
if (!this._originalOptionsHtml && this._dropdownContentElement) {
|
|
1460
|
-
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options
|
|
1251
|
+
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
1461
1252
|
if (optionsContainer) {
|
|
1462
1253
|
this._originalOptionsHtml = optionsContainer.innerHTML;
|
|
1463
1254
|
}
|
|
@@ -1476,36 +1267,26 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1476
1267
|
* @param items Search result items
|
|
1477
1268
|
*/
|
|
1478
1269
|
KTSelect.prototype._updateSearchResults = function (items) {
|
|
1479
|
-
var _this = this;
|
|
1480
1270
|
if (!this._dropdownContentElement)
|
|
1481
1271
|
return;
|
|
1482
|
-
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options
|
|
1272
|
+
var optionsContainer = this._dropdownContentElement.querySelector('[data-kt-select-options]');
|
|
1483
1273
|
if (!optionsContainer)
|
|
1484
1274
|
return;
|
|
1485
1275
|
// Clear current options
|
|
1486
1276
|
optionsContainer.innerHTML = '';
|
|
1487
1277
|
if (items.length === 0) {
|
|
1488
1278
|
// Show no results message using template for consistency and customization
|
|
1489
|
-
var noResultsElement = templates_1.defaultTemplates.
|
|
1279
|
+
var noResultsElement = templates_1.defaultTemplates.empty(this._config);
|
|
1490
1280
|
optionsContainer.appendChild(noResultsElement);
|
|
1491
1281
|
return;
|
|
1492
1282
|
}
|
|
1493
1283
|
// Process each item individually to create options
|
|
1494
1284
|
items.forEach(function (item) {
|
|
1495
1285
|
// Create option for the original select
|
|
1496
|
-
var selectOption =
|
|
1286
|
+
var selectOption = document.createElement('option');
|
|
1497
1287
|
selectOption.value = item.id;
|
|
1498
|
-
if (item.description) {
|
|
1499
|
-
selectOption.setAttribute('data-kt-select-option-description', item.description);
|
|
1500
|
-
}
|
|
1501
|
-
if (item.icon) {
|
|
1502
|
-
selectOption.setAttribute('data-kt-select-option-icon', item.icon);
|
|
1503
|
-
}
|
|
1504
|
-
// Create option element for the dropdown
|
|
1505
|
-
var ktOption = new option_1.KTSelectOption(selectOption, _this._config);
|
|
1506
|
-
var renderedOption = ktOption.render();
|
|
1507
1288
|
// Add to dropdown container
|
|
1508
|
-
optionsContainer.appendChild(
|
|
1289
|
+
optionsContainer.appendChild(selectOption);
|
|
1509
1290
|
});
|
|
1510
1291
|
// Add pagination "Load More" button if needed
|
|
1511
1292
|
if (this._config.pagination && this._remoteModule.hasMorePages()) {
|
|
@@ -1514,18 +1295,178 @@ var KTSelect = /** @class */ (function (_super) {
|
|
|
1514
1295
|
// Update options NodeList
|
|
1515
1296
|
this._options = this._wrapperElement.querySelectorAll("[data-kt-select-option]");
|
|
1516
1297
|
};
|
|
1517
|
-
/**
|
|
1518
|
-
* Filter options by query
|
|
1519
|
-
*/
|
|
1520
|
-
KTSelect.prototype.filterOptions = function (query) {
|
|
1521
|
-
this._filterOptionsForCombobox(query);
|
|
1522
|
-
};
|
|
1523
1298
|
/**
|
|
1524
1299
|
* Check if dropdown is open
|
|
1525
1300
|
*/
|
|
1526
1301
|
KTSelect.prototype.isDropdownOpen = function () {
|
|
1527
1302
|
return this._dropdownIsOpen;
|
|
1528
1303
|
};
|
|
1304
|
+
KTSelect.prototype.getSelectedOptionsText = function () {
|
|
1305
|
+
var _this = this;
|
|
1306
|
+
var selectedValues = this.getSelectedOptions();
|
|
1307
|
+
var displaySeparator = this._config.displaySeparator || ', ';
|
|
1308
|
+
var texts = selectedValues.map(function (value) {
|
|
1309
|
+
var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
|
|
1310
|
+
return (option === null || option === void 0 ? void 0 : option.getAttribute('data-text')) || '';
|
|
1311
|
+
}).filter(Boolean);
|
|
1312
|
+
return texts.join(displaySeparator);
|
|
1313
|
+
};
|
|
1314
|
+
/**
|
|
1315
|
+
* Check if an option is disabled (either in dropdown or original select)
|
|
1316
|
+
*/
|
|
1317
|
+
KTSelect.prototype._isOptionDisabled = function (value) {
|
|
1318
|
+
var dropdownOption = Array.from(this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
|
|
1319
|
+
var isDropdownDisabled = dropdownOption && (dropdownOption.classList.contains('disabled') || dropdownOption.getAttribute('aria-disabled') === 'true');
|
|
1320
|
+
var selectOption = Array.from(this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
|
|
1321
|
+
var isNativeDisabled = selectOption && selectOption.disabled;
|
|
1322
|
+
return Boolean(isDropdownDisabled || isNativeDisabled);
|
|
1323
|
+
};
|
|
1324
|
+
/**
|
|
1325
|
+
* Centralized keyboard event handler for all select modes
|
|
1326
|
+
*/
|
|
1327
|
+
KTSelect.prototype._handleKeyboardEvent = function (event) {
|
|
1328
|
+
// If the event target is the search input and the event was already handled (defaultPrevented),
|
|
1329
|
+
// then return early to avoid duplicate processing by this broader handler.
|
|
1330
|
+
if (event.target === this._searchInputElement && event.defaultPrevented) {
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
var isOpen = this._dropdownIsOpen;
|
|
1334
|
+
var config = this._config;
|
|
1335
|
+
var focusManager = this._focusManager;
|
|
1336
|
+
var buffer = this._typeToSearchBuffer;
|
|
1337
|
+
// If the event target is the search input, let it handle most typing keys naturally.
|
|
1338
|
+
if (event.target === this._searchInputElement) {
|
|
1339
|
+
// Allow navigation keys like ArrowDown, ArrowUp, Escape, Enter (for search/selection) to be handled by the logic below.
|
|
1340
|
+
// For other keys (characters, space, backspace, delete), let the input field process them.
|
|
1341
|
+
if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp' &&
|
|
1342
|
+
event.key !== 'Escape' && event.key !== 'Enter' && event.key !== 'Tab' &&
|
|
1343
|
+
event.key !== 'Home' && event.key !== 'End') {
|
|
1344
|
+
// If it's a character key and we are NOT type-to-searching (because search has focus)
|
|
1345
|
+
// then let the input field handle it for its own value.
|
|
1346
|
+
// The search module's 'input' event will handle filtering based on the input's value.
|
|
1347
|
+
buffer.clear(); // Clear type-to-search buffer when typing in search field
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
// For Enter specifically in search input, we might want to select the focused option or submit search.
|
|
1351
|
+
// This is handled later in the switch.
|
|
1352
|
+
}
|
|
1353
|
+
// Ignore modifier keys (except for specific combinations if added later)
|
|
1354
|
+
if (event.altKey || event.ctrlKey || event.metaKey)
|
|
1355
|
+
return;
|
|
1356
|
+
// Type-to-search: only for single char keys, when search input does not have focus
|
|
1357
|
+
if (event.key.length === 1 && !event.repeat && !event.key.match(/\s/) && document.activeElement !== this._searchInputElement) {
|
|
1358
|
+
buffer.push(event.key);
|
|
1359
|
+
var str = buffer.getBuffer();
|
|
1360
|
+
if (isOpen) {
|
|
1361
|
+
focusManager.focusByString(str);
|
|
1362
|
+
}
|
|
1363
|
+
else {
|
|
1364
|
+
// If closed, type-to-search could potentially open and select.
|
|
1365
|
+
// For now, let's assume it only works when open or opens it first.
|
|
1366
|
+
// Or, we could find the matching option and set it directly without opening.
|
|
1367
|
+
}
|
|
1368
|
+
return; // Type-to-search handles the event
|
|
1369
|
+
}
|
|
1370
|
+
switch (event.key) {
|
|
1371
|
+
case 'ArrowDown':
|
|
1372
|
+
event.preventDefault();
|
|
1373
|
+
if (!isOpen) {
|
|
1374
|
+
this.openDropdown();
|
|
1375
|
+
}
|
|
1376
|
+
else {
|
|
1377
|
+
focusManager.focusNext();
|
|
1378
|
+
}
|
|
1379
|
+
break;
|
|
1380
|
+
case 'ArrowUp':
|
|
1381
|
+
event.preventDefault();
|
|
1382
|
+
if (!isOpen) {
|
|
1383
|
+
this.openDropdown();
|
|
1384
|
+
}
|
|
1385
|
+
else {
|
|
1386
|
+
focusManager.focusPrevious();
|
|
1387
|
+
}
|
|
1388
|
+
break;
|
|
1389
|
+
case 'Home':
|
|
1390
|
+
event.preventDefault();
|
|
1391
|
+
if (isOpen)
|
|
1392
|
+
focusManager.focusFirst();
|
|
1393
|
+
break;
|
|
1394
|
+
case 'End':
|
|
1395
|
+
event.preventDefault();
|
|
1396
|
+
if (isOpen)
|
|
1397
|
+
focusManager.focusLast();
|
|
1398
|
+
break;
|
|
1399
|
+
case 'Enter':
|
|
1400
|
+
case ' ': // Space
|
|
1401
|
+
if (isOpen) {
|
|
1402
|
+
var focusedOptionEl = this._focusManager.getFocusedOption();
|
|
1403
|
+
if (focusedOptionEl) {
|
|
1404
|
+
var val = focusedOptionEl.dataset.value;
|
|
1405
|
+
// If single select, and the item is already selected, just close.
|
|
1406
|
+
if (val !== undefined && !this._config.multiple && this._state.isSelected(val)) {
|
|
1407
|
+
if (this._config.debug)
|
|
1408
|
+
console.log('Enter on already selected item in single-select mode. Closing.');
|
|
1409
|
+
this.closeDropdown();
|
|
1410
|
+
event.preventDefault();
|
|
1411
|
+
break;
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
// Proceed with selection if not handled above
|
|
1415
|
+
this.selectFocusedOption();
|
|
1416
|
+
// Close dropdown if configured to do so (for new selections)
|
|
1417
|
+
if (!this._config.multiple) {
|
|
1418
|
+
// This will also be true for the case handled above, but closeDropdown is idempotent.
|
|
1419
|
+
// However, the break above prevents this from being reached for that specific case.
|
|
1420
|
+
this.closeDropdown();
|
|
1421
|
+
}
|
|
1422
|
+
event.preventDefault(); // Prevent form submission or other default actions
|
|
1423
|
+
break;
|
|
1424
|
+
}
|
|
1425
|
+
else {
|
|
1426
|
+
this.openDropdown();
|
|
1427
|
+
}
|
|
1428
|
+
break;
|
|
1429
|
+
case 'Escape':
|
|
1430
|
+
if (isOpen) {
|
|
1431
|
+
this.closeDropdown();
|
|
1432
|
+
event.target.blur();
|
|
1433
|
+
}
|
|
1434
|
+
break;
|
|
1435
|
+
case 'Tab':
|
|
1436
|
+
// Let Tab propagate for normal focus movement
|
|
1437
|
+
break;
|
|
1438
|
+
default:
|
|
1439
|
+
break;
|
|
1440
|
+
}
|
|
1441
|
+
};
|
|
1442
|
+
KTSelect.prototype.renderDisplayTemplateForSelected = function (selectedValues) {
|
|
1443
|
+
var _this = this;
|
|
1444
|
+
var optionsConfig = this._config.optionsConfig || {};
|
|
1445
|
+
var displaySeparator = this._config.displaySeparator || ', ';
|
|
1446
|
+
var contentArray = Array.from(new Set(selectedValues.map(function (value) {
|
|
1447
|
+
var option = Array.from(_this._options).find(function (opt) { return opt.getAttribute('data-value') === value; });
|
|
1448
|
+
if (!option)
|
|
1449
|
+
return '';
|
|
1450
|
+
var displayTemplate = _this._config.displayTemplate;
|
|
1451
|
+
var text = option.getAttribute('data-text') || '';
|
|
1452
|
+
// Replace all {{varname}} in option.innerHTML with values from _config
|
|
1453
|
+
Object.entries(optionsConfig[value] || {}).forEach(function (_a) {
|
|
1454
|
+
var key = _a[0], val = _a[1];
|
|
1455
|
+
if (["string", "number", "boolean"].includes(typeof val)) {
|
|
1456
|
+
displayTemplate = displayTemplate.replace(new RegExp("{{".concat(key, "}}"), 'g'), String(val));
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
return (0, utils_1.renderTemplateString)(displayTemplate, {
|
|
1460
|
+
selectedCount: selectedValues.length || 0,
|
|
1461
|
+
selectedTexts: _this.getSelectedOptionsText() || '',
|
|
1462
|
+
text: text,
|
|
1463
|
+
});
|
|
1464
|
+
}).filter(Boolean)));
|
|
1465
|
+
return contentArray.join(displaySeparator);
|
|
1466
|
+
};
|
|
1467
|
+
KTSelect.prototype.getDisplayElement = function () {
|
|
1468
|
+
return this._displayElement;
|
|
1469
|
+
};
|
|
1529
1470
|
/**
|
|
1530
1471
|
* ========================================================================
|
|
1531
1472
|
* STATIC METHODS
|