@keenthemes/ktui 1.2.5 → 1.2.6

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 (64) hide show
  1. package/dist/ktui.js +1965 -2690
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +60 -0
  5. package/lib/cjs/components/datatable/datatable-checkbox.d.ts.map +1 -1
  6. package/lib/cjs/components/datatable/datatable-checkbox.js.map +1 -1
  7. package/lib/cjs/components/datatable/datatable-layout-plugin.d.ts +7 -0
  8. package/lib/cjs/components/datatable/datatable-layout-plugin.d.ts.map +1 -0
  9. package/lib/cjs/components/datatable/datatable-layout-plugin.js +328 -0
  10. package/lib/cjs/components/datatable/datatable-layout-plugin.js.map +1 -0
  11. package/lib/cjs/components/datatable/datatable-local-provider.d.ts +2 -2
  12. package/lib/cjs/components/datatable/datatable-local-provider.d.ts.map +1 -1
  13. package/lib/cjs/components/datatable/datatable-local-provider.js +5 -3
  14. package/lib/cjs/components/datatable/datatable-local-provider.js.map +1 -1
  15. package/lib/cjs/components/datatable/datatable-pagination-renderer.d.ts.map +1 -1
  16. package/lib/cjs/components/datatable/datatable-pagination-renderer.js +11 -12
  17. package/lib/cjs/components/datatable/datatable-pagination-renderer.js.map +1 -1
  18. package/lib/cjs/components/datatable/datatable.d.ts +9 -0
  19. package/lib/cjs/components/datatable/datatable.d.ts.map +1 -1
  20. package/lib/cjs/components/datatable/datatable.js +90 -17
  21. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  22. package/lib/cjs/components/datatable/index.d.ts +1 -1
  23. package/lib/cjs/components/datatable/index.d.ts.map +1 -1
  24. package/lib/cjs/components/datatable/types.d.ts +27 -0
  25. package/lib/cjs/components/datatable/types.d.ts.map +1 -1
  26. package/lib/cjs/index.d.ts +1 -1
  27. package/lib/cjs/index.d.ts.map +1 -1
  28. package/lib/cjs/index.js.map +1 -1
  29. package/lib/esm/components/datatable/datatable-checkbox.d.ts.map +1 -1
  30. package/lib/esm/components/datatable/datatable-checkbox.js.map +1 -1
  31. package/lib/esm/components/datatable/datatable-layout-plugin.d.ts +7 -0
  32. package/lib/esm/components/datatable/datatable-layout-plugin.d.ts.map +1 -0
  33. package/lib/esm/components/datatable/datatable-layout-plugin.js +324 -0
  34. package/lib/esm/components/datatable/datatable-layout-plugin.js.map +1 -0
  35. package/lib/esm/components/datatable/datatable-local-provider.d.ts +2 -2
  36. package/lib/esm/components/datatable/datatable-local-provider.d.ts.map +1 -1
  37. package/lib/esm/components/datatable/datatable-local-provider.js +5 -3
  38. package/lib/esm/components/datatable/datatable-local-provider.js.map +1 -1
  39. package/lib/esm/components/datatable/datatable-pagination-renderer.d.ts.map +1 -1
  40. package/lib/esm/components/datatable/datatable-pagination-renderer.js +11 -12
  41. package/lib/esm/components/datatable/datatable-pagination-renderer.js.map +1 -1
  42. package/lib/esm/components/datatable/datatable.d.ts +9 -0
  43. package/lib/esm/components/datatable/datatable.d.ts.map +1 -1
  44. package/lib/esm/components/datatable/datatable.js +90 -17
  45. package/lib/esm/components/datatable/datatable.js.map +1 -1
  46. package/lib/esm/components/datatable/index.d.ts +1 -1
  47. package/lib/esm/components/datatable/index.d.ts.map +1 -1
  48. package/lib/esm/components/datatable/types.d.ts +27 -0
  49. package/lib/esm/components/datatable/types.d.ts.map +1 -1
  50. package/lib/esm/index.d.ts +1 -1
  51. package/lib/esm/index.d.ts.map +1 -1
  52. package/lib/esm/index.js.map +1 -1
  53. package/package.json +1 -1
  54. package/src/components/datatable/__tests__/locked-layout.test.ts +257 -0
  55. package/src/components/datatable/__tests__/pagination-reset.test.ts +18 -0
  56. package/src/components/datatable/datatable-checkbox.ts +5 -8
  57. package/src/components/datatable/datatable-layout-plugin.ts +449 -0
  58. package/src/components/datatable/datatable-local-provider.ts +15 -7
  59. package/src/components/datatable/datatable-pagination-renderer.ts +10 -13
  60. package/src/components/datatable/datatable.css +98 -0
  61. package/src/components/datatable/datatable.ts +109 -15
  62. package/src/components/datatable/index.ts +5 -0
  63. package/src/components/datatable/types.ts +33 -0
  64. package/src/index.ts +5 -0
@@ -11,6 +11,8 @@ import {
11
11
  KTDataTableSortOrderInterface,
12
12
  KTDataTableStateInterface,
13
13
  KTDataTableColumnFilterInterface,
14
+ KTDataTableLayoutPluginContextInterface,
15
+ KTDataTableLayoutPluginInterface,
14
16
  } from './types';
15
17
  import { KTOptionType } from '../../types';
16
18
  import KTComponents from '../../index';
@@ -20,6 +22,7 @@ import {
20
22
  KTDataTableCheckboxAPI,
21
23
  } from './datatable-checkbox';
22
24
  import { createSortHandler, KTDataTableSortAPI } from './datatable-sort';
25
+ import { createStickyLayoutPlugin } from './datatable-layout-plugin';
23
26
  import {
24
27
  KTDataTableCleanup,
25
28
  KTDataTableEventAdapter,
@@ -33,6 +36,7 @@ import { KTDataTableRemoteDataProvider } from './datatable-remote-provider';
33
36
  import { KTDataTableConfigStateStore } from './datatable-state-store';
34
37
  import { KTDataTableDomPaginationRenderer } from './datatable-pagination-renderer';
35
38
  import { KTDataTableDomTableRenderer } from './datatable-table-renderer';
39
+ import KTUtils from '../../helpers/utils';
36
40
 
37
41
  /**
38
42
  * Custom DataTable plugin class with server-side API, pagination, and sorting
@@ -80,6 +84,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
80
84
 
81
85
  private _checkbox: KTDataTableCheckboxAPI;
82
86
  private _sortHandler: KTDataTableSortAPI<T>;
87
+ private _layoutPlugin: KTDataTableLayoutPluginInterface | null = null;
83
88
  private _eventAdapter: KTDataTableEventAdapter;
84
89
  private _stateStore: KTDataTableStateStore;
85
90
  private _localProvider: KTDataTableLocalDataProvider<T>;
@@ -95,10 +100,10 @@ export class KTDataTable<T extends KTDataTableDataInterface>
95
100
  super();
96
101
 
97
102
  if (KTData.has(element as HTMLElement, this._name)) {
98
- // Already initialized (e.g. by createInstances). Merge user config so columns/sortType etc. apply.
103
+ // Already initialized (e.g. by createInstances). Merge demo config and redraw once.
99
104
  const existing = KTDataTable.getInstance(element as HTMLElement);
100
105
  if (existing && config) {
101
- existing._mergeConfig(config);
106
+ existing._applyRuntimeConfig(config);
102
107
  }
103
108
  return;
104
109
  }
@@ -109,7 +114,11 @@ export class KTDataTable<T extends KTDataTableDataInterface>
109
114
  if (!this._element) {
110
115
  return;
111
116
  }
117
+ if (!this._element.hasAttribute('data-kt-datatable')) {
118
+ this._element.setAttribute('data-kt-datatable', 'true');
119
+ }
112
120
  this._buildConfig();
121
+ this._normalizePageSizeConfig();
113
122
  this._stateStore = new KTDataTableConfigStateStore(this._config);
114
123
  this._eventAdapter = createDataTableEventAdapter(
115
124
  this._fireEvent.bind(this),
@@ -120,6 +129,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
120
129
  KTDataTable.asElementWithInstance(element).instance = this;
121
130
 
122
131
  this._initElements();
132
+ this._layoutPlugin = this._createLayoutPlugin();
123
133
  this._tableRenderer = new KTDataTableDomTableRenderer<T>();
124
134
  this._paginationRenderer = new KTDataTableDomPaginationRenderer();
125
135
  this._initDataProviders();
@@ -155,6 +165,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
155
165
 
156
166
  if (this._config.stateSave) {
157
167
  this._loadState();
168
+ this._normalizePageState();
158
169
  }
159
170
 
160
171
  this._updateData();
@@ -188,6 +199,69 @@ export class KTDataTable<T extends KTDataTableDataInterface>
188
199
  });
189
200
  }
190
201
 
202
+ private _createLayoutPlugin(): KTDataTableLayoutPluginInterface | null {
203
+ if (this._config.layoutPlugin) {
204
+ return this._config.layoutPlugin;
205
+ }
206
+
207
+ if (this._config.lockedLayout) {
208
+ return createStickyLayoutPlugin();
209
+ }
210
+
211
+ return null;
212
+ }
213
+
214
+ /**
215
+ * Apply config from a late constructor call (e.g. docs demo script after auto-init).
216
+ */
217
+ private _applyRuntimeConfig(config: KTDataTableConfigInterface): void {
218
+ this._mergeConfig(config);
219
+ this._normalizePageSizeConfig();
220
+ this._layoutPlugin = this._createLayoutPlugin();
221
+ this.reload();
222
+ }
223
+
224
+ private _normalizePageSizeConfig(): void {
225
+ const configuredPageSizes = Array.isArray(this._config.pageSizes)
226
+ ? this._config.pageSizes
227
+ : [];
228
+ const pageSizes = configuredPageSizes
229
+ .map((size) => Number(size))
230
+ .filter((size) => Number.isFinite(size) && size > 0)
231
+ .map((size) => Math.floor(size));
232
+ const fallbackPageSizes = [5, 10, 20, 30, 50];
233
+ this._config.pageSizes =
234
+ pageSizes.length > 0 ? Array.from(new Set(pageSizes)) : fallbackPageSizes;
235
+
236
+ const configuredPageSize = Number(this._config.pageSize);
237
+ this._config.pageSize =
238
+ Number.isFinite(configuredPageSize) && configuredPageSize > 0
239
+ ? Math.floor(configuredPageSize)
240
+ : this._config.pageSizes[0];
241
+ }
242
+
243
+ private _normalizePageState(): void {
244
+ const statePageSize = Number(this._config._state.pageSize);
245
+ this._config._state.pageSize =
246
+ Number.isFinite(statePageSize) && statePageSize > 0
247
+ ? Math.floor(statePageSize)
248
+ : this._config.pageSize;
249
+
250
+ const statePage = Number(this._config._state.page);
251
+ this._config._state.page =
252
+ Number.isFinite(statePage) && statePage > 0 ? Math.floor(statePage) : 1;
253
+ }
254
+
255
+ private _getLayoutPluginContext(): KTDataTableLayoutPluginContextInterface {
256
+ return {
257
+ rootElement: this._element,
258
+ tableElement: this._tableElement,
259
+ theadElement: this._theadElement,
260
+ tbodyElement: this._tbodyElement,
261
+ config: this._config,
262
+ };
263
+ }
264
+
191
265
  /**
192
266
  * Initialize default configuration for the datatable
193
267
  * @param config User-provided configuration options
@@ -431,7 +505,9 @@ export class KTDataTable<T extends KTDataTableDataInterface>
431
505
  const root = this._element;
432
506
  const attrs = this._config.attributes;
433
507
  if (!root || !attrs?.table) {
434
- throw new Error('KTDataTable: root element and table selector are required');
508
+ throw new Error(
509
+ 'KTDataTable: root element and table selector are required',
510
+ );
435
511
  }
436
512
 
437
513
  const tableEl = root.querySelector<HTMLTableElement>(attrs.table);
@@ -698,11 +774,20 @@ export class KTDataTable<T extends KTDataTableDataInterface>
698
774
  * @returns {Promise<void>} A promise that resolves when the table and pagination controls are updated
699
775
  */
700
776
  private async _draw(): Promise<void> {
701
- this._stateStore.patchState({
702
- totalPages:
703
- Math.ceil(this.getState().totalItems / this.getState().pageSize) || 0,
704
- });
777
+ const normalizedPageSize = Math.max(
778
+ 1,
779
+ Number(this.getState().pageSize) || Number(this._config.pageSize) || 1,
780
+ );
781
+ const totalPages =
782
+ Math.ceil(this.getState().totalItems / normalizedPageSize) || 0;
783
+ const page =
784
+ totalPages > 0
785
+ ? Math.min(Math.max(1, this.getState().page), totalPages)
786
+ : 1;
787
+
788
+ this._stateStore.patchState({ totalPages, page });
705
789
 
790
+ this._layoutPlugin?.beforeDraw?.(this._getLayoutPluginContext());
706
791
  this._emit('draw');
707
792
 
708
793
  this._dispose();
@@ -716,6 +801,15 @@ export class KTDataTable<T extends KTDataTableDataInterface>
716
801
  this._updatePagination();
717
802
  }
718
803
 
804
+ this._layoutPlugin?.afterDraw?.(this._getLayoutPluginContext());
805
+ if (!this._config.apiEndpoint) {
806
+ this._stateStore.patchState({
807
+ _contentChecksum: KTUtils.checksum(
808
+ JSON.stringify(this._tbodyElement.innerHTML),
809
+ ),
810
+ });
811
+ }
812
+
719
813
  this._emit('drew');
720
814
 
721
815
  // Spinner is hidden in _finalize() to ensure it stays visible until the entire request completes
@@ -731,7 +825,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
731
825
  * @returns {HTMLTableSectionElement} The new table body element
732
826
  */
733
827
  private _updateTable(): HTMLTableSectionElement {
734
- return this._tableRenderer.render({
828
+ this._tbodyElement = this._tableRenderer.render({
735
829
  config: this._config,
736
830
  context: this,
737
831
  data: this._data,
@@ -743,6 +837,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
743
837
  tableElement: this._tableElement,
744
838
  theadElement: this._theadElement,
745
839
  });
840
+ return this._tbodyElement;
746
841
  }
747
842
 
748
843
  /**
@@ -810,9 +905,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
810
905
  const root = this._element;
811
906
  const spinnerSel = this._config.attributes?.spinner;
812
907
  const fromDom =
813
- root && spinnerSel
814
- ? root.querySelector<HTMLElement>(spinnerSel)
815
- : null;
908
+ root && spinnerSel ? root.querySelector<HTMLElement>(spinnerSel) : null;
816
909
  const spinner = fromDom ?? this._createSpinner();
817
910
  if (spinner) {
818
911
  spinner.style.display = 'block';
@@ -825,9 +918,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
825
918
  const root = this._element;
826
919
  const spinnerSel = this._config.attributes?.spinner;
827
920
  const spinner =
828
- root && spinnerSel
829
- ? root.querySelector<HTMLElement>(spinnerSel)
830
- : null;
921
+ root && spinnerSel ? root.querySelector<HTMLElement>(spinnerSel) : null;
831
922
  if (spinner) {
832
923
  spinner.style.display = 'none';
833
924
  }
@@ -934,6 +1025,8 @@ export class KTDataTable<T extends KTDataTableDataInterface>
934
1025
  * This method is called before re-rendering or when disposing the component.
935
1026
  */
936
1027
  private _dispose() {
1028
+ this._layoutPlugin?.dispose?.(this._getLayoutPluginContext());
1029
+
937
1030
  const root = this._element;
938
1031
  if (!root) {
939
1032
  return;
@@ -983,7 +1076,8 @@ export class KTDataTable<T extends KTDataTableDataInterface>
983
1076
  } else {
984
1077
  const checkSel = this._config.attributes?.check;
985
1078
  if (checkSel) {
986
- const headerCheckElement = root.querySelector<HTMLInputElement>(checkSel);
1079
+ const headerCheckElement =
1080
+ root.querySelector<HTMLInputElement>(checkSel);
987
1081
  if (headerCheckElement) {
988
1082
  headerCheckElement.replaceWith(headerCheckElement.cloneNode(true));
989
1083
  }
@@ -16,4 +16,9 @@ export type {
16
16
  KTDataTableCheckConfigInterface,
17
17
  KTDataTableCheckInterface,
18
18
  KTDataTableCheckChangePayloadInterface,
19
+ KTDataTableLockedRowsConfigInterface,
20
+ KTDataTableLockedColumnsConfigInterface,
21
+ KTDataTableLockedLayoutConfigInterface,
22
+ KTDataTableLayoutPluginContextInterface,
23
+ KTDataTableLayoutPluginInterface,
19
24
  } from './types';
@@ -69,6 +69,36 @@ export interface KTDataTableResponseDataInterface {
69
69
  totalCount: number;
70
70
  }
71
71
 
72
+ export interface KTDataTableLockedRowsConfigInterface {
73
+ top?: number;
74
+ bottom?: number;
75
+ }
76
+
77
+ export interface KTDataTableLockedColumnsConfigInterface {
78
+ left?: string[];
79
+ right?: string[];
80
+ }
81
+
82
+ export interface KTDataTableLockedLayoutConfigInterface {
83
+ stickyHeader?: boolean;
84
+ stickyRows?: KTDataTableLockedRowsConfigInterface;
85
+ stickyColumns?: KTDataTableLockedColumnsConfigInterface;
86
+ }
87
+
88
+ export interface KTDataTableLayoutPluginContextInterface {
89
+ rootElement: HTMLElement;
90
+ tableElement: HTMLTableElement;
91
+ theadElement: HTMLTableSectionElement;
92
+ tbodyElement: HTMLTableSectionElement;
93
+ config: KTDataTableConfigInterface;
94
+ }
95
+
96
+ export interface KTDataTableLayoutPluginInterface {
97
+ beforeDraw?: (ctx: KTDataTableLayoutPluginContextInterface) => void;
98
+ afterDraw?: (ctx: KTDataTableLayoutPluginContextInterface) => void;
99
+ dispose?: (ctx: KTDataTableLayoutPluginContextInterface) => void;
100
+ }
101
+
72
102
  // Define the DataTable options type
73
103
  export interface KTDataTableConfigInterface {
74
104
  requestMethod?: string;
@@ -187,6 +217,9 @@ export interface KTDataTableConfigInterface {
187
217
  preserveSelection?: boolean;
188
218
  };
189
219
 
220
+ lockedLayout?: KTDataTableLockedLayoutConfigInterface;
221
+ layoutPlugin?: KTDataTableLayoutPluginInterface;
222
+
190
223
  _state?: KTDataTableStateInterface;
191
224
  _data?: KTDataTableDataInterface[];
192
225
 
package/src/index.ts CHANGED
@@ -87,6 +87,11 @@ export type {
87
87
  KTDataTableCheckConfigInterface,
88
88
  KTDataTableCheckInterface,
89
89
  KTDataTableCheckChangePayloadInterface,
90
+ KTDataTableLockedRowsConfigInterface,
91
+ KTDataTableLockedColumnsConfigInterface,
92
+ KTDataTableLockedLayoutConfigInterface,
93
+ KTDataTableLayoutPluginContextInterface,
94
+ KTDataTableLayoutPluginInterface,
90
95
  } from './components/datatable';
91
96
  export type {
92
97
  KTDismissConfigInterface,