@keenthemes/ktui 1.1.4 → 1.1.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 (101) hide show
  1. package/dist/ktui.js +11061 -10799
  2. package/dist/ktui.min.js +1 -1
  3. package/dist/ktui.min.js.map +1 -1
  4. package/dist/styles.css +33 -27
  5. package/lib/cjs/components/collapse/collapse.js +0 -2
  6. package/lib/cjs/components/collapse/collapse.js.map +1 -1
  7. package/lib/cjs/components/component.js +11 -0
  8. package/lib/cjs/components/component.js.map +1 -1
  9. package/lib/cjs/components/datatable/datatable-sort.js +80 -11
  10. package/lib/cjs/components/datatable/datatable-sort.js.map +1 -1
  11. package/lib/cjs/components/datatable/datatable.js +77 -24
  12. package/lib/cjs/components/datatable/datatable.js.map +1 -1
  13. package/lib/cjs/components/drawer/drawer.js +63 -42
  14. package/lib/cjs/components/drawer/drawer.js.map +1 -1
  15. package/lib/cjs/components/dropdown/dropdown.js +6 -0
  16. package/lib/cjs/components/dropdown/dropdown.js.map +1 -1
  17. package/lib/cjs/components/scrollto/scrollto.js +0 -2
  18. package/lib/cjs/components/scrollto/scrollto.js.map +1 -1
  19. package/lib/cjs/components/select/combobox.js.map +1 -1
  20. package/lib/cjs/components/select/dropdown.js.map +1 -1
  21. package/lib/cjs/components/select/remote.js.map +1 -1
  22. package/lib/cjs/components/select/search.js +9 -5
  23. package/lib/cjs/components/select/search.js.map +1 -1
  24. package/lib/cjs/components/select/select.js +29 -9
  25. package/lib/cjs/components/select/select.js.map +1 -1
  26. package/lib/cjs/components/select/tags.js.map +1 -1
  27. package/lib/cjs/components/select/templates.js.map +1 -1
  28. package/lib/cjs/components/select/utils.js +10 -0
  29. package/lib/cjs/components/select/utils.js.map +1 -1
  30. package/lib/cjs/components/sticky/sticky.js +104 -24
  31. package/lib/cjs/components/sticky/sticky.js.map +1 -1
  32. package/lib/cjs/components/theme-switch/theme-switch.js +0 -2
  33. package/lib/cjs/components/theme-switch/theme-switch.js.map +1 -1
  34. package/lib/cjs/components/toast/toast.js +1 -2
  35. package/lib/cjs/components/toast/toast.js.map +1 -1
  36. package/lib/cjs/helpers/dom.js +0 -2
  37. package/lib/cjs/helpers/dom.js.map +1 -1
  38. package/lib/esm/components/collapse/collapse.js +0 -2
  39. package/lib/esm/components/collapse/collapse.js.map +1 -1
  40. package/lib/esm/components/component.js +11 -0
  41. package/lib/esm/components/component.js.map +1 -1
  42. package/lib/esm/components/datatable/datatable-sort.js +80 -11
  43. package/lib/esm/components/datatable/datatable-sort.js.map +1 -1
  44. package/lib/esm/components/datatable/datatable.js +77 -24
  45. package/lib/esm/components/datatable/datatable.js.map +1 -1
  46. package/lib/esm/components/drawer/drawer.js +63 -42
  47. package/lib/esm/components/drawer/drawer.js.map +1 -1
  48. package/lib/esm/components/dropdown/dropdown.js +6 -0
  49. package/lib/esm/components/dropdown/dropdown.js.map +1 -1
  50. package/lib/esm/components/scrollto/scrollto.js +0 -2
  51. package/lib/esm/components/scrollto/scrollto.js.map +1 -1
  52. package/lib/esm/components/select/combobox.js.map +1 -1
  53. package/lib/esm/components/select/dropdown.js.map +1 -1
  54. package/lib/esm/components/select/remote.js.map +1 -1
  55. package/lib/esm/components/select/search.js +9 -5
  56. package/lib/esm/components/select/search.js.map +1 -1
  57. package/lib/esm/components/select/select.js +29 -9
  58. package/lib/esm/components/select/select.js.map +1 -1
  59. package/lib/esm/components/select/tags.js.map +1 -1
  60. package/lib/esm/components/select/templates.js.map +1 -1
  61. package/lib/esm/components/select/utils.js +10 -0
  62. package/lib/esm/components/select/utils.js.map +1 -1
  63. package/lib/esm/components/sticky/sticky.js +104 -24
  64. package/lib/esm/components/sticky/sticky.js.map +1 -1
  65. package/lib/esm/components/theme-switch/theme-switch.js +0 -2
  66. package/lib/esm/components/theme-switch/theme-switch.js.map +1 -1
  67. package/lib/esm/components/toast/toast.js +1 -2
  68. package/lib/esm/components/toast/toast.js.map +1 -1
  69. package/lib/esm/helpers/dom.js +0 -2
  70. package/lib/esm/helpers/dom.js.map +1 -1
  71. package/package.json +14 -7
  72. package/src/components/collapse/collapse.ts +0 -3
  73. package/src/components/component.ts +14 -4
  74. package/src/components/datatable/__tests__/currency-sort.test.ts +108 -0
  75. package/src/components/datatable/__tests__/multi-row-headers.test.ts +121 -0
  76. package/src/components/datatable/__tests__/pagination-reset.test.ts +13 -5
  77. package/src/components/datatable/__tests__/race-conditions.test.ts +138 -78
  78. package/src/components/datatable/__tests__/setup.ts +9 -4
  79. package/src/components/datatable/datatable-sort.ts +88 -10
  80. package/src/components/datatable/datatable.css +4 -4
  81. package/src/components/datatable/datatable.ts +91 -30
  82. package/src/components/datatable/types.ts +16 -0
  83. package/src/components/drawer/drawer.ts +97 -57
  84. package/src/components/drawer/types.ts +4 -2
  85. package/src/components/dropdown/dropdown.ts +8 -1
  86. package/src/components/scrollto/scrollto.ts +0 -3
  87. package/src/components/select/__tests__/ux-behaviors.test.ts +274 -8
  88. package/src/components/select/combobox.ts +0 -1
  89. package/src/components/select/dropdown.ts +0 -2
  90. package/src/components/select/remote.ts +1 -6
  91. package/src/components/select/search.ts +14 -7
  92. package/src/components/select/select.ts +29 -29
  93. package/src/components/select/tags.ts +0 -1
  94. package/src/components/select/templates.ts +8 -8
  95. package/src/components/select/utils.ts +15 -2
  96. package/src/components/sticky/__tests__/sticky.test.ts +205 -0
  97. package/src/components/sticky/sticky.ts +119 -21
  98. package/src/components/sticky/types.ts +3 -0
  99. package/src/components/theme-switch/theme-switch.ts +0 -3
  100. package/src/components/toast/toast.ts +3 -2
  101. package/src/helpers/dom.ts +0 -3
@@ -44,7 +44,7 @@ export function createSortHandler<T = KTDataTableDataInterface>(
44
44
  dispatchEvent: (eventName: string, eventData?: any) => void,
45
45
  updateData: () => void,
46
46
  ): KTDataTableSortAPI<T> {
47
- // Helper to compare values for sorting
47
+ // Helper to compare values for sorting (string)
48
48
  function compareValues(
49
49
  a: unknown,
50
50
  b: unknown,
@@ -63,15 +63,79 @@ export function createSortHandler<T = KTDataTableDataInterface>(
63
63
  : 0;
64
64
  }
65
65
 
66
+ // Parse value for numeric sort: strip currency/commas, then parseFloat
67
+ function parseNumeric(value: unknown): number {
68
+ if (value === null || value === undefined || value === '') {
69
+ return Number.NaN;
70
+ }
71
+ const s = String(value).replace(/[^0-9.-]/g, '');
72
+ const n = parseFloat(s);
73
+ return Number.isNaN(n) ? Number.NaN : n;
74
+ }
75
+
76
+ // Compare two numbers; NaN sorts to the end for both asc and desc
77
+ function compareNumeric(
78
+ aNum: number,
79
+ bNum: number,
80
+ sortOrder: KTDataTableSortOrderInterface,
81
+ ): number {
82
+ const aNaN = Number.isNaN(aNum);
83
+ const bNaN = Number.isNaN(bNum);
84
+ if (aNaN && bNaN) return 0;
85
+ if (aNaN) return 1;
86
+ if (bNaN) return -1;
87
+ if (aNum < bNum) return sortOrder === 'asc' ? -1 : 1;
88
+ if (aNum > bNum) return sortOrder === 'asc' ? 1 : -1;
89
+ return 0;
90
+ }
91
+
92
+ function getColumnDef(sortField: keyof T | number):
93
+ | {
94
+ sortType?: 'string' | 'numeric';
95
+ sortValue?: (
96
+ cellValue: unknown,
97
+ rowData: KTDataTableDataInterface,
98
+ ) => number | string;
99
+ }
100
+ | undefined {
101
+ const columns = config.columns;
102
+ if (!columns) return undefined;
103
+ const key =
104
+ typeof sortField === 'number'
105
+ ? (Object.keys(columns)[sortField] as keyof T | undefined)
106
+ : sortField;
107
+ return key !== undefined ? columns[key as string] : undefined;
108
+ }
109
+
66
110
  function sortData(
67
111
  data: T[],
68
112
  sortField: keyof T | number,
69
113
  sortOrder: KTDataTableSortOrderInterface,
70
114
  ): T[] {
115
+ const columnDef = getColumnDef(sortField);
116
+ const sortValueFn = columnDef?.sortValue;
117
+ const useNumeric = !sortValueFn && columnDef?.sortType === 'numeric';
118
+
71
119
  return data.sort((a, b) => {
72
- const aValue = a[sortField as keyof T] as unknown;
73
- const bValue = b[sortField as keyof T] as unknown;
74
- return compareValues(aValue, bValue, sortOrder);
120
+ const aRaw = a[sortField as keyof T] as unknown;
121
+ const bRaw = b[sortField as keyof T] as unknown;
122
+
123
+ if (typeof sortValueFn === 'function') {
124
+ const aVal = sortValueFn(aRaw, a as KTDataTableDataInterface);
125
+ const bVal = sortValueFn(bRaw, b as KTDataTableDataInterface);
126
+ const aNum = typeof aVal === 'number' ? aVal : parseNumeric(aVal);
127
+ const bNum = typeof bVal === 'number' ? bVal : parseNumeric(bVal);
128
+ if (typeof aVal === 'number' && typeof bVal === 'number') {
129
+ return compareNumeric(aNum, bNum, sortOrder);
130
+ }
131
+ return compareValues(aVal, bVal, sortOrder);
132
+ }
133
+ if (useNumeric) {
134
+ const aNum = parseNumeric(aRaw);
135
+ const bNum = parseNumeric(bRaw);
136
+ return compareNumeric(aNum, bNum, sortOrder);
137
+ }
138
+ return compareValues(aRaw, bRaw, sortOrder);
75
139
  });
76
140
  }
77
141
 
@@ -97,24 +161,38 @@ export function createSortHandler<T = KTDataTableDataInterface>(
97
161
  sortField: keyof T,
98
162
  sortOrder: KTDataTableSortOrderInterface,
99
163
  ): void {
164
+ const baseClass = config.sort?.classes?.base || '';
100
165
  const sortClass = sortOrder
101
166
  ? sortOrder === 'asc'
102
167
  ? config.sort?.classes?.asc || ''
103
168
  : config.sort?.classes?.desc || ''
104
169
  : '';
170
+ // Clear all headers: remove sort state so only the active column shows highlighted arrow
171
+ const allTh = theadElement.querySelectorAll('th');
172
+ allTh.forEach((header) => {
173
+ const el = header as HTMLElement;
174
+ el.setAttribute('aria-sort', 'none');
175
+ const sortElement = header.querySelector(`.${baseClass}`) as HTMLElement;
176
+ if (sortElement) {
177
+ sortElement.className = baseClass;
178
+ }
179
+ });
180
+ // Apply sort state to the active column so table.css [aria-sort='asc'] / [aria-sort='desc'] can highlight the arrow
105
181
  const th =
106
182
  typeof sortField === 'number'
107
- ? theadElement.querySelectorAll('th')[sortField]
183
+ ? allTh[sortField]
108
184
  : (theadElement.querySelector(
109
185
  `th[data-kt-datatable-column="${String(sortField)}"], th[data-kt-datatable-column-sort="${String(sortField)}"]`,
110
186
  ) as HTMLElement);
111
187
  if (th) {
112
- const sortElement = th.querySelector(
113
- `.${config.sort?.classes?.base}`,
114
- ) as HTMLElement;
188
+ const sortElement = th.querySelector(`.${baseClass}`) as HTMLElement;
115
189
  if (sortElement) {
116
- sortElement.className =
117
- `${config.sort?.classes?.base} ${sortClass}`.trim();
190
+ sortElement.className = `${baseClass} ${sortClass}`.trim();
191
+ }
192
+ if (sortOrder) {
193
+ th.setAttribute('aria-sort', sortOrder);
194
+ } else {
195
+ th.setAttribute('aria-sort', 'none');
118
196
  }
119
197
  }
120
198
  }
@@ -92,19 +92,19 @@
92
92
  }
93
93
 
94
94
  @custom-variant kt-datatable-sort-asc {
95
- &.[data-kt-datatable-column-sort='asc']:where([data-kt-datatable] *) {
95
+ &.[aria-sort='asc']:where([data-kt-datatable] *) {
96
96
  @slot;
97
97
  }
98
- [data-kt-datatable] [data-kt-datatable-column-sort='asc'] & {
98
+ [data-kt-datatable] [aria-sort='asc'] & {
99
99
  @slot;
100
100
  }
101
101
  }
102
102
 
103
103
  @custom-variant kt-datatable-sort-desc {
104
- &.[data-kt-datatable-column-sort='desc']:where([data-kt-datatable] *) {
104
+ &.[aria-sort='desc']:where([data-kt-datatable] *) {
105
105
  @slot;
106
106
  }
107
- [data-kt-datatable] [data-kt-datatable-column-sort='desc'] & {
107
+ [data-kt-datatable] [aria-sort='desc'] & {
108
108
  @slot;
109
109
  }
110
110
  }
@@ -73,7 +73,14 @@ export class KTDataTable<T extends KTDataTableDataInterface>
73
73
  constructor(element: HTMLElement, config?: KTDataTableConfigInterface) {
74
74
  super();
75
75
 
76
- if (KTData.has(element as HTMLElement, this._name)) return;
76
+ if (KTData.has(element as HTMLElement, this._name)) {
77
+ // Already initialized (e.g. by createInstances). Merge user config so columns/sortType etc. apply.
78
+ const existing = KTDataTable.getInstance(element as HTMLElement);
79
+ if (existing && config) {
80
+ existing._mergeConfig(config);
81
+ }
82
+ return;
83
+ }
77
84
 
78
85
  this._defaultConfig = this._initDefaultConfig(config);
79
86
 
@@ -668,14 +675,14 @@ export class KTDataTable<T extends KTDataTableDataInterface>
668
675
  this._storeOriginalClasses();
669
676
 
670
677
  const rows = this._tbodyElement.querySelectorAll<HTMLTableRowElement>('tr');
671
-
678
+
672
679
  // Filter th elements to only include those with data-kt-datatable-column attribute
673
680
  const allThs: NodeListOf<HTMLTableCellElement> = this._theadElement
674
681
  ? this._theadElement.querySelectorAll('th')
675
682
  : ([] as unknown as NodeListOf<HTMLTableCellElement>);
676
-
677
- const ths: HTMLTableCellElement[] = Array.from(allThs).filter(th =>
678
- th.hasAttribute('data-kt-datatable-column')
683
+
684
+ const ths: HTMLTableCellElement[] = Array.from(allThs).filter((th) =>
685
+ th.hasAttribute('data-kt-datatable-column'),
679
686
  );
680
687
 
681
688
  rows.forEach((row: HTMLTableRowElement) => {
@@ -708,22 +715,47 @@ export class KTDataTable<T extends KTDataTableDataInterface>
708
715
  */
709
716
  private _localTableHeaderInvalidate(): boolean {
710
717
  const { originalData } = this.getState();
711
-
712
- // Count only th elements with data-kt-datatable-column attribute
713
- const allThs: NodeListOf<HTMLTableCellElement> = this._theadElement
714
- ? this._theadElement.querySelectorAll('th')
715
- : ([] as unknown as NodeListOf<HTMLTableCellElement>);
716
- const currentTableHeaders = Array.from(allThs).filter(th =>
717
- th.hasAttribute('data-kt-datatable-column')
718
- ).length;
719
-
718
+
720
719
  const totalColumns = originalData.length
721
720
  ? Object.keys(originalData[0]).length
722
721
  : 0;
723
722
 
723
+ // Count th elements with data-kt-datatable-column; when none (e.g. multi-row headers), use logical column count so we don't falsely invalidate
724
+ const allThs: NodeListOf<HTMLTableCellElement> = this._theadElement
725
+ ? this._theadElement.querySelectorAll('th')
726
+ : ([] as unknown as NodeListOf<HTMLTableCellElement>);
727
+ const thsWithColumn = Array.from(allThs).filter((th) =>
728
+ th.hasAttribute('data-kt-datatable-column'),
729
+ );
730
+ const currentTableHeaders =
731
+ thsWithColumn.length > 0
732
+ ? thsWithColumn.length
733
+ : this._getLogicalColumnCount();
734
+
724
735
  return currentTableHeaders !== totalColumns;
725
736
  }
726
737
 
738
+ /**
739
+ * Returns the logical data column count (number of data columns), used for multi-row headers
740
+ * where querySelectorAll('th') would overcount. Prefers state.originalData, then first tbody row td count.
741
+ * @returns {number} Number of data columns, or 0 if unknown
742
+ */
743
+ private _getLogicalColumnCount(): number {
744
+ const { originalData } = this.getState();
745
+ if (originalData && originalData.length > 0) {
746
+ return Object.keys(originalData[0]).length;
747
+ }
748
+ if (this._tbodyElement) {
749
+ const firstRow = this._tbodyElement.querySelector<HTMLTableRowElement>(
750
+ 'tr',
751
+ );
752
+ if (firstRow) {
753
+ return firstRow.querySelectorAll<HTMLTableCellElement>('td').length;
754
+ }
755
+ }
756
+ return 0;
757
+ }
758
+
727
759
  /**
728
760
  * Fetch data from the server
729
761
  */
@@ -763,13 +795,13 @@ export class KTDataTable<T extends KTDataTableDataInterface>
763
795
  response,
764
796
  error: String(error),
765
797
  status: response.status,
766
- statusText: response.statusText
798
+ statusText: response.statusText,
767
799
  });
768
800
  this._dispatchEvent('parseError', {
769
801
  response,
770
802
  error: String(error),
771
803
  status: response.status,
772
- statusText: response.statusText
804
+ statusText: response.statusText,
773
805
  });
774
806
  return;
775
807
  }
@@ -855,7 +887,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
855
887
  private async _performFetchRequest(
856
888
  queryParams: URLSearchParams,
857
889
  ): Promise<Response> {
858
- let requestMethod: RequestInit['method'] = this._config.requestMethod;
890
+ const requestMethod: RequestInit['method'] = this._config.requestMethod;
859
891
  let requestBody: RequestInit['body'] | undefined = undefined;
860
892
 
861
893
  // Cancel previous request to prevent race conditions
@@ -1015,10 +1047,15 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1015
1047
  const allThs: NodeListOf<HTMLTableCellElement> = this._theadElement
1016
1048
  ? this._theadElement.querySelectorAll('th')
1017
1049
  : ([] as unknown as NodeListOf<HTMLTableCellElement>);
1018
-
1019
- const ths: HTMLTableCellElement[] = Array.from(allThs).filter(th =>
1020
- th.hasAttribute('data-kt-datatable-column')
1050
+
1051
+ const ths: HTMLTableCellElement[] = Array.from(allThs).filter((th) =>
1052
+ th.hasAttribute('data-kt-datatable-column'),
1021
1053
  );
1054
+ // When no th has data-kt-datatable-column (e.g. multi-row headers), use logical column count from tbody so we don't overcount thead cells
1055
+ const columnsToRender: HTMLTableCellElement[] =
1056
+ ths.length > 0 ? ths : [];
1057
+ const logicalColumnCount =
1058
+ ths.length > 0 ? ths.length : this._getLogicalColumnCount();
1022
1059
 
1023
1060
  this._data.forEach((item: T, rowIndex: number) => {
1024
1061
  const row = document.createElement('tr');
@@ -1033,9 +1070,9 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1033
1070
  ? this.getState().originalDataAttributes[rowIndex]
1034
1071
  : null;
1035
1072
 
1036
- // Use the order of <th> elements with data-kt-datatable-column to render <td>s in the correct order
1037
- ths.forEach((th, colIndex) => {
1038
- const colName = th.getAttribute('data-kt-datatable-column');
1073
+ for (let colIndex = 0; colIndex < logicalColumnCount; colIndex++) {
1074
+ const th = columnsToRender[colIndex];
1075
+ const colName = th?.getAttribute('data-kt-datatable-column');
1039
1076
  const td = document.createElement('td');
1040
1077
  let value: any;
1041
1078
  if (colName && Object.prototype.hasOwnProperty.call(item, colName)) {
@@ -1063,7 +1100,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1063
1100
  }
1064
1101
 
1065
1102
  row.appendChild(td);
1066
- });
1103
+ }
1067
1104
  } else {
1068
1105
  Object.keys(this._config.columns).forEach(
1069
1106
  (key: keyof T, colIndex: number) => {
@@ -1117,9 +1154,9 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1117
1154
  private _noticeOnTable(message: string = ''): void {
1118
1155
  const row = this._tableElement.tBodies[0].insertRow();
1119
1156
  const cell = row.insertCell();
1120
- cell.colSpan = this._theadElement
1121
- ? this._theadElement.querySelectorAll('th').length
1122
- : 0;
1157
+ const logicalCount = this._getLogicalColumnCount();
1158
+ // Use logical column count so multi-row headers don't overcount; fallback to 1 when 0 so message still displays
1159
+ cell.colSpan = logicalCount > 0 ? logicalCount : 1;
1123
1160
  cell.innerHTML = message;
1124
1161
  }
1125
1162
 
@@ -1472,7 +1509,7 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1472
1509
  const state = JSON.parse(stateString) as KTDataTableStateInterface;
1473
1510
  if (state) this._config._state = state;
1474
1511
  return state;
1475
- } catch {} // eslint-disable-line no-empty
1512
+ } catch {}
1476
1513
 
1477
1514
  return null;
1478
1515
  }
@@ -1811,8 +1848,32 @@ export class KTDataTable<T extends KTDataTableDataInterface>
1811
1848
  */
1812
1849
  public static init(): void {
1813
1850
  if (typeof document === 'undefined') return;
1814
- // Create instances of KTDataTable for all elements with a
1815
- // data-kt-datatable="true" attribute
1851
+ KTDataTable.createInstances();
1852
+ }
1853
+
1854
+ /**
1855
+ * Force reinitialization of datatables by clearing existing instances.
1856
+ * Useful for Livewire wire:navigate where the DOM is replaced and new tables need to be initialized.
1857
+ */
1858
+ public static reinit(): void {
1859
+ if (typeof document === 'undefined') return;
1860
+ const elements = document.querySelectorAll<HTMLElement>(
1861
+ '[data-kt-datatable="true"]',
1862
+ );
1863
+ elements.forEach((element) => {
1864
+ try {
1865
+ const instance = KTDataTable.getInstance(element);
1866
+ if (instance && typeof instance.dispose === 'function') {
1867
+ instance.dispose();
1868
+ }
1869
+ KTData.remove(element, 'datatable');
1870
+ element.removeAttribute('data-kt-datatable-initialized');
1871
+ element.classList.remove('datatable-initialized');
1872
+ } catch {
1873
+ // ignore per-element errors
1874
+ }
1875
+ });
1876
+ KTDataTable._instances.clear();
1816
1877
  KTDataTable.createInstances();
1817
1878
  }
1818
1879
 
@@ -101,6 +101,22 @@ export interface KTDataTableConfigInterface {
101
101
  rowData: KTDataTableDataInterface,
102
102
  row: HTMLTableRowElement,
103
103
  ) => void;
104
+ /**
105
+ * Sort comparison type for this column. When 'numeric', values are parsed
106
+ * (e.g. strip currency/commas) and compared as numbers.
107
+ */
108
+ sortType?: 'string' | 'numeric';
109
+ /**
110
+ * Custom value used for sorting. When set, this is used instead of the raw
111
+ * cell value (and instead of sortType). Return a number or string to sort by.
112
+ * Use for custom formats (e.g. dates, combined fields, custom parsing).
113
+ */
114
+ sortValue?: (
115
+ cellValue:
116
+ | KTDataTableDataInterface[keyof KTDataTableDataInterface]
117
+ | string,
118
+ rowData: KTDataTableDataInterface,
119
+ ) => number | string;
104
120
  };
105
121
  };
106
122