@rozie-ui/data-table-solid 0.7.4 → 0.8.1
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/CHANGELOG.md +18 -0
- package/README.md +5 -1
- package/dist/index.cjs +501 -16
- package/dist/index.d.cts +23 -2
- package/dist/index.d.mts +23 -2
- package/dist/index.mjs +501 -16
- package/dist/source/index.jsx +500 -15
- package/package.json +2 -2
- package/src/Column.tsx +36 -3
- package/src/DataTable.tsx +484 -32
- package/src/helpers/activeFollow.ts +42 -0
- package/src/helpers/columnRuleUtils.ts +105 -0
- package/src/helpers/heldView.ts +185 -0
- package/src/index.ts +1 -1
package/dist/source/index.jsx
CHANGED
|
@@ -93,6 +93,74 @@ const columnSpecsEquivalent = (a, b, depth) => {
|
|
|
93
93
|
return true;
|
|
94
94
|
};
|
|
95
95
|
//#endregion
|
|
96
|
+
//#region src/helpers/columnRuleUtils.ts
|
|
97
|
+
const FILTER_FN_NAMES = [
|
|
98
|
+
"includesString",
|
|
99
|
+
"includesStringSensitive",
|
|
100
|
+
"equalsString",
|
|
101
|
+
"arrIncludes",
|
|
102
|
+
"arrIncludesAll",
|
|
103
|
+
"arrIncludesSome",
|
|
104
|
+
"equals",
|
|
105
|
+
"weakEquals",
|
|
106
|
+
"inNumberRange"
|
|
107
|
+
];
|
|
108
|
+
const SORTING_FN_NAMES = [
|
|
109
|
+
"alphanumeric",
|
|
110
|
+
"alphanumericCaseSensitive",
|
|
111
|
+
"text",
|
|
112
|
+
"textCaseSensitive",
|
|
113
|
+
"datetime",
|
|
114
|
+
"basic"
|
|
115
|
+
];
|
|
116
|
+
const warned = /* @__PURE__ */ new Set();
|
|
117
|
+
const resolveName = (value, names, kind, columnId, warn) => {
|
|
118
|
+
if (value === "auto" || names.includes(value)) return value;
|
|
119
|
+
const key = kind + "\0" + columnId + "\0" + value;
|
|
120
|
+
if (!warned.has(key)) {
|
|
121
|
+
warned.add(key);
|
|
122
|
+
warn(`[data-table] column "${columnId}": unknown ${kind} "${value}"; falling back to "auto".`);
|
|
123
|
+
}
|
|
124
|
+
return "auto";
|
|
125
|
+
};
|
|
126
|
+
const resolveFilterFn = (value, columnId, warn = console.warn) => {
|
|
127
|
+
if (value == null) return void 0;
|
|
128
|
+
if (typeof value === "string") return resolveName(value, FILTER_FN_NAMES, "filterFn", columnId, warn);
|
|
129
|
+
if (typeof value !== "function") return void 0;
|
|
130
|
+
const fn = value;
|
|
131
|
+
const adapter = (row, colId, filterValue) => {
|
|
132
|
+
try {
|
|
133
|
+
return fn(row.getValue(colId), filterValue, row.original);
|
|
134
|
+
} catch (err) {
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
if (fn.autoRemove !== void 0) adapter.autoRemove = fn.autoRemove;
|
|
139
|
+
if (fn.resolveFilterValue !== void 0) adapter.resolveFilterValue = fn.resolveFilterValue;
|
|
140
|
+
return adapter;
|
|
141
|
+
};
|
|
142
|
+
const resolveSortingFn = (value, columnId, warn = console.warn) => {
|
|
143
|
+
if (value == null) return void 0;
|
|
144
|
+
if (typeof value === "string") return resolveName(value, SORTING_FN_NAMES, "sortingFn", columnId, warn);
|
|
145
|
+
if (typeof value !== "function") return void 0;
|
|
146
|
+
const fn = value;
|
|
147
|
+
return (rowA, rowB, colId) => {
|
|
148
|
+
try {
|
|
149
|
+
return fn(rowA.getValue(colId), rowB.getValue(colId), rowA.original, rowB.original);
|
|
150
|
+
} catch (err) {
|
|
151
|
+
return 0;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
const columnRuleKeys = (spec, columnId, warn) => {
|
|
156
|
+
const out = {};
|
|
157
|
+
const f = resolveFilterFn(spec?.filterFn, columnId, warn);
|
|
158
|
+
if (f !== void 0) out.filterFn = f;
|
|
159
|
+
const s = resolveSortingFn(spec?.sortingFn, columnId, warn);
|
|
160
|
+
if (s !== void 0) out.sortingFn = s;
|
|
161
|
+
return out;
|
|
162
|
+
};
|
|
163
|
+
//#endregion
|
|
96
164
|
//#region src/helpers/indexMath.ts
|
|
97
165
|
const clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
|
|
98
166
|
const focusables = (cellEl) => {
|
|
@@ -101,6 +169,24 @@ const focusables = (cellEl) => {
|
|
|
101
169
|
};
|
|
102
170
|
const applyUpdater = (updater, current) => typeof updater === "function" ? updater(current) : updater;
|
|
103
171
|
//#endregion
|
|
172
|
+
//#region src/helpers/activeFollow.ts
|
|
173
|
+
function resolveFollow(prevIds, activeRow, nextIds, viewChangeOrWrite) {
|
|
174
|
+
if (!prevIds || !Number.isInteger(activeRow) || activeRow < 0 || activeRow >= prevIds.length) return { kind: "clamp" };
|
|
175
|
+
const id = prevIds[activeRow];
|
|
176
|
+
if (nextIds[activeRow] === id) return { kind: "stay" };
|
|
177
|
+
const index = nextIds.indexOf(id);
|
|
178
|
+
if (index >= 0) return {
|
|
179
|
+
kind: "move",
|
|
180
|
+
index
|
|
181
|
+
};
|
|
182
|
+
return viewChangeOrWrite ? { kind: "park" } : { kind: "clamp" };
|
|
183
|
+
}
|
|
184
|
+
function sameIdSequence(a, b) {
|
|
185
|
+
if (!a || a.length !== b.length) return false;
|
|
186
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
//#endregion
|
|
104
190
|
//#region src/helpers/tsvGrid.ts
|
|
105
191
|
const escapeTsvField = (s) => {
|
|
106
192
|
if (s.indexOf(" ") >= 0 || s.indexOf("\n") >= 0 || s.indexOf("\r") >= 0 || s.indexOf("\"") >= 0) return "\"" + s.replace(/"/g, "\"\"") + "\"";
|
|
@@ -236,6 +322,150 @@ const indexOfRowIn = (rows, rowOriginal, rowId) => {
|
|
|
236
322
|
return -1;
|
|
237
323
|
};
|
|
238
324
|
//#endregion
|
|
325
|
+
//#region src/helpers/heldView.ts
|
|
326
|
+
const CLEAN_VIEW_STATE = Object.freeze({
|
|
327
|
+
held: false,
|
|
328
|
+
filterMismatches: 0,
|
|
329
|
+
sortMismatches: 0
|
|
330
|
+
});
|
|
331
|
+
const viewStatesEqual = (a, b) => a.held === b.held && a.filterMismatches === b.filterMismatches && a.sortMismatches === b.sortMismatches;
|
|
332
|
+
const changedIndices = (prev, next) => {
|
|
333
|
+
const out = [];
|
|
334
|
+
if (prev.length !== next.length) {
|
|
335
|
+
const n = Math.max(prev.length, next.length);
|
|
336
|
+
for (let i = 0; i < n; i++) out.push(i);
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
for (let i = 0; i < next.length; i++) if (prev[i] !== next[i]) out.push(i);
|
|
340
|
+
return out;
|
|
341
|
+
};
|
|
342
|
+
const rowIds = (model) => (model?.rows ?? []).map((r) => r.id);
|
|
343
|
+
const createHoldController = () => {
|
|
344
|
+
let active = false;
|
|
345
|
+
let heldMembership = null;
|
|
346
|
+
let heldOrder = null;
|
|
347
|
+
const written = /* @__PURE__ */ new Set();
|
|
348
|
+
let version = 0;
|
|
349
|
+
let liveFilteredIds = /* @__PURE__ */ new Set();
|
|
350
|
+
let liveSortedIds = [];
|
|
351
|
+
const release = () => {
|
|
352
|
+
heldMembership = null;
|
|
353
|
+
heldOrder = null;
|
|
354
|
+
written.clear();
|
|
355
|
+
version++;
|
|
356
|
+
};
|
|
357
|
+
const wrapFiltered = (base) => (table) => {
|
|
358
|
+
const getBase = base(table);
|
|
359
|
+
let lastBase = void 0;
|
|
360
|
+
let lastVersion = -1;
|
|
361
|
+
let lastOut = void 0;
|
|
362
|
+
return () => {
|
|
363
|
+
const baseModel = getBase();
|
|
364
|
+
if (!heldMembership) return baseModel;
|
|
365
|
+
if (baseModel === lastBase && version === lastVersion) return lastOut;
|
|
366
|
+
liveFilteredIds = new Set(rowIds(baseModel));
|
|
367
|
+
const held = heldMembership;
|
|
368
|
+
const rows = table.getCoreRowModel().rows.filter((r) => held.has(r.id));
|
|
369
|
+
const rowsById = {};
|
|
370
|
+
for (const r of rows) rowsById[r.id] = r;
|
|
371
|
+
lastBase = baseModel;
|
|
372
|
+
lastVersion = version;
|
|
373
|
+
lastOut = {
|
|
374
|
+
rows,
|
|
375
|
+
flatRows: rows,
|
|
376
|
+
rowsById
|
|
377
|
+
};
|
|
378
|
+
return lastOut;
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
const wrapSorted = (base) => (table) => {
|
|
382
|
+
const getBase = base(table);
|
|
383
|
+
let lastBase = void 0;
|
|
384
|
+
let lastVersion = -1;
|
|
385
|
+
let lastOut = void 0;
|
|
386
|
+
return () => {
|
|
387
|
+
const baseModel = getBase();
|
|
388
|
+
if (!heldOrder) return baseModel;
|
|
389
|
+
if (baseModel === lastBase && version === lastVersion) return lastOut;
|
|
390
|
+
const baseRows = baseModel?.rows ?? [];
|
|
391
|
+
liveSortedIds = baseRows.map((r) => r.id);
|
|
392
|
+
const byId = /* @__PURE__ */ new Map();
|
|
393
|
+
for (const r of baseRows) byId.set(r.id, r);
|
|
394
|
+
const rows = [];
|
|
395
|
+
for (const id of heldOrder) {
|
|
396
|
+
const r = byId.get(id);
|
|
397
|
+
if (r) {
|
|
398
|
+
rows.push(r);
|
|
399
|
+
byId.delete(id);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
for (const r of baseRows) if (byId.has(r.id)) rows.push(r);
|
|
403
|
+
lastBase = baseModel;
|
|
404
|
+
lastVersion = version;
|
|
405
|
+
lastOut = {
|
|
406
|
+
rows,
|
|
407
|
+
flatRows: rows,
|
|
408
|
+
rowsById: baseModel?.rowsById ?? {}
|
|
409
|
+
};
|
|
410
|
+
return lastOut;
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
return {
|
|
414
|
+
setActive(next) {
|
|
415
|
+
const was = active;
|
|
416
|
+
active = !!next;
|
|
417
|
+
if (!active && was) release();
|
|
418
|
+
},
|
|
419
|
+
isActive: () => active,
|
|
420
|
+
isHolding: () => heldMembership !== null,
|
|
421
|
+
capture(table) {
|
|
422
|
+
if (!active || heldMembership) return;
|
|
423
|
+
const filtered = table.getFilteredRowModel();
|
|
424
|
+
const sorted = typeof table.getSortedRowModel === "function" ? table.getSortedRowModel() : filtered;
|
|
425
|
+
heldMembership = new Set(rowIds(filtered));
|
|
426
|
+
heldOrder = rowIds(sorted);
|
|
427
|
+
written.clear();
|
|
428
|
+
version++;
|
|
429
|
+
},
|
|
430
|
+
release,
|
|
431
|
+
noteWrite(prev, next) {
|
|
432
|
+
if (!heldMembership) return;
|
|
433
|
+
for (const i of changedIndices(prev, next)) written.add(i);
|
|
434
|
+
},
|
|
435
|
+
wrapFiltered,
|
|
436
|
+
wrapSorted,
|
|
437
|
+
viewState(table) {
|
|
438
|
+
if (!active) return CLEAN_VIEW_STATE;
|
|
439
|
+
if (!heldMembership || !heldOrder) return {
|
|
440
|
+
held: true,
|
|
441
|
+
filterMismatches: 0,
|
|
442
|
+
sortMismatches: 0
|
|
443
|
+
};
|
|
444
|
+
table.getSortedRowModel();
|
|
445
|
+
const held = heldMembership;
|
|
446
|
+
let filterMismatches = 0;
|
|
447
|
+
for (const id of held) if (!liveFilteredIds.has(id)) filterMismatches++;
|
|
448
|
+
const coreRows = table.getCoreRowModel().rows;
|
|
449
|
+
for (const r of coreRows) if (!held.has(r.id) && liveFilteredIds.has(r.id)) filterMismatches++;
|
|
450
|
+
const heldPos = /* @__PURE__ */ new Map();
|
|
451
|
+
heldOrder.forEach((id, i) => heldPos.set(id, i));
|
|
452
|
+
const livePos = /* @__PURE__ */ new Map();
|
|
453
|
+
liveSortedIds.forEach((id, i) => livePos.set(id, i));
|
|
454
|
+
let sortMismatches = 0;
|
|
455
|
+
for (const i of written) {
|
|
456
|
+
const id = coreRows[i]?.id;
|
|
457
|
+
if (id === void 0 || !heldPos.has(id)) continue;
|
|
458
|
+
if (heldPos.get(id) !== livePos.get(id)) sortMismatches++;
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
held: true,
|
|
462
|
+
filterMismatches,
|
|
463
|
+
sortMismatches
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
};
|
|
468
|
+
//#endregion
|
|
239
469
|
//#region src/DataTable.tsx
|
|
240
470
|
__rozieInjectStyle("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
|
|
241
471
|
--rdt-color: var(--rozie-data-table-fg, var(--rdt-ds-fg));
|
|
@@ -653,6 +883,7 @@ function DataTable(_props) {
|
|
|
653
883
|
singleClickEdit: false,
|
|
654
884
|
undoable: false,
|
|
655
885
|
undoLimit: 100,
|
|
886
|
+
holdView: false,
|
|
656
887
|
virtual: false,
|
|
657
888
|
estimateRowHeight: 40,
|
|
658
889
|
autoMeasure: false,
|
|
@@ -684,6 +915,7 @@ function DataTable(_props) {
|
|
|
684
915
|
"singleClickEdit",
|
|
685
916
|
"undoable",
|
|
686
917
|
"undoLimit",
|
|
918
|
+
"holdView",
|
|
687
919
|
"virtual",
|
|
688
920
|
"estimateRowHeight",
|
|
689
921
|
"autoMeasure",
|
|
@@ -706,6 +938,7 @@ function DataTable(_props) {
|
|
|
706
938
|
"onSelectionChange",
|
|
707
939
|
"onSortChange",
|
|
708
940
|
"onVisibilityChange",
|
|
941
|
+
"onViewStateChange",
|
|
709
942
|
"onVisibleRangeChange",
|
|
710
943
|
"groupBarSlot",
|
|
711
944
|
"selectAllSlot",
|
|
@@ -756,7 +989,9 @@ function DataTable(_props) {
|
|
|
756
989
|
redo,
|
|
757
990
|
canUndo,
|
|
758
991
|
canRedo,
|
|
759
|
-
clearHistory
|
|
992
|
+
clearHistory,
|
|
993
|
+
refreshView,
|
|
994
|
+
getViewState
|
|
760
995
|
});
|
|
761
996
|
});
|
|
762
997
|
const __ctx_data_table_columns = rozieContext("data-table:columns");
|
|
@@ -845,6 +1080,7 @@ function DataTable(_props) {
|
|
|
845
1080
|
columnOrder(),
|
|
846
1081
|
columnPinning(),
|
|
847
1082
|
local.selectionMode,
|
|
1083
|
+
local.holdView,
|
|
848
1084
|
(data() || []).length,
|
|
849
1085
|
data(),
|
|
850
1086
|
dataDefault(),
|
|
@@ -869,13 +1105,15 @@ function DataTable(_props) {
|
|
|
869
1105
|
onMount(() => {
|
|
870
1106
|
setDataDefault(data() || []);
|
|
871
1107
|
seedColumnPinning();
|
|
1108
|
+
const cols0 = tableColumns();
|
|
1109
|
+
lastColumnSig = columnSetSignature(cols0);
|
|
872
1110
|
table = createTable({
|
|
873
1111
|
data: feedData(),
|
|
874
|
-
columns:
|
|
1112
|
+
columns: cols0,
|
|
875
1113
|
state: currentState(),
|
|
876
1114
|
getCoreRowModel: getCoreRowModel(),
|
|
877
|
-
getSortedRowModel:
|
|
878
|
-
getFilteredRowModel:
|
|
1115
|
+
getSortedRowModel: heldSortedRowModel,
|
|
1116
|
+
getFilteredRowModel: heldFilteredRowModel,
|
|
879
1117
|
getPaginationRowModel: getPaginationRowModel(),
|
|
880
1118
|
getExpandedRowModel: getExpandedRowModel(),
|
|
881
1119
|
getSubRows: local.getSubRows || void 0,
|
|
@@ -910,6 +1148,21 @@ function DataTable(_props) {
|
|
|
910
1148
|
renderFallbackValue: null,
|
|
911
1149
|
onStateChange: () => {}
|
|
912
1150
|
});
|
|
1151
|
+
table.resetPageIndex = () => {
|
|
1152
|
+
if (!table) return;
|
|
1153
|
+
const pg = table.getState().pagination;
|
|
1154
|
+
writePagination({
|
|
1155
|
+
pageIndex: pg.pageIndex,
|
|
1156
|
+
pageSize: pg.pageSize
|
|
1157
|
+
});
|
|
1158
|
+
};
|
|
1159
|
+
const st0 = currentState();
|
|
1160
|
+
lastHoldSorting = st0.sorting;
|
|
1161
|
+
lastHoldColumnFilters = st0.columnFilters;
|
|
1162
|
+
lastHoldGlobalFilter = st0.globalFilter;
|
|
1163
|
+
lastPageGrouping = st0.grouping;
|
|
1164
|
+
syncHoldActive(st0);
|
|
1165
|
+
lastPropsData = data();
|
|
913
1166
|
refreshRowModel = () => {
|
|
914
1167
|
if (!table) return;
|
|
915
1168
|
const nextRows = windowSource().slice();
|
|
@@ -924,7 +1177,17 @@ function DataTable(_props) {
|
|
|
924
1177
|
}
|
|
925
1178
|
remeasureColumnWindow();
|
|
926
1179
|
const nextRowCount = nextRows.length;
|
|
927
|
-
|
|
1180
|
+
const nextColCount = nextRows.length ? nextRows[0].getVisibleCells().length : nextGroups.length ? (nextGroups[nextGroups.length - 1].headers || []).length : 0;
|
|
1181
|
+
const nextIds = nextRows.map((r) => r.id);
|
|
1182
|
+
const fedData = table.options.data;
|
|
1183
|
+
const dataChanged = fedData !== lastFedData;
|
|
1184
|
+
lastFedData = fedData;
|
|
1185
|
+
const viewChangeOrWrite = pendingViewChange || pendingWrite && dataChanged;
|
|
1186
|
+
const swapWithoutIds = dataChanged && !pendingWrite && !pendingViewChange && table.options.getRowId == null;
|
|
1187
|
+
pendingViewChange = false;
|
|
1188
|
+
if (dataChanged) pendingWrite = false;
|
|
1189
|
+
followActiveCell(swapWithoutIds ? null : prevRowIds, nextIds, viewChangeOrWrite, nextRowCount, nextColCount, pendingEditFollow != null);
|
|
1190
|
+
prevRowIds = nextIds;
|
|
928
1191
|
const pgState = table.getState().pagination;
|
|
929
1192
|
const pc = table.getPageCount();
|
|
930
1193
|
if (pc > 0 && pgState.pageIndex > pc - 1) writePagination({
|
|
@@ -940,6 +1203,11 @@ function DataTable(_props) {
|
|
|
940
1203
|
syncIndeterminate();
|
|
941
1204
|
if (typeof queueMicrotask !== "undefined") queueMicrotask(syncIndeterminate);
|
|
942
1205
|
else Promise.resolve().then(syncIndeterminate);
|
|
1206
|
+
const vs = holdCtrl.viewState(table);
|
|
1207
|
+
if (!viewStatesEqual(vs, lastViewState)) {
|
|
1208
|
+
lastViewState = vs;
|
|
1209
|
+
_props.onViewStateChange?.(vs);
|
|
1210
|
+
}
|
|
943
1211
|
};
|
|
944
1212
|
refreshRowModel();
|
|
945
1213
|
gridRoot = __rozieRootRef ? __rozieRootRef.querySelector(".rozie-data-table") : null;
|
|
@@ -1031,6 +1299,48 @@ function DataTable(_props) {
|
|
|
1031
1299
|
let undoStack = [];
|
|
1032
1300
|
let redoStack = [];
|
|
1033
1301
|
let restoringHistory = false;
|
|
1302
|
+
const holdCtrl = createHoldController();
|
|
1303
|
+
const heldFilteredRowModel = holdCtrl.wrapFiltered(getFilteredRowModel());
|
|
1304
|
+
const heldSortedRowModel = holdCtrl.wrapSorted(getSortedRowModel());
|
|
1305
|
+
let pendingViewChange = false;
|
|
1306
|
+
let pendingWrite = false;
|
|
1307
|
+
let prevRowIds = null;
|
|
1308
|
+
let lastFedData = null;
|
|
1309
|
+
let lastViewState = CLEAN_VIEW_STATE;
|
|
1310
|
+
let lastHoldSorting = null;
|
|
1311
|
+
let lastHoldColumnFilters = null;
|
|
1312
|
+
let lastHoldGlobalFilter = null;
|
|
1313
|
+
let holdFallbackWarned = false;
|
|
1314
|
+
let lastPageGrouping = null;
|
|
1315
|
+
let lastColumnSig = "";
|
|
1316
|
+
function columnSetSignature(defs) {
|
|
1317
|
+
let sig = "";
|
|
1318
|
+
const stack = (defs || []).slice().reverse();
|
|
1319
|
+
while (stack.length) {
|
|
1320
|
+
const d = stack.pop();
|
|
1321
|
+
if (!d) continue;
|
|
1322
|
+
sig += String(d.id) + (d.enableSorting ? "+" : "") + (d.enableColumnFilter ? "*" : "") + "|";
|
|
1323
|
+
if (Array.isArray(d.columns)) for (let i = d.columns.length - 1; i >= 0; i--) stack.push(d.columns[i]);
|
|
1324
|
+
}
|
|
1325
|
+
return sig;
|
|
1326
|
+
}
|
|
1327
|
+
let lastPropsData = null;
|
|
1328
|
+
function isExternalSwap() {
|
|
1329
|
+
const pd = data();
|
|
1330
|
+
if (pd === lastPropsData) return false;
|
|
1331
|
+
return !(pd != null && pd[DATA_WRITE_TOKEN_KEY] != null);
|
|
1332
|
+
}
|
|
1333
|
+
function syncHoldActive(st) {
|
|
1334
|
+
const wanted = local.holdView === true;
|
|
1335
|
+
const active = wanted && local.manual !== true && local.getSubRows == null && !(st.grouping || []).length;
|
|
1336
|
+
const wasHolding = holdCtrl.isHolding();
|
|
1337
|
+
holdCtrl.setActive(active);
|
|
1338
|
+
if (wasHolding && !holdCtrl.isHolding()) pendingViewChange = true;
|
|
1339
|
+
if (wanted && !active && !holdFallbackWarned) {
|
|
1340
|
+
holdFallbackWarned = true;
|
|
1341
|
+
console.warn("[rozie-data-table] holdView falls back to live behaviour while grouping is active, in manual mode, or with tree data (getSubRows); the view is not held.");
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1034
1344
|
let expandedTouched = false;
|
|
1035
1345
|
function groupingActiveDefault() {
|
|
1036
1346
|
return ((grouping() != null ? grouping() : groupingDefault()) || []).length > 0;
|
|
@@ -1164,6 +1474,7 @@ function DataTable(_props) {
|
|
|
1164
1474
|
expandable: c.expandable === true,
|
|
1165
1475
|
groupable: c.groupable !== false,
|
|
1166
1476
|
aggregationFn: wrapAggregationFn(c.aggregationFn),
|
|
1477
|
+
...columnRuleKeys(c, id),
|
|
1167
1478
|
pinned: c.pinned != null ? c.pinned : "",
|
|
1168
1479
|
width: c.width != null ? c.width : "",
|
|
1169
1480
|
...parseWidthToSize(c.width) != null ? { size: parseWidthToSize(c.width) } : {},
|
|
@@ -1207,6 +1518,7 @@ function DataTable(_props) {
|
|
|
1207
1518
|
expandable: spec.expandable === true,
|
|
1208
1519
|
groupable: spec.groupable !== false,
|
|
1209
1520
|
aggregationFn: wrapAggregationFn(spec.aggregationFn),
|
|
1521
|
+
...columnRuleKeys(spec, id),
|
|
1210
1522
|
pinned: spec.pinned != null ? spec.pinned : "",
|
|
1211
1523
|
width: spec.width != null ? spec.width : "",
|
|
1212
1524
|
...parseWidthToSize(spec.width) != null ? { size: parseWidthToSize(spec.width) } : {},
|
|
@@ -1363,6 +1675,9 @@ function DataTable(_props) {
|
|
|
1363
1675
|
recordSnapshot(currentData());
|
|
1364
1676
|
emitHistoryChangeIfEdged(prevU, prevR);
|
|
1365
1677
|
}
|
|
1678
|
+
if (table) holdCtrl.capture(table);
|
|
1679
|
+
holdCtrl.noteWrite(currentData() || [], Array.isArray(next) ? next : []);
|
|
1680
|
+
pendingWrite = true;
|
|
1366
1681
|
const fresh = Array.isArray(next) ? next.slice() : next;
|
|
1367
1682
|
try {
|
|
1368
1683
|
Object.defineProperty(fresh, DATA_WRITE_TOKEN_KEY, {
|
|
@@ -1986,13 +2301,60 @@ function DataTable(_props) {
|
|
|
1986
2301
|
if (local.selectionMode === "none") return false;
|
|
1987
2302
|
return lazyRowsActive() ? (row) => !rowIsLazyPlaceholder(row) : true;
|
|
1988
2303
|
}
|
|
2304
|
+
function writePaginationSoon(next) {
|
|
2305
|
+
if (!programmatic) {
|
|
2306
|
+
writePagination(next);
|
|
2307
|
+
return;
|
|
2308
|
+
}
|
|
2309
|
+
const run = () => writePagination(next);
|
|
2310
|
+
if (typeof queueMicrotask !== "undefined") queueMicrotask(run);
|
|
2311
|
+
else Promise.resolve().then(run);
|
|
2312
|
+
}
|
|
1989
2313
|
function reFeed() {
|
|
1990
2314
|
if (!table) return;
|
|
2315
|
+
const st0 = currentState();
|
|
2316
|
+
syncHoldActive(st0);
|
|
2317
|
+
let st = st0;
|
|
2318
|
+
let pageReset = null;
|
|
2319
|
+
const groupingChanged = st0.grouping !== lastPageGrouping;
|
|
2320
|
+
lastPageGrouping = st0.grouping;
|
|
2321
|
+
const viewChanged = st0.sorting !== lastHoldSorting || st0.columnFilters !== lastHoldColumnFilters || st0.globalFilter !== lastHoldGlobalFilter;
|
|
2322
|
+
if (viewChanged) {
|
|
2323
|
+
lastHoldSorting = st0.sorting;
|
|
2324
|
+
lastHoldColumnFilters = st0.columnFilters;
|
|
2325
|
+
lastHoldGlobalFilter = st0.globalFilter;
|
|
2326
|
+
holdCtrl.release();
|
|
2327
|
+
pendingViewChange = true;
|
|
2328
|
+
}
|
|
2329
|
+
if ((viewChanged || groupingChanged) && local.manual !== true && st0.pagination && st0.pagination.pageIndex !== 0) {
|
|
2330
|
+
pageReset = {
|
|
2331
|
+
pageIndex: 0,
|
|
2332
|
+
pageSize: st0.pagination.pageSize
|
|
2333
|
+
};
|
|
2334
|
+
st = {
|
|
2335
|
+
...st0,
|
|
2336
|
+
pagination: pageReset
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
const cols = tableColumns();
|
|
2340
|
+
const colSig = columnSetSignature(cols);
|
|
2341
|
+
if (colSig !== lastColumnSig) {
|
|
2342
|
+
lastColumnSig = colSig;
|
|
2343
|
+
st = {
|
|
2344
|
+
...st,
|
|
2345
|
+
sorting: [...st.sorting || []],
|
|
2346
|
+
columnFilters: [...st.columnFilters || []]
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
if (holdCtrl.isHolding() && isExternalSwap()) holdCtrl.release();
|
|
2350
|
+
if (pendingWrite && isExternalSwap()) pendingWrite = false;
|
|
1991
2351
|
table.setOptions((prev) => ({
|
|
1992
2352
|
...prev,
|
|
1993
2353
|
data: feedData(),
|
|
1994
|
-
columns:
|
|
1995
|
-
state:
|
|
2354
|
+
columns: cols,
|
|
2355
|
+
state: st,
|
|
2356
|
+
getFilteredRowModel: heldFilteredRowModel,
|
|
2357
|
+
getSortedRowModel: heldSortedRowModel,
|
|
1996
2358
|
enableRowSelection: rowSelectionOption(),
|
|
1997
2359
|
enableMultiRowSelection: local.selectionMode === "multiple",
|
|
1998
2360
|
rowCount: local.rowCount ?? void 0,
|
|
@@ -2020,15 +2382,19 @@ function DataTable(_props) {
|
|
|
2020
2382
|
onColumnSizingInfoChange: onColumnSizingInfoChangeCb
|
|
2021
2383
|
}));
|
|
2022
2384
|
if (refreshRowModel) refreshRowModel();
|
|
2385
|
+
if (pageReset) writePaginationSoon(pageReset);
|
|
2023
2386
|
}
|
|
2024
|
-
let lastPropsData = null;
|
|
2025
2387
|
function maybeClearHistoryOnExternalSwap() {
|
|
2026
2388
|
const pd = data();
|
|
2027
2389
|
if (pd === lastPropsData) return;
|
|
2028
2390
|
lastPropsData = pd;
|
|
2029
|
-
if (!local.undoable) return;
|
|
2030
2391
|
if (pd != null && pd[DATA_WRITE_TOKEN_KEY] != null) return;
|
|
2031
|
-
|
|
2392
|
+
pendingWrite = false;
|
|
2393
|
+
if (holdCtrl.isHolding()) {
|
|
2394
|
+
holdCtrl.release();
|
|
2395
|
+
if (refreshRowModel) refreshRowModel();
|
|
2396
|
+
}
|
|
2397
|
+
if (local.undoable) clearHistory();
|
|
2032
2398
|
}
|
|
2033
2399
|
let lastData = null;
|
|
2034
2400
|
let lastDataLen = -1;
|
|
@@ -2405,6 +2771,23 @@ function DataTable(_props) {
|
|
|
2405
2771
|
function cut() {
|
|
2406
2772
|
return cutRange();
|
|
2407
2773
|
}
|
|
2774
|
+
function refreshView() {
|
|
2775
|
+
holdCtrl.release();
|
|
2776
|
+
pendingViewChange = true;
|
|
2777
|
+
if (!table) return;
|
|
2778
|
+
table.setOptions((p) => ({
|
|
2779
|
+
...p,
|
|
2780
|
+
state: {
|
|
2781
|
+
...p.state,
|
|
2782
|
+
columnFilters: [...p.state.columnFilters || []],
|
|
2783
|
+
sorting: [...p.state.sorting || []]
|
|
2784
|
+
}
|
|
2785
|
+
}));
|
|
2786
|
+
if (refreshRowModel) refreshRowModel();
|
|
2787
|
+
}
|
|
2788
|
+
function getViewState() {
|
|
2789
|
+
return holdCtrl.viewState(table);
|
|
2790
|
+
}
|
|
2408
2791
|
function isGrid() {
|
|
2409
2792
|
return local.interactionMode === "grid";
|
|
2410
2793
|
}
|
|
@@ -2937,6 +3320,7 @@ function DataTable(_props) {
|
|
|
2937
3320
|
if (!tgt || !tgt.closest) return;
|
|
2938
3321
|
const cellEl = tgt.closest("[data-grid-cell]");
|
|
2939
3322
|
if (!cellEl) return;
|
|
3323
|
+
activeCellEngaged = true;
|
|
2940
3324
|
const rowAttr = cellEl.getAttribute("data-row");
|
|
2941
3325
|
const colAttr = cellEl.getAttribute("data-col-index");
|
|
2942
3326
|
if (rowAttr == null || colAttr == null) return;
|
|
@@ -3110,13 +3494,62 @@ function DataTable(_props) {
|
|
|
3110
3494
|
if (typeof requestAnimationFrame === "function") requestAnimationFrame(tryFocus);
|
|
3111
3495
|
else setTimeout(tryFocus, 0);
|
|
3112
3496
|
}
|
|
3113
|
-
function
|
|
3497
|
+
function followOpenEditors(prevIds, nextIds) {
|
|
3498
|
+
if (!prevIds || sameIdSequence(prevIds, nextIds)) return false;
|
|
3499
|
+
let owns = false;
|
|
3500
|
+
const er = editingRow();
|
|
3501
|
+
if (er >= 0) {
|
|
3502
|
+
const ef = resolveFollow(prevIds, er, nextIds, true);
|
|
3503
|
+
if (ef.kind === "move") {
|
|
3504
|
+
setEditingRow(ef.index);
|
|
3505
|
+
focusEditorWhenReady(ef.index, editingCol(), false);
|
|
3506
|
+
owns = true;
|
|
3507
|
+
} else if (ef.kind !== "stay") {
|
|
3508
|
+
committedThisSession = true;
|
|
3509
|
+
editTransition = true;
|
|
3510
|
+
endEdit();
|
|
3511
|
+
editTransition = false;
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
const rr = editingRowIndex();
|
|
3515
|
+
if (rr != null && rr >= 0) {
|
|
3516
|
+
const rf = resolveFollow(prevIds, rr, nextIds, true);
|
|
3517
|
+
if (rf.kind === "move") {
|
|
3518
|
+
setEditingRowIndex(rf.index);
|
|
3519
|
+
owns = true;
|
|
3520
|
+
} else if (rf.kind !== "stay") {
|
|
3521
|
+
editTransition = true;
|
|
3522
|
+
endRowEdit();
|
|
3523
|
+
editTransition = false;
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
return owns;
|
|
3527
|
+
}
|
|
3528
|
+
function rowIdInModel(index) {
|
|
3529
|
+
const row = windowSource()[index];
|
|
3530
|
+
return row ? row.id : null;
|
|
3531
|
+
}
|
|
3532
|
+
function modelIndexOfRowId(id) {
|
|
3533
|
+
const rows = windowSource();
|
|
3534
|
+
for (let i = 0; i < rows.length; i++) if (rows[i].id === id) return i;
|
|
3535
|
+
return -1;
|
|
3536
|
+
}
|
|
3537
|
+
function followActiveCell(prevIds, nextIds, viewChangeOrWrite, rowCount, colCount, editFollowPending = false) {
|
|
3538
|
+
const editorOwnsFocus = followOpenEditors(prevIds, nextIds);
|
|
3539
|
+
if (!isGrid()) return;
|
|
3540
|
+
let follow = null;
|
|
3541
|
+
if (activeCellEngaged && rowCount > 0 && !activeIsHeader() && !gridEmptyFallback) follow = resolveFollow(prevIds, activeRow(), nextIds, viewChangeOrWrite);
|
|
3542
|
+
clampActiveCell(rowCount, colCount, follow, editFollowPending || editorOwnsFocus, rowCount <= 0 && viewChangeOrWrite);
|
|
3543
|
+
if (viewChangeOrWrite && !sameIdSequence(prevIds, nextIds)) clearRange();
|
|
3544
|
+
}
|
|
3545
|
+
function clampActiveCell(rowCount, colCount, follow = null, editFollowPending = false, focusEmptyPark = false) {
|
|
3114
3546
|
if (!isGrid()) return;
|
|
3115
3547
|
const colN = colCount != null ? colCount : visibleColCount();
|
|
3116
3548
|
const rowN = rowCount != null ? rowCount : bodyRowCount();
|
|
3117
3549
|
let recoverFocus = false;
|
|
3118
3550
|
let doomedRow = -1;
|
|
3119
3551
|
let doomedCol = 0;
|
|
3552
|
+
let focusOnBody = false;
|
|
3120
3553
|
if (gridRoot) {
|
|
3121
3554
|
const rootNode = gridRoot.getRootNode ? gridRoot.getRootNode() : null;
|
|
3122
3555
|
const focusedEl = rootNode ? rootNode.activeElement : null;
|
|
@@ -3125,6 +3558,7 @@ function DataTable(_props) {
|
|
|
3125
3558
|
const fRowAttr = focusedCell.getAttribute("data-row");
|
|
3126
3559
|
const fColAttr = focusedCell.getAttribute("data-col-index");
|
|
3127
3560
|
if (fRowAttr != null && fRowAttr !== "__header") {
|
|
3561
|
+
focusOnBody = true;
|
|
3128
3562
|
const fr = parseInt(fRowAttr, 10);
|
|
3129
3563
|
const fc = parseInt(fColAttr, 10);
|
|
3130
3564
|
if (Number.isFinite(fr) && fr > rowN - 1) {
|
|
@@ -3144,6 +3578,7 @@ function DataTable(_props) {
|
|
|
3144
3578
|
setActiveColIndex(0);
|
|
3145
3579
|
gridEmptyFallback = true;
|
|
3146
3580
|
clampRange(rowN - 1, colN - 1);
|
|
3581
|
+
if (focusEmptyPark && (focusOnBody || editFollowPending)) recoverGridFocus("__header", 0, headerLeafLevel());
|
|
3147
3582
|
return;
|
|
3148
3583
|
}
|
|
3149
3584
|
if (gridEmptyFallback) {
|
|
@@ -3151,6 +3586,31 @@ function DataTable(_props) {
|
|
|
3151
3586
|
setActiveIsHeader(false);
|
|
3152
3587
|
setActiveRow(0);
|
|
3153
3588
|
}
|
|
3589
|
+
if (follow && follow.kind === "move") {
|
|
3590
|
+
const nextRow = follow.index;
|
|
3591
|
+
setActiveRow(nextRow);
|
|
3592
|
+
clampRange(rowN - 1, colN - 1);
|
|
3593
|
+
_props.onActivecellChange?.({
|
|
3594
|
+
rowIndex: toAbsRow(nextRow),
|
|
3595
|
+
colIndex: col,
|
|
3596
|
+
isHeader: false
|
|
3597
|
+
});
|
|
3598
|
+
if (focusOnBody && !editFollowPending) focusCellWhenReady(nextRow, col);
|
|
3599
|
+
return;
|
|
3600
|
+
}
|
|
3601
|
+
if (follow && follow.kind === "park") {
|
|
3602
|
+
const level = headerLeafLevel();
|
|
3603
|
+
setActiveIsHeader(true);
|
|
3604
|
+
setActiveHeaderLevel(level);
|
|
3605
|
+
clampRange(rowN - 1, colN - 1);
|
|
3606
|
+
_props.onActivecellChange?.({
|
|
3607
|
+
rowIndex: null,
|
|
3608
|
+
colIndex: col,
|
|
3609
|
+
isHeader: true
|
|
3610
|
+
});
|
|
3611
|
+
if (focusOnBody || editFollowPending) recoverGridFocus("__header", col, level);
|
|
3612
|
+
return;
|
|
3613
|
+
}
|
|
3154
3614
|
if (!activeIsHeader()) {
|
|
3155
3615
|
const lastRow = rowN - 1;
|
|
3156
3616
|
const maxRow = lastRow < 0 ? 0 : lastRow;
|
|
@@ -3216,6 +3676,7 @@ function DataTable(_props) {
|
|
|
3216
3676
|
colVirtualizer._willUpdate();
|
|
3217
3677
|
}
|
|
3218
3678
|
let gridEmptyFallback = false;
|
|
3679
|
+
let activeCellEngaged = false;
|
|
3219
3680
|
let rangeTransition = false;
|
|
3220
3681
|
let rangeClickPending = null;
|
|
3221
3682
|
let rangeActive = false;
|
|
@@ -3936,6 +4397,7 @@ function DataTable(_props) {
|
|
|
3936
4397
|
const colId = columnIdAt(rowIndex, colIndex);
|
|
3937
4398
|
if (colId == null || !columnEditable(colId)) return;
|
|
3938
4399
|
committedThisSession = false;
|
|
4400
|
+
outsidePointerDown = false;
|
|
3939
4401
|
setInvalid("");
|
|
3940
4402
|
setEditingRowIndex(null);
|
|
3941
4403
|
setRowDraft({});
|
|
@@ -4386,12 +4848,14 @@ function DataTable(_props) {
|
|
|
4386
4848
|
const fromRow = editingRow();
|
|
4387
4849
|
const fromCol = editingCol();
|
|
4388
4850
|
const target = e.shiftKey ? prevEditableCell(fromRow, fromCol) : nextEditableCell(fromRow, fromCol);
|
|
4851
|
+
const targetRowId = target ? rowIdInModel(target.row) : null;
|
|
4389
4852
|
const committed = commitEdit(void 0, true);
|
|
4390
|
-
|
|
4391
|
-
|
|
4853
|
+
const advanceRow = targetRowId != null ? modelIndexOfRowId(targetRowId) : -1;
|
|
4854
|
+
if (committed && target && advanceRow >= 0) {
|
|
4855
|
+
setActiveRow(advanceRow);
|
|
4392
4856
|
setActiveColIndex(target.col);
|
|
4393
|
-
beginEdit(
|
|
4394
|
-
} else if (committed) focusCellWhenReady(fromRow, fromCol);
|
|
4857
|
+
beginEdit(advanceRow, target.col, null);
|
|
4858
|
+
} else if (committed && target) {} else if (committed) focusCellWhenReady(fromRow, fromCol);
|
|
4395
4859
|
} else if (key === "Escape") {
|
|
4396
4860
|
e.preventDefault();
|
|
4397
4861
|
cancelEdit();
|
|
@@ -5479,6 +5943,8 @@ function Column(_props) {
|
|
|
5479
5943
|
expandable: false,
|
|
5480
5944
|
groupable: true,
|
|
5481
5945
|
aggregationFn: null,
|
|
5946
|
+
filterFn: null,
|
|
5947
|
+
sortingFn: null,
|
|
5482
5948
|
editable: false,
|
|
5483
5949
|
editor: "text",
|
|
5484
5950
|
editorOptions: [],
|
|
@@ -5494,6 +5960,8 @@ function Column(_props) {
|
|
|
5494
5960
|
"expandable",
|
|
5495
5961
|
"groupable",
|
|
5496
5962
|
"aggregationFn",
|
|
5963
|
+
"filterFn",
|
|
5964
|
+
"sortingFn",
|
|
5497
5965
|
"editable",
|
|
5498
5966
|
"editor",
|
|
5499
5967
|
"editorOptions",
|
|
@@ -5511,11 +5979,15 @@ function Column(_props) {
|
|
|
5511
5979
|
local.expandable,
|
|
5512
5980
|
local.groupable,
|
|
5513
5981
|
local.aggregationFn,
|
|
5982
|
+
local.filterFn,
|
|
5983
|
+
local.sortingFn,
|
|
5514
5984
|
local.editable,
|
|
5515
5985
|
local.editor,
|
|
5516
5986
|
local.editorOptions,
|
|
5517
5987
|
local.validate
|
|
5518
5988
|
], (v) => untrack(() => (() => {
|
|
5989
|
+
latestFilterFn = local.filterFn;
|
|
5990
|
+
latestSortingFn = local.sortingFn;
|
|
5519
5991
|
if (reg) reg.registerColumn(colId(), buildSpec());
|
|
5520
5992
|
})()), { defer: true }));
|
|
5521
5993
|
onMount(() => {
|
|
@@ -5541,10 +6013,21 @@ function Column(_props) {
|
|
|
5541
6013
|
let reg = null;
|
|
5542
6014
|
reg = registry;
|
|
5543
6015
|
let registered = false;
|
|
6016
|
+
let latestFilterFn = null;
|
|
6017
|
+
let latestSortingFn = null;
|
|
6018
|
+
const filterTrampoline = Object.assign((...args) => typeof latestFilterFn === "function" ? latestFilterFn(...args) : true, {
|
|
6019
|
+
autoRemove: (value, column) => typeof latestFilterFn === "function" && typeof latestFilterFn.autoRemove === "function" ? latestFilterFn.autoRemove(value, column) : false,
|
|
6020
|
+
resolveFilterValue: (value) => typeof latestFilterFn === "function" && typeof latestFilterFn.resolveFilterValue === "function" ? latestFilterFn.resolveFilterValue(value) : value
|
|
6021
|
+
});
|
|
6022
|
+
function sortingTrampoline(...args) {
|
|
6023
|
+
return typeof latestSortingFn === "function" ? latestSortingFn(...args) : 0;
|
|
6024
|
+
}
|
|
5544
6025
|
function colId() {
|
|
5545
6026
|
return local.id !== "" ? local.id : local.field;
|
|
5546
6027
|
}
|
|
5547
6028
|
function buildSpec() {
|
|
6029
|
+
latestFilterFn = local.filterFn;
|
|
6030
|
+
latestSortingFn = local.sortingFn;
|
|
5548
6031
|
return {
|
|
5549
6032
|
id: colId(),
|
|
5550
6033
|
field: local.field !== "" ? local.field : colId(),
|
|
@@ -5556,6 +6039,8 @@ function Column(_props) {
|
|
|
5556
6039
|
expandable: local.expandable,
|
|
5557
6040
|
groupable: local.groupable,
|
|
5558
6041
|
aggregationFn: local.aggregationFn,
|
|
6042
|
+
filterFn: typeof local.filterFn === "function" ? filterTrampoline : local.filterFn,
|
|
6043
|
+
sortingFn: typeof local.sortingFn === "function" ? sortingTrampoline : local.sortingFn,
|
|
5559
6044
|
editable: local.editable,
|
|
5560
6045
|
editor: local.editor,
|
|
5561
6046
|
editorOptions: local.editorOptions,
|