@keenthemes/ktui 1.0.25 → 1.0.26

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 (48) hide show
  1. package/dist/ktui.js +213 -33
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +210 -0
  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-test.html +205 -0
  9. package/examples/select/formdata-remote-test.html +161 -0
  10. package/examples/select/modal-positioning-test.html +336 -0
  11. package/lib/cjs/components/datatable/datatable-checkbox.js +16 -3
  12. package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
  13. package/lib/cjs/components/datatable/datatable.js +3 -5
  14. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  15. package/lib/cjs/components/image-input/image-input.js.map +1 -1
  16. package/lib/cjs/components/modal/modal.js +3 -1
  17. package/lib/cjs/components/modal/modal.js.map +1 -1
  18. package/lib/cjs/components/select/config.js +5 -0
  19. package/lib/cjs/components/select/config.js.map +1 -1
  20. package/lib/cjs/components/select/dropdown.js +25 -2
  21. package/lib/cjs/components/select/dropdown.js.map +1 -1
  22. package/lib/cjs/components/select/select.js +161 -22
  23. package/lib/cjs/components/select/select.js.map +1 -1
  24. package/lib/cjs/components/select/templates.js.map +1 -1
  25. package/lib/esm/components/datatable/datatable-checkbox.js +16 -3
  26. package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
  27. package/lib/esm/components/datatable/datatable.js +3 -5
  28. package/lib/esm/components/datatable/datatable.js.map +1 -1
  29. package/lib/esm/components/image-input/image-input.js.map +1 -1
  30. package/lib/esm/components/modal/modal.js +3 -1
  31. package/lib/esm/components/modal/modal.js.map +1 -1
  32. package/lib/esm/components/select/config.js +5 -0
  33. package/lib/esm/components/select/config.js.map +1 -1
  34. package/lib/esm/components/select/dropdown.js +25 -2
  35. package/lib/esm/components/select/dropdown.js.map +1 -1
  36. package/lib/esm/components/select/select.js +161 -22
  37. package/lib/esm/components/select/select.js.map +1 -1
  38. package/lib/esm/components/select/templates.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/components/datatable/datatable-checkbox.ts +18 -3
  41. package/src/components/datatable/datatable.ts +3 -0
  42. package/src/components/datatable/types.ts +1 -0
  43. package/src/components/image-input/image-input.ts +12 -15
  44. package/src/components/modal/modal.ts +5 -1
  45. package/src/components/select/config.ts +6 -0
  46. package/src/components/select/dropdown.ts +32 -3
  47. package/src/components/select/select.ts +192 -35
  48. package/src/components/select/templates.ts +2 -1
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 });
@@ -9243,7 +9254,9 @@ var KTModal = /** @class */ (function (_super) {
9243
9254
  this._element.addEventListener('click', function (event) {
9244
9255
  if (_this._element !== event.target)
9245
9256
  return;
9246
- if (_this._getOption('backdropStatic') === false) {
9257
+ // Only hide if both backdropStatic is false AND persistent is false
9258
+ if (_this._getOption('backdropStatic') === false &&
9259
+ utils_1.default.stringToBoolean(_this._getOption('persistent')) === false) {
9247
9260
  _this._hide();
9248
9261
  }
9249
9262
  });
@@ -9632,6 +9645,26 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9632
9645
  this._dropdownElement.style.width = "".concat(toggleWidth, "px");
9633
9646
  }
9634
9647
  };
9648
+ /**
9649
+ * Detect if the select is inside a modal container
9650
+ * @returns The modal element if found, null otherwise
9651
+ */
9652
+ KTSelectDropdown.prototype._getModalContainer = function () {
9653
+ return this._element.closest('[data-kt-modal], .kt-modal, .kt-modal-center');
9654
+ };
9655
+ /**
9656
+ * Get the appropriate positioning strategy based on context
9657
+ * @returns 'fixed' if inside modal, 'absolute' otherwise
9658
+ */
9659
+ KTSelectDropdown.prototype._getPositioningStrategy = function () {
9660
+ // Check if config explicitly sets strategy
9661
+ if (this._config.dropdownStrategy) {
9662
+ return this._config.dropdownStrategy;
9663
+ }
9664
+ // Use fixed positioning if inside a modal (to handle transform-based centering)
9665
+ var modalParent = this._getModalContainer();
9666
+ return modalParent ? 'fixed' : 'absolute';
9667
+ };
9635
9668
  /**
9636
9669
  * Initialize the Popper instance for dropdown positioning
9637
9670
  */
@@ -9642,9 +9675,12 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9642
9675
  var offsetValue = '0, 5';
9643
9676
  // Get configuration options
9644
9677
  var placement = this._config.dropdownPlacement || 'bottom-start';
9645
- var strategy = this._config.dropdownStrategy || 'fixed';
9678
+ var strategy = this._getPositioningStrategy();
9646
9679
  var preventOverflow = this._config.dropdownPreventOverflow !== false;
9647
9680
  var flip = this._config.dropdownFlip !== false;
9681
+ // Detect modal container for boundary
9682
+ var modalParent = this._getModalContainer();
9683
+ var boundary = modalParent || 'clippingParents';
9648
9684
  // Create new popper instance
9649
9685
  this._popperInstance = (0, core_1.createPopper)(this._toggleElement, this._dropdownElement, {
9650
9686
  placement: placement,
@@ -9659,7 +9695,7 @@ var KTSelectDropdown = /** @class */ (function (_super) {
9659
9695
  {
9660
9696
  name: 'preventOverflow',
9661
9697
  options: {
9662
- boundary: 'viewport',
9698
+ boundary: boundary,
9663
9699
  altAxis: preventOverflow,
9664
9700
  },
9665
9701
  },
@@ -12533,6 +12569,22 @@ var KTSelect = /** @class */ (function (_super) {
12533
12569
  selectedOptions: this.getSelectedOptions(),
12534
12570
  });
12535
12571
  };
12572
+ /**
12573
+ * Sync native select value attribute for FormData support
12574
+ */
12575
+ KTSelect.prototype._syncNativeSelectValue = function () {
12576
+ var selectedOptions = this.getSelectedOptions();
12577
+ if (this._config.multiple) {
12578
+ // For multiple select, the selected options are marked via option.selected
12579
+ // The native select's value property will return the first selected option's value
12580
+ // FormData will include all selected values automatically
12581
+ }
12582
+ else {
12583
+ // For single select, set the value attribute explicitly
12584
+ var selectedValue = selectedOptions.length > 0 ? selectedOptions[0] : '';
12585
+ this._element.value = selectedValue;
12586
+ }
12587
+ };
12536
12588
  /**
12537
12589
  * Update selected option display value
12538
12590
  */
@@ -12540,6 +12592,8 @@ var KTSelect = /** @class */ (function (_super) {
12540
12592
  var selectedOptions = this.getSelectedOptions();
12541
12593
  var tagsEnabled = this._config.tags && this._tagsModule;
12542
12594
  var valueDisplayEl = this.getValueDisplayElement();
12595
+ // Sync native select value for FormData support
12596
+ this._syncNativeSelectValue();
12543
12597
  if (tagsEnabled) {
12544
12598
  // Tags module will render tags if selectedOptions > 0, or clear them if selectedOptions === 0.
12545
12599
  this._tagsModule.updateTagsDisplay(selectedOptions);
@@ -12641,6 +12695,8 @@ var KTSelect = /** @class */ (function (_super) {
12641
12695
  Array.from(this._element.querySelectorAll('option')).forEach(function (opt) {
12642
12696
  opt.selected = false;
12643
12697
  });
12698
+ // Clear native select value
12699
+ this._element.value = '';
12644
12700
  this.updateSelectedOptionDisplay();
12645
12701
  this._updateSelectedOptionClass();
12646
12702
  // Update select all button state
@@ -13009,41 +13065,160 @@ var KTSelect = /** @class */ (function (_super) {
13009
13065
  };
13010
13066
  /**
13011
13067
  * Update the dropdown to sync with native select element changes
13012
- * Optionally accepts new options to replace existing ones
13068
+ * For remote selects, refetches data from the server
13069
+ * Optionally accepts new options to replace existing ones (static selects only)
13013
13070
  * @param newOptions Optional array of new options [{value, text}, ...]
13014
13071
  * @public
13015
13072
  */
13016
13073
  KTSelect.prototype.update = function (newOptions) {
13017
13074
  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);
13075
+ // For remote selects, refetch data
13076
+ if (this._config.remote && this._remoteModule) {
13077
+ this._remoteModule
13078
+ .fetchData()
13079
+ .then(function (items) {
13080
+ // Clear existing options
13081
+ _this._clearExistingOptions();
13082
+ // Add new options from remote data
13083
+ items.forEach(function (item) {
13084
+ var option = document.createElement('option');
13085
+ option.value = item.id;
13086
+ option.textContent = item.title;
13087
+ if (item.disabled)
13088
+ option.disabled = true;
13089
+ _this._element.appendChild(option);
13090
+ });
13091
+ // Rebuild dropdown
13092
+ _this._rebuildOptionsFromNative();
13093
+ // Dispatch updated event
13094
+ _this._dispatchEvent('updated');
13095
+ _this._fireEvent('updated');
13096
+ })
13097
+ .catch(function (error) {
13098
+ console.error('Error updating remote data:', error);
13099
+ _this._dispatchEvent('updateError');
13100
+ _this._fireEvent('updateError');
13027
13101
  });
13028
13102
  }
13029
- // Rebuild dropdown from native select
13030
- this._rebuildOptionsFromNative();
13031
- // Dispatch updated event
13032
- this._dispatchEvent('updated');
13033
- this._fireEvent('updated');
13103
+ else {
13104
+ // For static selects, handle new options
13105
+ if (newOptions) {
13106
+ // Clear existing options except placeholder
13107
+ this._clearExistingOptions();
13108
+ // Add new options to native select
13109
+ newOptions.forEach(function (opt) {
13110
+ var option = document.createElement('option');
13111
+ option.value = opt.value;
13112
+ option.textContent = opt.text;
13113
+ _this._element.appendChild(option);
13114
+ });
13115
+ }
13116
+ // Rebuild dropdown from native select
13117
+ this._rebuildOptionsFromNative();
13118
+ // Dispatch updated event
13119
+ this._dispatchEvent('updated');
13120
+ this._fireEvent('updated');
13121
+ }
13122
+ };
13123
+ /**
13124
+ * Reload remote data and rebuild the dropdown
13125
+ * Only works with remote data enabled
13126
+ * @returns Promise that resolves when reload completes
13127
+ * @public
13128
+ */
13129
+ KTSelect.prototype.reload = function () {
13130
+ var _this = this;
13131
+ // Guard clause: only works with remote data
13132
+ if (!this._config.remote || !this._remoteModule) {
13133
+ console.warn('reload() only works with remote data enabled');
13134
+ return Promise.resolve();
13135
+ }
13136
+ // Dispatch reload start event
13137
+ this._dispatchEvent('reloadStart');
13138
+ this._fireEvent('reloadStart');
13139
+ // Fetch fresh remote data
13140
+ return this._remoteModule
13141
+ .fetchData()
13142
+ .then(function (items) {
13143
+ // Clear existing options
13144
+ _this._clearExistingOptions();
13145
+ // Update state with new items
13146
+ return _this._state.setItems(items).then(function () {
13147
+ // Generate new options HTML
13148
+ _this._generateOptionsHtml(_this._element);
13149
+ // Update the dropdown
13150
+ _this._updateDropdownWithNewOptions();
13151
+ // Sync selection state from native select
13152
+ _this._syncSelectionFromNative();
13153
+ // Update visual display
13154
+ _this.updateSelectedOptionDisplay();
13155
+ _this._updateSelectedOptionClass();
13156
+ // Update select all button state if applicable
13157
+ if (_this._config.multiple && _this._config.enableSelectAll) {
13158
+ _this.updateSelectAllButtonState();
13159
+ }
13160
+ // Dispatch reload complete event
13161
+ _this._dispatchEvent('reloadComplete');
13162
+ _this._fireEvent('reloadComplete');
13163
+ });
13164
+ })
13165
+ .catch(function (error) {
13166
+ console.error('Error reloading remote data:', error);
13167
+ // Dispatch reload error event with error details
13168
+ _this._dispatchEvent('reloadError', { error: error });
13169
+ _this._fireEvent('reloadError', { error: error });
13170
+ // Re-throw error so caller can handle it
13171
+ throw error;
13172
+ });
13034
13173
  };
13035
13174
  /**
13036
13175
  * Refresh the visual display and state without rebuilding options
13176
+ * For remote selects, refetches data from the server
13037
13177
  * @public
13038
13178
  */
13039
13179
  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');
13180
+ var _this = this;
13181
+ // For remote selects, refetch data
13182
+ if (this._config.remote && this._remoteModule) {
13183
+ this._remoteModule
13184
+ .fetchData()
13185
+ .then(function (items) {
13186
+ // Clear existing options
13187
+ _this._clearExistingOptions();
13188
+ // Add new options
13189
+ items.forEach(function (item) {
13190
+ var option = document.createElement('option');
13191
+ option.value = item.id;
13192
+ option.textContent = item.title;
13193
+ if (item.disabled)
13194
+ option.disabled = true;
13195
+ _this._element.appendChild(option);
13196
+ });
13197
+ // Rebuild dropdown
13198
+ _this._rebuildOptionsFromNative();
13199
+ // Sync selection state
13200
+ _this._syncSelectionFromNative();
13201
+ // Reapply ARIA attributes
13202
+ _this._setAriaAttributes();
13203
+ // Dispatch refreshed event
13204
+ _this._dispatchEvent('refreshed');
13205
+ _this._fireEvent('refreshed');
13206
+ })
13207
+ .catch(function (error) {
13208
+ console.error('Error refreshing remote data:', error);
13209
+ _this._dispatchEvent('refreshError');
13210
+ _this._fireEvent('refreshError');
13211
+ });
13212
+ }
13213
+ else {
13214
+ // For static selects, just sync visual state
13215
+ this._syncSelectionFromNative();
13216
+ // Reapply ARIA attributes
13217
+ this._setAriaAttributes();
13218
+ // Dispatch refreshed event
13219
+ this._dispatchEvent('refreshed');
13220
+ this._fireEvent('refreshed');
13221
+ }
13047
13222
  };
13048
13223
  /**
13049
13224
  * ========================================================================
@@ -18447,6 +18622,11 @@ var KTSelectState = /** @class */ (function () {
18447
18622
  return this._config;
18448
18623
  };
18449
18624
  KTSelectState.prototype.setSelectedOptions = function (value) {
18625
+ // Handle empty array case first to prevent undefined elements
18626
+ if (Array.isArray(value) && value.length === 0) {
18627
+ this._selectedOptions = [];
18628
+ return;
18629
+ }
18450
18630
  if (this._config.multiple &&
18451
18631
  typeof value === 'string' &&
18452
18632
  !this._selectedOptions.includes(value)) {