@keenthemes/ktui 1.0.25 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/ktui.js +335 -36
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +216 -13
  5. package/examples/datatable/checkbox-events-test.html +400 -0
  6. package/examples/datatable/credentials-test.html +423 -0
  7. package/examples/datatable/remote-checkbox-test.html +365 -0
  8. package/examples/modal/persistent.html +205 -0
  9. package/examples/modal/remote-select-dropdown.html +166 -0
  10. package/examples/modal/select-dropdown-container.html +129 -0
  11. package/examples/select/formdata-remote.html +161 -0
  12. package/examples/select/modal-positioning-test.html +338 -0
  13. package/lib/cjs/components/datatable/datatable-checkbox.js +16 -3
  14. package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
  15. package/lib/cjs/components/datatable/datatable.js +3 -5
  16. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  17. package/lib/cjs/components/image-input/image-input.js.map +1 -1
  18. package/lib/cjs/components/modal/modal.js +16 -2
  19. package/lib/cjs/components/modal/modal.js.map +1 -1
  20. package/lib/cjs/components/select/config.js +5 -0
  21. package/lib/cjs/components/select/config.js.map +1 -1
  22. package/lib/cjs/components/select/dropdown.js +54 -3
  23. package/lib/cjs/components/select/dropdown.js.map +1 -1
  24. package/lib/cjs/components/select/select.js +241 -23
  25. package/lib/cjs/components/select/select.js.map +1 -1
  26. package/lib/cjs/components/select/templates.js.map +1 -1
  27. package/lib/esm/components/datatable/datatable-checkbox.js +16 -3
  28. package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
  29. package/lib/esm/components/datatable/datatable.js +3 -5
  30. package/lib/esm/components/datatable/datatable.js.map +1 -1
  31. package/lib/esm/components/image-input/image-input.js.map +1 -1
  32. package/lib/esm/components/modal/modal.js +16 -2
  33. package/lib/esm/components/modal/modal.js.map +1 -1
  34. package/lib/esm/components/select/config.js +5 -0
  35. package/lib/esm/components/select/config.js.map +1 -1
  36. package/lib/esm/components/select/dropdown.js +54 -3
  37. package/lib/esm/components/select/dropdown.js.map +1 -1
  38. package/lib/esm/components/select/select.js +241 -23
  39. package/lib/esm/components/select/select.js.map +1 -1
  40. package/lib/esm/components/select/templates.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/components/datatable/datatable-checkbox.ts +18 -3
  43. package/src/components/datatable/datatable.ts +3 -0
  44. package/src/components/datatable/types.ts +1 -0
  45. package/src/components/image-input/image-input.ts +12 -15
  46. package/src/components/modal/modal.ts +20 -2
  47. package/src/components/select/config.ts +6 -0
  48. package/src/components/select/dropdown.ts +69 -4
  49. package/src/components/select/select.ts +306 -36
  50. package/src/components/select/templates.ts +2 -1
  51. package/lib/cjs/components/config.js +0 -26
  52. package/lib/cjs/components/config.js.map +0 -1
  53. package/lib/cjs/components/config.umd.js +0 -23
  54. package/lib/cjs/components/config.umd.js.map +0 -1
  55. package/lib/cjs/components/menu/index.js +0 -6
  56. package/lib/cjs/components/menu/index.js.map +0 -1
  57. package/lib/cjs/components/menu/menu.js +0 -1021
  58. package/lib/cjs/components/menu/menu.js.map +0 -1
  59. package/lib/cjs/components/menu/types.js +0 -3
  60. package/lib/cjs/components/menu/types.js.map +0 -1
  61. package/lib/cjs/components/theme/index.js +0 -6
  62. package/lib/cjs/components/theme/index.js.map +0 -1
  63. package/lib/cjs/components/theme/theme.js +0 -147
  64. package/lib/cjs/components/theme/theme.js.map +0 -1
  65. package/lib/cjs/components/theme/types.js +0 -3
  66. package/lib/cjs/components/theme/types.js.map +0 -1
  67. package/lib/esm/components/config.js +0 -24
  68. package/lib/esm/components/config.js.map +0 -1
  69. package/lib/esm/components/config.umd.js +0 -23
  70. package/lib/esm/components/config.umd.js.map +0 -1
  71. package/lib/esm/components/menu/index.js +0 -2
  72. package/lib/esm/components/menu/index.js.map +0 -1
  73. package/lib/esm/components/menu/menu.js +0 -1018
  74. package/lib/esm/components/menu/menu.js.map +0 -1
  75. package/lib/esm/components/menu/types.js +0 -2
  76. package/lib/esm/components/menu/types.js.map +0 -1
  77. package/lib/esm/components/theme/index.js +0 -2
  78. package/lib/esm/components/theme/index.js.map +0 -1
  79. package/lib/esm/components/theme/theme.js +0 -144
  80. package/lib/esm/components/theme/theme.js.map +0 -1
  81. package/lib/esm/components/theme/types.js +0 -2
  82. package/lib/esm/components/theme/types.js.map +0 -1
  83. /package/examples/select/{dark-mode-test.html → dark-mode.html} +0 -0
  84. /package/examples/select/{dropdowncontainer-test.html → dropdowncontainer.html} +0 -0
  85. /package/examples/select/{global-config-test.html → global-config.html} +0 -0
package/dist/ktui.js CHANGED
@@ -6993,8 +6993,11 @@ function createCheckboxHandler(element, config, fireEvent) {
6993
6993
  return;
6994
6994
  var value = input.value;
6995
6995
  var selectedRows = getSelectedRows();
6996
- if (input.checked) {
6997
- if (!selectedRows.includes(value))
6996
+ var wasChecked = selectedRows.includes(value);
6997
+ var isNowChecked = input.checked;
6998
+ // Update state first
6999
+ if (isNowChecked) {
7000
+ if (!wasChecked)
6998
7001
  selectedRows.push(value);
6999
7002
  }
7000
7003
  else {
@@ -7002,14 +7005,24 @@ function createCheckboxHandler(element, config, fireEvent) {
7002
7005
  }
7003
7006
  setSelectedRows(selectedRows);
7004
7007
  updateHeaderCheckboxState();
7008
+ // Fire specific checked/unchecked events after state is updated
7009
+ if (isNowChecked && !wasChecked) {
7010
+ fireEvent('checked');
7011
+ }
7012
+ else if (!isNowChecked && wasChecked) {
7013
+ fireEvent('unchecked');
7014
+ }
7015
+ // Always fire changed event for backward compatibility
7005
7016
  fireEvent('changed');
7006
7017
  }
7007
7018
  // When the header checkbox is toggled
7008
7019
  function checkboxToggle(event) {
7009
7020
  var checked = !isChecked();
7021
+ // Update state first, then fire events
7022
+ change(checked);
7023
+ // Fire checked/unchecked events after state is updated
7010
7024
  var eventType = checked ? 'checked' : 'unchecked';
7011
7025
  fireEvent(eventType);
7012
- change(checked);
7013
7026
  }
7014
7027
  // Change all visible checkboxes and update selectedRows
7015
7028
  function change(checked) {
@@ -8405,11 +8418,9 @@ var KTDataTable = /** @class */ (function (_super) {
8405
8418
  apiEndpointWithQueryParams.search = queryParams.toString();
8406
8419
  this._config.apiEndpoint = apiEndpointWithQueryParams.toString();
8407
8420
  }
8408
- return [2 /*return*/, fetch(this._config.apiEndpoint, {
8409
- method: requestMethod,
8410
- body: requestBody,
8411
- headers: this._config.requestHeaders,
8412
- }).catch(function (error) {
8421
+ return [2 /*return*/, fetch(this._config.apiEndpoint, __assign({ method: requestMethod, body: requestBody, headers: this._config.requestHeaders }, (this._config.requestCredentials && {
8422
+ credentials: this._config.requestCredentials,
8423
+ }))).catch(function (error) {
8413
8424
  // Trigger an error event
8414
8425
  _this._fireEvent('error', { error: error });
8415
8426
  _this._dispatchEvent('error', { error: error });
@@ -9241,9 +9252,23 @@ var KTModal = /** @class */ (function (_super) {
9241
9252
  KTModal.prototype._handlers = function () {
9242
9253
  var _this = this;
9243
9254
  this._element.addEventListener('click', function (event) {
9244
- if (_this._element !== event.target)
9255
+ var target = event.target;
9256
+ var currentTarget = event.currentTarget;
9257
+ // Only proceed if clicking directly on the backdrop (modal element itself)
9258
+ // This prevents closing when clicking inside modal content or any child elements
9259
+ // (including dropdowns rendered via dropdownContainer pointing to modal)
9260
+ if (target !== currentTarget) {
9261
+ // Stop propagation for clicks inside dropdowns to prevent dropdown from closing
9262
+ // Check if click is inside a dropdown element (KT Select dropdown)
9263
+ var dropdownElement = target.closest('[data-kt-select-dropdown]');
9264
+ if (dropdownElement) {
9265
+ event.stopPropagation();
9266
+ }
9245
9267
  return;
9246
- if (_this._getOption('backdropStatic') === false) {
9268
+ }
9269
+ // Only hide if both backdropStatic is false AND persistent is false
9270
+ if (_this._getOption('backdropStatic') === false &&
9271
+ utils_1.default.stringToBoolean(_this._getOption('persistent')) === false) {
9247
9272
  _this._hide();
9248
9273
  }
9249
9274
  });
@@ -9563,8 +9588,14 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9563
9588
  _this._dropdownElement = dropdownElement;
9564
9589
  _this._config = config;
9565
9590
  _this._ktSelectInstance = ktSelectInstance; // Assign instance
9591
+ // For centered modals, don't move dropdown to container to preserve positioning context
9592
+ // For other cases, move to container if specified
9593
+ var modalParent = _this._getModalContainer();
9594
+ var isCenteredModal = modalParent && modalParent.classList.contains('kt-modal-center');
9595
+ // Only move dropdown if not in centered modal (regardless of strategy override)
9596
+ // This prevents the positioning bug even if user sets dropdownStrategy: 'fixed'
9566
9597
  var container = _this._resolveDropdownContainer();
9567
- if (container) {
9598
+ if (container && !isCenteredModal) {
9568
9599
  if (container !== _this._dropdownElement.parentElement) {
9569
9600
  container.appendChild(_this._dropdownElement);
9570
9601
  }
@@ -9632,6 +9663,49 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9632
9663
  this._dropdownElement.style.width = "".concat(toggleWidth, "px");
9633
9664
  }
9634
9665
  };
9666
+ /**
9667
+ * Detect if the select is inside a modal container
9668
+ * @returns The modal element if found, null otherwise
9669
+ */
9670
+ KTSelectDropdown.prototype._getModalContainer = function () {
9671
+ return this._element.closest('[data-kt-modal], .kt-modal, .kt-modal-center');
9672
+ };
9673
+ /**
9674
+ * Get the appropriate boundary element for Popper positioning
9675
+ * For centered modals, use .kt-modal-content to avoid transform calculation issues
9676
+ * @returns The boundary element, or null if no modal found
9677
+ */
9678
+ KTSelectDropdown.prototype._getModalBoundary = function () {
9679
+ var modalParent = this._getModalContainer();
9680
+ if (!modalParent) {
9681
+ return null;
9682
+ }
9683
+ // For centered modals, use .kt-modal-content as boundary to avoid transform issues
9684
+ if (modalParent.classList.contains('kt-modal-center')) {
9685
+ var modalContent = modalParent.querySelector('.kt-modal-content');
9686
+ return modalContent || modalParent;
9687
+ }
9688
+ // For non-centered modals, use the modal element itself
9689
+ return modalParent;
9690
+ };
9691
+ /**
9692
+ * Get the appropriate positioning strategy based on context
9693
+ * @returns 'fixed' if inside non-centered modal, 'absolute' for centered modals or no modal
9694
+ */
9695
+ KTSelectDropdown.prototype._getPositioningStrategy = function () {
9696
+ // Check if config explicitly sets strategy
9697
+ if (this._config.dropdownStrategy) {
9698
+ return this._config.dropdownStrategy;
9699
+ }
9700
+ // For centered modals, use absolute positioning to avoid transform calculation issues
9701
+ // For non-centered modals, use fixed positioning
9702
+ var modalParent = this._getModalContainer();
9703
+ if (modalParent && modalParent.classList.contains('kt-modal-center')) {
9704
+ return 'absolute';
9705
+ }
9706
+ // Use fixed positioning for non-centered modals
9707
+ return modalParent ? 'fixed' : 'absolute';
9708
+ };
9635
9709
  /**
9636
9710
  * Initialize the Popper instance for dropdown positioning
9637
9711
  */
@@ -9642,9 +9716,11 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9642
9716
  var offsetValue = '0, 5';
9643
9717
  // Get configuration options
9644
9718
  var placement = this._config.dropdownPlacement || 'bottom-start';
9645
- var strategy = this._config.dropdownStrategy || 'fixed';
9719
+ var strategy = this._getPositioningStrategy();
9646
9720
  var preventOverflow = this._config.dropdownPreventOverflow !== false;
9647
9721
  var flip = this._config.dropdownFlip !== false;
9722
+ // Get appropriate boundary element for modal context
9723
+ var boundary = this._getModalBoundary() || 'clippingParents';
9648
9724
  // Create new popper instance
9649
9725
  this._popperInstance = (0, core_1.createPopper)(this._toggleElement, this._dropdownElement, {
9650
9726
  placement: placement,
@@ -9659,7 +9735,7 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9659
9735
  {
9660
9736
  name: 'preventOverflow',
9661
9737
  options: {
9662
- boundary: 'viewport',
9738
+ boundary: boundary,
9663
9739
  altAxis: preventOverflow,
9664
9740
  },
9665
9741
  },
@@ -11858,6 +11934,12 @@ var KTSelect = /** @class */ (function (_super) {
11858
11934
  KTSelect.prototype._completeRemoteSetup = function () {
11859
11935
  // Initialize options
11860
11936
  this._preSelectOptions(this._element);
11937
+ // Prevent browser auto-selection when placeholder is configured
11938
+ if (this._config.placeholder &&
11939
+ this._state.getSelectedOptions().length === 0 &&
11940
+ this._preSelectedValues.length === 0) {
11941
+ this._element.value = '';
11942
+ }
11861
11943
  // Apply pre-selected values captured before remote data was loaded
11862
11944
  if (this._preSelectedValues.length > 0) {
11863
11945
  if (this._config.debug) {
@@ -12100,6 +12182,11 @@ var KTSelect = /** @class */ (function (_super) {
12100
12182
  this._setupElementReferences();
12101
12183
  // Initialize options
12102
12184
  this._preSelectOptions(this._element);
12185
+ // Prevent browser auto-selection when placeholder is configured
12186
+ if (this._config.placeholder &&
12187
+ this._state.getSelectedOptions().length === 0) {
12188
+ this._element.value = '';
12189
+ }
12103
12190
  // Apply disabled state if needed
12104
12191
  this._applyInitialDisabledState();
12105
12192
  // Initialize search if enabled
@@ -12533,6 +12620,22 @@ var KTSelect = /** @class */ (function (_super) {
12533
12620
  selectedOptions: this.getSelectedOptions(),
12534
12621
  });
12535
12622
  };
12623
+ /**
12624
+ * Sync native select value attribute for FormData support
12625
+ */
12626
+ KTSelect.prototype._syncNativeSelectValue = function () {
12627
+ var selectedOptions = this.getSelectedOptions();
12628
+ if (this._config.multiple) {
12629
+ // For multiple select, the selected options are marked via option.selected
12630
+ // The native select's value property will return the first selected option's value
12631
+ // FormData will include all selected values automatically
12632
+ }
12633
+ else {
12634
+ // For single select, set the value attribute explicitly
12635
+ var selectedValue = selectedOptions.length > 0 ? selectedOptions[0] : '';
12636
+ this._element.value = selectedValue;
12637
+ }
12638
+ };
12536
12639
  /**
12537
12640
  * Update selected option display value
12538
12641
  */
@@ -12540,6 +12643,8 @@ var KTSelect = /** @class */ (function (_super) {
12540
12643
  var selectedOptions = this.getSelectedOptions();
12541
12644
  var tagsEnabled = this._config.tags && this._tagsModule;
12542
12645
  var valueDisplayEl = this.getValueDisplayElement();
12646
+ // Sync native select value for FormData support
12647
+ this._syncNativeSelectValue();
12543
12648
  if (tagsEnabled) {
12544
12649
  // Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
12545
12650
  this._tagsModule.updateTagsDisplay(selectedOptions);
@@ -12641,6 +12746,8 @@ var KTSelect = /** @class */ (function (_super) {
12641
12746
  Array.from(this._element.querySelectorAll('option')).forEach(function (opt) {
12642
12747
  opt.selected = false;
12643
12748
  });
12749
+ // Clear native select value
12750
+ this._element.value = '';
12644
12751
  this.updateSelectedOptionDisplay();
12645
12752
  this._updateSelectedOptionClass();
12646
12753
  // Update select all button state
@@ -13009,41 +13116,228 @@ var KTSelect = /** @class */ (function (_super) {
13009
13116
  };
13010
13117
  /**
13011
13118
  * Update the dropdown to sync with native select element changes
13012
- * Optionally accepts new options to replace existing ones
13013
- * @param newOptions Optional array of new options [{value, text}, ...]
13119
+ * For remote selects, refetches data from the server and preserves selections
13120
+ * Optionally accepts new options to replace existing ones (static selects only)
13121
+ *
13122
+ * @param newOptions Optional array of new options [{value, text}, ...] (static selects only)
13014
13123
  * @public
13124
+ * @remarks
13125
+ * - For static selects: rebuilds dropdown from native select or new options
13126
+ * - For remote selects: fetches fresh data, preserves matching selections
13127
+ * - Selections are preserved if their values exist in new remote data
13128
+ * - Selections are cleared if their values don't exist in new data
13129
+ * @fires updated - After update completes successfully
13130
+ * @fires updateError - If remote data fetch fails
13015
13131
  */
13016
13132
  KTSelect.prototype.update = function (newOptions) {
13017
13133
  var _this = this;
13018
- if (newOptions) {
13019
- // Clear existing options except placeholder
13020
- this._clearExistingOptions();
13021
- // Add new options to native select
13022
- newOptions.forEach(function (opt) {
13023
- var option = document.createElement('option');
13024
- option.value = opt.value;
13025
- option.textContent = opt.text;
13026
- _this._element.appendChild(option);
13134
+ // For remote selects, refetch data
13135
+ if (this._config.remote && this._remoteModule) {
13136
+ this._remoteModule
13137
+ .fetchData()
13138
+ .then(function (items) {
13139
+ // Capture currently selected values before clearing
13140
+ var currentlySelected = _this._state.getSelectedOptions();
13141
+ // Clear existing options (also captures to _preSelectedValues)
13142
+ _this._clearExistingOptions();
13143
+ // Get all available values from new remote data
13144
+ var availableValues = items.map(function (item) { return item.id; });
13145
+ // Filter to only values that exist in new data
13146
+ var validSelections = currentlySelected.filter(function (value) {
13147
+ return availableValues.includes(value);
13148
+ });
13149
+ if (_this._config.debug && currentlySelected.length > 0) {
13150
+ console.log('update(): Preserving selections that exist in new data:', validSelections);
13151
+ }
13152
+ // Add new options from remote data and restore selection state
13153
+ items.forEach(function (item) {
13154
+ var option = document.createElement('option');
13155
+ option.value = item.id;
13156
+ option.textContent = item.title;
13157
+ if (item.disabled)
13158
+ option.disabled = true;
13159
+ // Restore selected attribute for preserved selections
13160
+ if (validSelections.includes(item.id)) {
13161
+ option.selected = true;
13162
+ }
13163
+ _this._element.appendChild(option);
13164
+ });
13165
+ // Rebuild dropdown
13166
+ _this._rebuildOptionsFromNative();
13167
+ // Sync selection state from native select (now has selected attributes)
13168
+ _this._syncSelectionFromNative();
13169
+ // Dispatch updated event
13170
+ _this._dispatchEvent('updated');
13171
+ _this._fireEvent('updated');
13172
+ })
13173
+ .catch(function (error) {
13174
+ console.error('Error updating remote data:', error);
13175
+ _this._dispatchEvent('updateError');
13176
+ _this._fireEvent('updateError');
13027
13177
  });
13028
13178
  }
13029
- // Rebuild dropdown from native select
13030
- this._rebuildOptionsFromNative();
13031
- // Dispatch updated event
13032
- this._dispatchEvent('updated');
13033
- this._fireEvent('updated');
13179
+ else {
13180
+ // For static selects, handle new options
13181
+ if (newOptions) {
13182
+ // Clear existing options except placeholder
13183
+ this._clearExistingOptions();
13184
+ // Add new options to native select
13185
+ newOptions.forEach(function (opt) {
13186
+ var option = document.createElement('option');
13187
+ option.value = opt.value;
13188
+ option.textContent = opt.text;
13189
+ _this._element.appendChild(option);
13190
+ });
13191
+ }
13192
+ // Rebuild dropdown from native select
13193
+ this._rebuildOptionsFromNative();
13194
+ // Dispatch updated event
13195
+ this._dispatchEvent('updated');
13196
+ this._fireEvent('updated');
13197
+ }
13198
+ };
13199
+ /**
13200
+ * Reload remote data and rebuild the dropdown
13201
+ * Only works with remote data enabled
13202
+ * @returns Promise that resolves when reload completes
13203
+ * @public
13204
+ */
13205
+ KTSelect.prototype.reload = function () {
13206
+ var _this = this;
13207
+ // Guard clause: only works with remote data
13208
+ if (!this._config.remote || !this._remoteModule) {
13209
+ console.warn('reload() only works with remote data enabled');
13210
+ return Promise.resolve();
13211
+ }
13212
+ // Dispatch reload start event
13213
+ this._dispatchEvent('reloadStart');
13214
+ this._fireEvent('reloadStart');
13215
+ // Capture currently selected values before clearing
13216
+ var currentlySelected = this._state.getSelectedOptions();
13217
+ // Fetch fresh remote data
13218
+ return this._remoteModule
13219
+ .fetchData()
13220
+ .then(function (items) {
13221
+ // Clear existing options (captures to _preSelectedValues)
13222
+ _this._clearExistingOptions();
13223
+ // Update state with new items
13224
+ return _this._state.setItems(items).then(function () {
13225
+ // Generate new options HTML
13226
+ _this._generateOptionsHtml(_this._element);
13227
+ // Preserve selections by marking matching options as selected
13228
+ var availableValues = items.map(function (item) {
13229
+ return item.id !== undefined ? String(item.id) : '';
13230
+ });
13231
+ var validSelections = currentlySelected.filter(function (value) {
13232
+ return availableValues.includes(value);
13233
+ });
13234
+ if (_this._config.debug && currentlySelected.length > 0) {
13235
+ console.log('reload(): Preserving selections that exist in new data:', validSelections);
13236
+ }
13237
+ // Mark preserved selections on new options
13238
+ validSelections.forEach(function (value) {
13239
+ var option = Array.from(_this._element.querySelectorAll('option')).find(function (opt) { return opt.value === value; });
13240
+ if (option) {
13241
+ option.selected = true;
13242
+ }
13243
+ });
13244
+ // Update the dropdown
13245
+ _this._updateDropdownWithNewOptions();
13246
+ // Sync selection state from native select (now has selected attributes)
13247
+ _this._syncSelectionFromNative();
13248
+ // Update visual display
13249
+ _this.updateSelectedOptionDisplay();
13250
+ _this._updateSelectedOptionClass();
13251
+ // Update select all button state if applicable
13252
+ if (_this._config.multiple && _this._config.enableSelectAll) {
13253
+ _this.updateSelectAllButtonState();
13254
+ }
13255
+ // Dispatch reload complete event
13256
+ _this._dispatchEvent('reloadComplete');
13257
+ _this._fireEvent('reloadComplete');
13258
+ });
13259
+ })
13260
+ .catch(function (error) {
13261
+ console.error('Error reloading remote data:', error);
13262
+ // Dispatch reload error event with error details
13263
+ _this._dispatchEvent('reloadError', { error: error });
13264
+ _this._fireEvent('reloadError', { error: error });
13265
+ // Re-throw error so caller can handle it
13266
+ throw error;
13267
+ });
13034
13268
  };
13035
13269
  /**
13036
13270
  * Refresh the visual display and state without rebuilding options
13271
+ * For remote selects, refetches data from the server and preserves selections
13272
+ * that exist in the newly fetched data
13273
+ *
13037
13274
  * @public
13275
+ * @remarks
13276
+ * - For static selects: syncs visual state with native select
13277
+ * - For remote selects: fetches fresh data, preserves matching selections
13278
+ * - Selections are preserved if their values exist in new remote data
13279
+ * - Selections are cleared if their values don't exist in new data
13280
+ * @fires refreshed - After refresh completes successfully
13281
+ * @fires refreshError - If remote data fetch fails
13038
13282
  */
13039
13283
  KTSelect.prototype.refresh = function () {
13040
- // Sync internal state from native select first
13041
- this._syncSelectionFromNative();
13042
- // Reapply ARIA attributes
13043
- this._setAriaAttributes();
13044
- // Dispatch refreshed event
13045
- this._dispatchEvent('refreshed');
13046
- this._fireEvent('refreshed');
13284
+ var _this = this;
13285
+ // For remote selects, refetch data
13286
+ if (this._config.remote && this._remoteModule) {
13287
+ this._remoteModule
13288
+ .fetchData()
13289
+ .then(function (items) {
13290
+ // Capture currently selected values before clearing
13291
+ var currentlySelected = _this._state.getSelectedOptions();
13292
+ // Clear existing options (also captures to _preSelectedValues)
13293
+ _this._clearExistingOptions();
13294
+ // Get all available values from new remote data
13295
+ var availableValues = items.map(function (item) { return item.id; });
13296
+ // Filter to only values that exist in new data
13297
+ var validSelections = currentlySelected.filter(function (value) {
13298
+ return availableValues.includes(value);
13299
+ });
13300
+ if (_this._config.debug && currentlySelected.length > 0) {
13301
+ console.log('refresh(): Preserving selections that exist in new data:', validSelections);
13302
+ }
13303
+ // Add new options and restore selection state
13304
+ items.forEach(function (item) {
13305
+ var option = document.createElement('option');
13306
+ option.value = item.id;
13307
+ option.textContent = item.title;
13308
+ if (item.disabled)
13309
+ option.disabled = true;
13310
+ // Restore selected attribute for preserved selections
13311
+ if (validSelections.includes(item.id)) {
13312
+ option.selected = true;
13313
+ }
13314
+ _this._element.appendChild(option);
13315
+ });
13316
+ // Rebuild dropdown
13317
+ _this._rebuildOptionsFromNative();
13318
+ // Sync selection state from native select (now has selected attributes)
13319
+ _this._syncSelectionFromNative();
13320
+ // Reapply ARIA attributes
13321
+ _this._setAriaAttributes();
13322
+ // Dispatch refreshed event
13323
+ _this._dispatchEvent('refreshed');
13324
+ _this._fireEvent('refreshed');
13325
+ })
13326
+ .catch(function (error) {
13327
+ console.error('Error refreshing remote data:', error);
13328
+ _this._dispatchEvent('refreshError');
13329
+ _this._fireEvent('refreshError');
13330
+ });
13331
+ }
13332
+ else {
13333
+ // For static selects, just sync visual state
13334
+ this._syncSelectionFromNative();
13335
+ // Reapply ARIA attributes
13336
+ this._setAriaAttributes();
13337
+ // Dispatch refreshed event
13338
+ this._dispatchEvent('refreshed');
13339
+ this._fireEvent('refreshed');
13340
+ }
13047
13341
  };
13048
13342
  /**
13049
13343
  * ========================================================================
@@ -18447,6 +18741,11 @@ var KTSelectState = /** @class */ (function () {
18447
18741
  return this._config;
18448
18742
  };
18449
18743
  KTSelectState.prototype.setSelectedOptions = function (value) {
18744
+ // Handle empty array case first to prevent undefined elements
18745
+ if (Array.isArray(value) && value.length === 0) {
18746
+ this._selectedOptions = [];
18747
+ return;
18748
+ }
18450
18749
  if (this._config.multiple &&
18451
18750
  typeof value === 'string' &&
18452
18751
  !this._selectedOptions.includes(value)) {