@rozie-ui/data-table-solid 0.7.3 → 0.8.0

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/dist/index.cjs CHANGED
@@ -121,6 +121,74 @@ const columnSpecsEquivalent = (a, b, depth) => {
121
121
  return true;
122
122
  };
123
123
  //#endregion
124
+ //#region src/helpers/columnRuleUtils.ts
125
+ const FILTER_FN_NAMES = [
126
+ "includesString",
127
+ "includesStringSensitive",
128
+ "equalsString",
129
+ "arrIncludes",
130
+ "arrIncludesAll",
131
+ "arrIncludesSome",
132
+ "equals",
133
+ "weakEquals",
134
+ "inNumberRange"
135
+ ];
136
+ const SORTING_FN_NAMES = [
137
+ "alphanumeric",
138
+ "alphanumericCaseSensitive",
139
+ "text",
140
+ "textCaseSensitive",
141
+ "datetime",
142
+ "basic"
143
+ ];
144
+ const warned = /* @__PURE__ */ new Set();
145
+ const resolveName = (value, names, kind, columnId, warn) => {
146
+ if (value === "auto" || names.includes(value)) return value;
147
+ const key = kind + "\0" + columnId + "\0" + value;
148
+ if (!warned.has(key)) {
149
+ warned.add(key);
150
+ warn(`[data-table] column "${columnId}": unknown ${kind} "${value}"; falling back to "auto".`);
151
+ }
152
+ return "auto";
153
+ };
154
+ const resolveFilterFn = (value, columnId, warn = console.warn) => {
155
+ if (value == null) return void 0;
156
+ if (typeof value === "string") return resolveName(value, FILTER_FN_NAMES, "filterFn", columnId, warn);
157
+ if (typeof value !== "function") return void 0;
158
+ const fn = value;
159
+ const adapter = (row, colId, filterValue) => {
160
+ try {
161
+ return fn(row.getValue(colId), filterValue, row.original);
162
+ } catch (err) {
163
+ return true;
164
+ }
165
+ };
166
+ if (fn.autoRemove !== void 0) adapter.autoRemove = fn.autoRemove;
167
+ if (fn.resolveFilterValue !== void 0) adapter.resolveFilterValue = fn.resolveFilterValue;
168
+ return adapter;
169
+ };
170
+ const resolveSortingFn = (value, columnId, warn = console.warn) => {
171
+ if (value == null) return void 0;
172
+ if (typeof value === "string") return resolveName(value, SORTING_FN_NAMES, "sortingFn", columnId, warn);
173
+ if (typeof value !== "function") return void 0;
174
+ const fn = value;
175
+ return (rowA, rowB, colId) => {
176
+ try {
177
+ return fn(rowA.getValue(colId), rowB.getValue(colId), rowA.original, rowB.original);
178
+ } catch (err) {
179
+ return 0;
180
+ }
181
+ };
182
+ };
183
+ const columnRuleKeys = (spec, columnId, warn) => {
184
+ const out = {};
185
+ const f = resolveFilterFn(spec?.filterFn, columnId, warn);
186
+ if (f !== void 0) out.filterFn = f;
187
+ const s = resolveSortingFn(spec?.sortingFn, columnId, warn);
188
+ if (s !== void 0) out.sortingFn = s;
189
+ return out;
190
+ };
191
+ //#endregion
124
192
  //#region src/helpers/indexMath.ts
125
193
  const clamp = (v, lo, hi) => v < lo ? lo : v > hi ? hi : v;
126
194
  const focusables = (cellEl) => {
@@ -129,6 +197,24 @@ const focusables = (cellEl) => {
129
197
  };
130
198
  const applyUpdater = (updater, current) => typeof updater === "function" ? updater(current) : updater;
131
199
  //#endregion
200
+ //#region src/helpers/activeFollow.ts
201
+ function resolveFollow(prevIds, activeRow, nextIds, viewChangeOrWrite) {
202
+ if (!prevIds || !Number.isInteger(activeRow) || activeRow < 0 || activeRow >= prevIds.length) return { kind: "clamp" };
203
+ const id = prevIds[activeRow];
204
+ if (nextIds[activeRow] === id) return { kind: "stay" };
205
+ const index = nextIds.indexOf(id);
206
+ if (index >= 0) return {
207
+ kind: "move",
208
+ index
209
+ };
210
+ return viewChangeOrWrite ? { kind: "park" } : { kind: "clamp" };
211
+ }
212
+ function sameIdSequence(a, b) {
213
+ if (!a || a.length !== b.length) return false;
214
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
215
+ return true;
216
+ }
217
+ //#endregion
132
218
  //#region src/helpers/tsvGrid.ts
133
219
  const escapeTsvField = (s) => {
134
220
  if (s.indexOf(" ") >= 0 || s.indexOf("\n") >= 0 || s.indexOf("\r") >= 0 || s.indexOf("\"") >= 0) return "\"" + s.replace(/"/g, "\"\"") + "\"";
@@ -264,9 +350,153 @@ const indexOfRowIn = (rows, rowOriginal, rowId) => {
264
350
  return -1;
265
351
  };
266
352
  //#endregion
353
+ //#region src/helpers/heldView.ts
354
+ const CLEAN_VIEW_STATE = Object.freeze({
355
+ held: false,
356
+ filterMismatches: 0,
357
+ sortMismatches: 0
358
+ });
359
+ const viewStatesEqual = (a, b) => a.held === b.held && a.filterMismatches === b.filterMismatches && a.sortMismatches === b.sortMismatches;
360
+ const changedIndices = (prev, next) => {
361
+ const out = [];
362
+ if (prev.length !== next.length) {
363
+ const n = Math.max(prev.length, next.length);
364
+ for (let i = 0; i < n; i++) out.push(i);
365
+ return out;
366
+ }
367
+ for (let i = 0; i < next.length; i++) if (prev[i] !== next[i]) out.push(i);
368
+ return out;
369
+ };
370
+ const rowIds = (model) => (model?.rows ?? []).map((r) => r.id);
371
+ const createHoldController = () => {
372
+ let active = false;
373
+ let heldMembership = null;
374
+ let heldOrder = null;
375
+ const written = /* @__PURE__ */ new Set();
376
+ let version = 0;
377
+ let liveFilteredIds = /* @__PURE__ */ new Set();
378
+ let liveSortedIds = [];
379
+ const release = () => {
380
+ heldMembership = null;
381
+ heldOrder = null;
382
+ written.clear();
383
+ version++;
384
+ };
385
+ const wrapFiltered = (base) => (table) => {
386
+ const getBase = base(table);
387
+ let lastBase = void 0;
388
+ let lastVersion = -1;
389
+ let lastOut = void 0;
390
+ return () => {
391
+ const baseModel = getBase();
392
+ if (!heldMembership) return baseModel;
393
+ if (baseModel === lastBase && version === lastVersion) return lastOut;
394
+ liveFilteredIds = new Set(rowIds(baseModel));
395
+ const held = heldMembership;
396
+ const rows = table.getCoreRowModel().rows.filter((r) => held.has(r.id));
397
+ const rowsById = {};
398
+ for (const r of rows) rowsById[r.id] = r;
399
+ lastBase = baseModel;
400
+ lastVersion = version;
401
+ lastOut = {
402
+ rows,
403
+ flatRows: rows,
404
+ rowsById
405
+ };
406
+ return lastOut;
407
+ };
408
+ };
409
+ const wrapSorted = (base) => (table) => {
410
+ const getBase = base(table);
411
+ let lastBase = void 0;
412
+ let lastVersion = -1;
413
+ let lastOut = void 0;
414
+ return () => {
415
+ const baseModel = getBase();
416
+ if (!heldOrder) return baseModel;
417
+ if (baseModel === lastBase && version === lastVersion) return lastOut;
418
+ const baseRows = baseModel?.rows ?? [];
419
+ liveSortedIds = baseRows.map((r) => r.id);
420
+ const byId = /* @__PURE__ */ new Map();
421
+ for (const r of baseRows) byId.set(r.id, r);
422
+ const rows = [];
423
+ for (const id of heldOrder) {
424
+ const r = byId.get(id);
425
+ if (r) {
426
+ rows.push(r);
427
+ byId.delete(id);
428
+ }
429
+ }
430
+ for (const r of baseRows) if (byId.has(r.id)) rows.push(r);
431
+ lastBase = baseModel;
432
+ lastVersion = version;
433
+ lastOut = {
434
+ rows,
435
+ flatRows: rows,
436
+ rowsById: baseModel?.rowsById ?? {}
437
+ };
438
+ return lastOut;
439
+ };
440
+ };
441
+ return {
442
+ setActive(next) {
443
+ const was = active;
444
+ active = !!next;
445
+ if (!active && was) release();
446
+ },
447
+ isActive: () => active,
448
+ isHolding: () => heldMembership !== null,
449
+ capture(table) {
450
+ if (!active || heldMembership) return;
451
+ const filtered = table.getFilteredRowModel();
452
+ const sorted = typeof table.getSortedRowModel === "function" ? table.getSortedRowModel() : filtered;
453
+ heldMembership = new Set(rowIds(filtered));
454
+ heldOrder = rowIds(sorted);
455
+ written.clear();
456
+ version++;
457
+ },
458
+ release,
459
+ noteWrite(prev, next) {
460
+ if (!heldMembership) return;
461
+ for (const i of changedIndices(prev, next)) written.add(i);
462
+ },
463
+ wrapFiltered,
464
+ wrapSorted,
465
+ viewState(table) {
466
+ if (!active) return CLEAN_VIEW_STATE;
467
+ if (!heldMembership || !heldOrder) return {
468
+ held: true,
469
+ filterMismatches: 0,
470
+ sortMismatches: 0
471
+ };
472
+ table.getSortedRowModel();
473
+ const held = heldMembership;
474
+ let filterMismatches = 0;
475
+ for (const id of held) if (!liveFilteredIds.has(id)) filterMismatches++;
476
+ const coreRows = table.getCoreRowModel().rows;
477
+ for (const r of coreRows) if (!held.has(r.id) && liveFilteredIds.has(r.id)) filterMismatches++;
478
+ const heldPos = /* @__PURE__ */ new Map();
479
+ heldOrder.forEach((id, i) => heldPos.set(id, i));
480
+ const livePos = /* @__PURE__ */ new Map();
481
+ liveSortedIds.forEach((id, i) => livePos.set(id, i));
482
+ let sortMismatches = 0;
483
+ for (const i of written) {
484
+ const id = coreRows[i]?.id;
485
+ if (id === void 0 || !heldPos.has(id)) continue;
486
+ if (heldPos.get(id) !== livePos.get(id)) sortMismatches++;
487
+ }
488
+ return {
489
+ held: true,
490
+ filterMismatches,
491
+ sortMismatches
492
+ };
493
+ }
494
+ };
495
+ };
496
+ //#endregion
267
497
  //#region src/DataTable.tsx
268
498
  var _tmpl$$11 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rozie-data-table-wrap data-rozie-s-d5dcab4c=""><div class=rdt-column-defs aria-hidden=true data-rozie-s-d5dcab4c=""></div><div class=rdt-toolbar data-rozie-s-d5dcab4c=""><input type=text role=searchbox aria-label="Search table"class=rdt-global-filter data-rozie-s-d5dcab4c="">`), _tmpl$2$4 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-sr-live role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$3$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class="rdt-sr-live rdt-sr-paste"data-testid=paste-announce role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$4$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class="rdt-sr-live rdt-sr-range"data-testid=range-announce role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$5$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class="rdt-sr-live rdt-sr-sortfilter"data-testid=sortfilter-announce role=status aria-live=polite aria-atomic=true data-rozie-s-d5dcab4c="">`), _tmpl$6 = /* @__PURE__ */ (0, solid_js_web.template)(`<details class=rdt-colvis data-rozie-s-d5dcab4c=""><summary class=rdt-colvis-summary data-rozie-s-d5dcab4c="">Columns</summary><div class=rdt-colvis-menu role=group aria-label="Toggle columns"data-rozie-s-d5dcab4c="">`), _tmpl$7 = /* @__PURE__ */ (0, solid_js_web.template)(`<label class=rdt-colvis-item data-rozie-s-d5dcab4c=""><input type=checkbox class=rdt-colvis-checkbox data-rozie-s-d5dcab4c=""><span class=rdt-colvis-label data-rozie-s-d5dcab4c="">`), _tmpl$8 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-group-bar-host data-rozie-s-d5dcab4c="">`), _tmpl$9 = /* @__PURE__ */ (0, solid_js_web.template)(`<span class=rdt-group-token data-group-token=""data-rozie-s-d5dcab4c="">`), _tmpl$0 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-scroll data-rozie-s-d5dcab4c=""><table data-rozie-s-d5dcab4c=""><thead class=rdt-thead role=rowgroup data-rozie-s-d5dcab4c=""></thead><tbody class=rdt-tbody role=rowgroup data-rozie-s-d5dcab4c=""><tr class=rdt-spacer aria-hidden=true data-rozie-s-d5dcab4c=""><td data-rozie-s-d5dcab4c=""></td></tr><tr class=rdt-spacer aria-hidden=true data-rozie-s-d5dcab4c=""><td data-rozie-s-d5dcab4c="">`), _tmpl$1 = /* @__PURE__ */ (0, solid_js_web.template)(`<table data-rozie-s-d5dcab4c=""><thead class=rdt-thead role=rowgroup data-rozie-s-d5dcab4c=""></thead><tbody class=rdt-tbody role=rowgroup data-rozie-s-d5dcab4c="">`), _tmpl$10 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr class=rdt-tr role=row data-rozie-s-d5dcab4c="">`), _tmpl$11 = /* @__PURE__ */ (0, solid_js_web.template)(`<th role=columnheader data-grid-cell=""data-row=__header data-rozie-s-d5dcab4c="">`), _tmpl$12 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c="">`), _tmpl$13 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-col-menu role=menu data-rozie-s-d5dcab4c=""><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Pin left</button><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Pin right</button><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Unpin</button><hr class=rdt-col-menu-sep data-rozie-s-d5dcab4c=""><button type=button role=menuitem class=rdt-col-menu-item data-rozie-s-d5dcab4c="">Hide column`), _tmpl$14 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><button type=button class=rdt-resize-handle data-rozie-s-d5dcab4c=""><span class=rdt-resize-grip aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$15 = /* @__PURE__ */ (0, solid_js_web.template)(`<button type=button class=rdt-sort-btn data-rozie-s-d5dcab4c=""><span class=rdt-header-label data-rozie-s-d5dcab4c=""></span><span class=rdt-sort-ind aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$16 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><span class=rdt-header-label data-rozie-s-d5dcab4c="">`), _tmpl$17 = /* @__PURE__ */ (0, solid_js_web.template)(`<button type=button class=rdt-col-menu-trigger data-rozie-s-d5dcab4c="">⋯`), _tmpl$18 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=checkbox aria-label="Select all rows"class=rdt-select-all data-rozie-s-d5dcab4c="">`), _tmpl$19 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr class=rdt-filter-row data-rozie-s-d5dcab4c="">`), _tmpl$20 = /* @__PURE__ */ (0, solid_js_web.template)(`<th role=presentation data-rozie-s-d5dcab4c="">`), _tmpl$21 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=text class=rdt-col-filter data-rozie-s-d5dcab4c="">`), _tmpl$22 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr role=row data-rozie-s-d5dcab4c="">`), _tmpl$23 = /* @__PURE__ */ (0, solid_js_web.template)(`<td data-grid-cell=""data-rozie-s-d5dcab4c="">`), _tmpl$24 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><button type=button data-expander=""class="rdt-expander rdt-group-toggle"data-rozie-s-d5dcab4c=""></button><span class=rdt-group-value data-rozie-s-d5dcab4c=""></span><span class=rdt-group-count data-rozie-s-d5dcab4c="">`), _tmpl$25 = /* @__PURE__ */ (0, solid_js_web.template)(`<span class=rdt-cell-value data-rozie-s-d5dcab4c="">`), _tmpl$26 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=number data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$27 = /* @__PURE__ */ (0, solid_js_web.template)(`<select data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$28 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=checkbox data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$29 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=text data-editing-cell=""data-builtin-editor=""class=rdt-cell-editor data-rozie-s-d5dcab4c="">`), _tmpl$30 = /* @__PURE__ */ (0, solid_js_web.template)(`<option data-rozie-s-d5dcab4c="">`), _tmpl$31 = /* @__PURE__ */ (0, solid_js_web.template)(`<input type=checkbox aria-label="Select row"class=rdt-select-row data-rozie-s-d5dcab4c="">`), _tmpl$32 = /* @__PURE__ */ (0, solid_js_web.template)(`<button type=button data-expander=""class=rdt-expander data-rozie-s-d5dcab4c="">`), _tmpl$33 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-fill-handle=""data-testid=fill-handle aria-hidden=true class=rdt-fill-handle data-rozie-s-d5dcab4c="">`), _tmpl$34 = /* @__PURE__ */ (0, solid_js_web.template)(`<tr class=rdt-detail-row role=row data-rozie-s-d5dcab4c=""><td class=rdt-detail-cell data-rozie-s-d5dcab4c="">`), _tmpl$35 = /* @__PURE__ */ (0, solid_js_web.template)(`<th class=rdt-col-spacer aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$36 = /* @__PURE__ */ (0, solid_js_web.template)(`<td class=rdt-col-spacer aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$37 = /* @__PURE__ */ (0, solid_js_web.template)(`<span data-rozie-s-d5dcab4c=""><input class=rdt-select-placeholder type=checkbox tabindex=-1 aria-hidden=true data-rozie-s-d5dcab4c="">`), _tmpl$38 = /* @__PURE__ */ (0, solid_js_web.template)(`<span class=rdt-skeleton aria-hidden=true data-rozie-s-d5dcab4c="">&#8203;`), _tmpl$39 = /* @__PURE__ */ (0, solid_js_web.template)(`<div class=rdt-pagination role=group aria-label=Pagination data-rozie-s-d5dcab4c=""><button type=button class="rdt-page-btn rdt-page-prev"data-rozie-s-d5dcab4c="">Prev</button><span class=rdt-page-status aria-live=polite data-rozie-s-d5dcab4c=""></span><button type=button class="rdt-page-btn rdt-page-next"data-rozie-s-d5dcab4c="">Next</button><select aria-label="Rows per page"class=rdt-page-size data-rozie-s-d5dcab4c=""><option value=10 data-rozie-s-d5dcab4c="">10</option><option value=25 data-rozie-s-d5dcab4c="">25</option><option value=50 data-rozie-s-d5dcab4c="">50</option><option value=100 data-rozie-s-d5dcab4c="">100`);
269
- /** A cell position as integers over the visible (display-order) model. */ /** The active (roving-focus) cell. A header cell reports `rowIndex: null` and `isHeader: true`. */ /** The rectangular cell-range selection. Both corners are `null` when there is no range. */ /** One data column offered to the `#groupBar` slot. */ /** One changed cell inside a row edit commit. */ /** The `activecell-change` payload. `isHeader` is set when the move landed on or left a header cell. */ /** The `cell-edit-commit` payload: one committed cell. */ /** The `row-edit-commit` payload: the row and every cell the save changed. */ /** The `filter-change` payload: `globalFilter` for the search box, `columnFilters` for a per-column filter. Exactly one key is set. */ /** The `history-change` payload: undo/redo availability. */ /** The `range-change` payload: the new range corners (both `null` when the range cleared). */ /** The `row-activate` payload. `row` is the original data object and `index` its position in the rendered model. */ /** The `visible-range-change` payload: the rendered row window, `end` exclusive. */ (0, _rozie_runtime_solid.__rozieInjectStyle)("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
499
+ /** A cell position as integers over the visible (display-order) model. */ /** The active (roving-focus) cell. A header cell reports `rowIndex: null` and `isHeader: true`. */ /** The rectangular cell-range selection. Both corners are `null` when there is no range. */ /** One data column offered to the `#groupBar` slot. */ /** One changed cell inside a row edit commit. */ /** The `activecell-change` payload. `isHeader` is set when the move landed on or left a header cell. */ /** The `cell-edit-commit` payload: one committed cell. */ /** The `row-edit-commit` payload: the row and every cell the save changed. */ /** The `filter-change` payload: `globalFilter` for the search box, `columnFilters` for a per-column filter. Exactly one key is set. */ /** The `history-change` payload: undo/redo availability. */ /** The held-view state (`holdView`): whether the view is held right now, and how many rows the held view disagrees with. */ /** The `range-change` payload: the new range corners (both `null` when the range cleared). */ /** The `row-activate` payload. `row` is the original data object and `index` its position in the rendered model. */ /** The `visible-range-change` payload: the rendered row window, `end` exclusive. */ (0, _rozie_runtime_solid.__rozieInjectStyle)("DataTable-d5dcab4c", `[data-rozie-s-d5dcab4c]:host {
270
500
  --rdt-color: var(--rozie-data-table-fg, var(--rdt-ds-fg));
271
501
  --rdt-select-accent: var(--rozie-data-table-select-accent, var(--rozie-data-table-accent, var(--rdt-ds-select-accent)));
272
502
  --rdt-border: 1px solid var(--rozie-data-table-border-color, var(--rdt-ds-border-color));
@@ -682,6 +912,7 @@ function DataTable(_props) {
682
912
  singleClickEdit: false,
683
913
  undoable: false,
684
914
  undoLimit: 100,
915
+ holdView: false,
685
916
  virtual: false,
686
917
  estimateRowHeight: 40,
687
918
  autoMeasure: false,
@@ -713,6 +944,7 @@ function DataTable(_props) {
713
944
  "singleClickEdit",
714
945
  "undoable",
715
946
  "undoLimit",
947
+ "holdView",
716
948
  "virtual",
717
949
  "estimateRowHeight",
718
950
  "autoMeasure",
@@ -735,6 +967,7 @@ function DataTable(_props) {
735
967
  "onSelectionChange",
736
968
  "onSortChange",
737
969
  "onVisibilityChange",
970
+ "onViewStateChange",
738
971
  "onVisibleRangeChange",
739
972
  "groupBarSlot",
740
973
  "selectAllSlot",
@@ -785,7 +1018,9 @@ function DataTable(_props) {
785
1018
  redo,
786
1019
  canUndo,
787
1020
  canRedo,
788
- clearHistory
1021
+ clearHistory,
1022
+ refreshView,
1023
+ getViewState
789
1024
  });
790
1025
  });
791
1026
  const __ctx_data_table_columns = (0, _rozie_runtime_solid.rozieContext)("data-table:columns");
@@ -856,16 +1091,58 @@ function DataTable(_props) {
856
1091
  const [pasteAnnounce, setPasteAnnounce] = (0, solid_js.createSignal)("");
857
1092
  const [rangeAnnounce, setRangeAnnounce] = (0, solid_js.createSignal)("");
858
1093
  const [liveAnnounce, setLiveAnnounce] = (0, solid_js.createSignal)("");
1094
+ (0, solid_js.createEffect)((0, solid_js.on)(() => windowVer(), (v) => (0, solid_js.untrack)(() => emitVisibleRangeIfChanged()), { defer: true }));
1095
+ (0, solid_js.createEffect)((0, solid_js.on)(() => [
1096
+ sorting(),
1097
+ globalFilter(),
1098
+ columnFilters(),
1099
+ pagination(),
1100
+ local.rowCount,
1101
+ local.pageCount,
1102
+ rowSelection(),
1103
+ expanded(),
1104
+ local.expandable,
1105
+ grouping(),
1106
+ local.groupable,
1107
+ columnVisibility(),
1108
+ columnSizing(),
1109
+ columnOrder(),
1110
+ columnPinning(),
1111
+ local.selectionMode,
1112
+ local.holdView,
1113
+ (data() || []).length,
1114
+ data(),
1115
+ dataDefault(),
1116
+ local.columns,
1117
+ colReg()
1118
+ ], (v) => (0, solid_js.untrack)(() => (() => {
1119
+ seedColumnPinning();
1120
+ reFeed();
1121
+ maybeClearHistoryOnExternalSwap();
1122
+ })()), { defer: true }));
1123
+ (0, solid_js.createEffect)((0, solid_js.on)(() => [
1124
+ sorting(),
1125
+ columnFilters(),
1126
+ globalFilter(),
1127
+ sortingDefault(),
1128
+ columnFiltersDefault(),
1129
+ globalFilterDefault()
1130
+ ], (v) => (0, solid_js.untrack)(() => (() => {
1131
+ const msg = buildSortFilterAnnounce();
1132
+ if (msg) setLiveAnnounce(msg);
1133
+ })()), { defer: true }));
859
1134
  (0, solid_js.onMount)(() => {
860
1135
  setDataDefault(data() || []);
861
1136
  seedColumnPinning();
1137
+ const cols0 = tableColumns();
1138
+ lastColumnSig = columnSetSignature(cols0);
862
1139
  table = (0, _tanstack_table_core.createTable)({
863
1140
  data: feedData(),
864
- columns: tableColumns(),
1141
+ columns: cols0,
865
1142
  state: currentState(),
866
1143
  getCoreRowModel: (0, _tanstack_table_core.getCoreRowModel)(),
867
- getSortedRowModel: (0, _tanstack_table_core.getSortedRowModel)(),
868
- getFilteredRowModel: (0, _tanstack_table_core.getFilteredRowModel)(),
1144
+ getSortedRowModel: heldSortedRowModel,
1145
+ getFilteredRowModel: heldFilteredRowModel,
869
1146
  getPaginationRowModel: (0, _tanstack_table_core.getPaginationRowModel)(),
870
1147
  getExpandedRowModel: (0, _tanstack_table_core.getExpandedRowModel)(),
871
1148
  getSubRows: local.getSubRows || void 0,
@@ -900,6 +1177,21 @@ function DataTable(_props) {
900
1177
  renderFallbackValue: null,
901
1178
  onStateChange: () => {}
902
1179
  });
1180
+ table.resetPageIndex = () => {
1181
+ if (!table) return;
1182
+ const pg = table.getState().pagination;
1183
+ writePagination({
1184
+ pageIndex: pg.pageIndex,
1185
+ pageSize: pg.pageSize
1186
+ });
1187
+ };
1188
+ const st0 = currentState();
1189
+ lastHoldSorting = st0.sorting;
1190
+ lastHoldColumnFilters = st0.columnFilters;
1191
+ lastHoldGlobalFilter = st0.globalFilter;
1192
+ lastPageGrouping = st0.grouping;
1193
+ syncHoldActive(st0);
1194
+ lastPropsData = data();
903
1195
  refreshRowModel = () => {
904
1196
  if (!table) return;
905
1197
  const nextRows = windowSource().slice();
@@ -914,7 +1206,17 @@ function DataTable(_props) {
914
1206
  }
915
1207
  remeasureColumnWindow();
916
1208
  const nextRowCount = nextRows.length;
917
- clampActiveCell(nextRowCount, nextRows.length ? nextRows[0].getVisibleCells().length : nextGroups.length ? (nextGroups[nextGroups.length - 1].headers || []).length : 0);
1209
+ const nextColCount = nextRows.length ? nextRows[0].getVisibleCells().length : nextGroups.length ? (nextGroups[nextGroups.length - 1].headers || []).length : 0;
1210
+ const nextIds = nextRows.map((r) => r.id);
1211
+ const fedData = table.options.data;
1212
+ const dataChanged = fedData !== lastFedData;
1213
+ lastFedData = fedData;
1214
+ const viewChangeOrWrite = pendingViewChange || pendingWrite && dataChanged;
1215
+ const swapWithoutIds = dataChanged && !pendingWrite && !pendingViewChange && table.options.getRowId == null;
1216
+ pendingViewChange = false;
1217
+ if (dataChanged) pendingWrite = false;
1218
+ followActiveCell(swapWithoutIds ? null : prevRowIds, nextIds, viewChangeOrWrite, nextRowCount, nextColCount, pendingEditFollow != null);
1219
+ prevRowIds = nextIds;
918
1220
  const pgState = table.getState().pagination;
919
1221
  const pc = table.getPageCount();
920
1222
  if (pc > 0 && pgState.pageIndex > pc - 1) writePagination({
@@ -930,6 +1232,11 @@ function DataTable(_props) {
930
1232
  syncIndeterminate();
931
1233
  if (typeof queueMicrotask !== "undefined") queueMicrotask(syncIndeterminate);
932
1234
  else Promise.resolve().then(syncIndeterminate);
1235
+ const vs = holdCtrl.viewState(table);
1236
+ if (!viewStatesEqual(vs, lastViewState)) {
1237
+ lastViewState = vs;
1238
+ _props.onViewStateChange?.(vs);
1239
+ }
933
1240
  };
934
1241
  refreshRowModel();
935
1242
  gridRoot = __rozieRootRef ? __rozieRootRef.querySelector(".rozie-data-table") : null;
@@ -998,45 +1305,6 @@ function DataTable(_props) {
998
1305
  lastDataLen = d.length;
999
1306
  reFeed();
1000
1307
  });
1001
- (0, solid_js.createEffect)((0, solid_js.on)(() => windowVer(), (v) => (0, solid_js.untrack)(() => emitVisibleRangeIfChanged()), { defer: true }));
1002
- (0, solid_js.createEffect)((0, solid_js.on)(() => [
1003
- sorting(),
1004
- globalFilter(),
1005
- columnFilters(),
1006
- pagination(),
1007
- local.rowCount,
1008
- local.pageCount,
1009
- rowSelection(),
1010
- expanded(),
1011
- local.expandable,
1012
- grouping(),
1013
- local.groupable,
1014
- columnVisibility(),
1015
- columnSizing(),
1016
- columnOrder(),
1017
- columnPinning(),
1018
- local.selectionMode,
1019
- (data() || []).length,
1020
- data(),
1021
- dataDefault(),
1022
- local.columns,
1023
- colReg()
1024
- ], (v) => (0, solid_js.untrack)(() => (() => {
1025
- seedColumnPinning();
1026
- reFeed();
1027
- maybeClearHistoryOnExternalSwap();
1028
- })()), { defer: true }));
1029
- (0, solid_js.createEffect)((0, solid_js.on)(() => [
1030
- sorting(),
1031
- columnFilters(),
1032
- globalFilter(),
1033
- sortingDefault(),
1034
- columnFiltersDefault(),
1035
- globalFilterDefault()
1036
- ], (v) => (0, solid_js.untrack)(() => (() => {
1037
- const msg = buildSortFilterAnnounce();
1038
- if (msg) setLiveAnnounce(msg);
1039
- })()), { defer: true }));
1040
1308
  let __rozieRootRef = null;
1041
1309
  let table = null;
1042
1310
  let virtualizer = null;
@@ -1060,6 +1328,48 @@ function DataTable(_props) {
1060
1328
  let undoStack = [];
1061
1329
  let redoStack = [];
1062
1330
  let restoringHistory = false;
1331
+ const holdCtrl = createHoldController();
1332
+ const heldFilteredRowModel = holdCtrl.wrapFiltered((0, _tanstack_table_core.getFilteredRowModel)());
1333
+ const heldSortedRowModel = holdCtrl.wrapSorted((0, _tanstack_table_core.getSortedRowModel)());
1334
+ let pendingViewChange = false;
1335
+ let pendingWrite = false;
1336
+ let prevRowIds = null;
1337
+ let lastFedData = null;
1338
+ let lastViewState = CLEAN_VIEW_STATE;
1339
+ let lastHoldSorting = null;
1340
+ let lastHoldColumnFilters = null;
1341
+ let lastHoldGlobalFilter = null;
1342
+ let holdFallbackWarned = false;
1343
+ let lastPageGrouping = null;
1344
+ let lastColumnSig = "";
1345
+ function columnSetSignature(defs) {
1346
+ let sig = "";
1347
+ const stack = (defs || []).slice().reverse();
1348
+ while (stack.length) {
1349
+ const d = stack.pop();
1350
+ if (!d) continue;
1351
+ sig += String(d.id) + (d.enableSorting ? "+" : "") + (d.enableColumnFilter ? "*" : "") + "|";
1352
+ if (Array.isArray(d.columns)) for (let i = d.columns.length - 1; i >= 0; i--) stack.push(d.columns[i]);
1353
+ }
1354
+ return sig;
1355
+ }
1356
+ let lastPropsData = null;
1357
+ function isExternalSwap() {
1358
+ const pd = data();
1359
+ if (pd === lastPropsData) return false;
1360
+ return !(pd != null && pd[DATA_WRITE_TOKEN_KEY] != null);
1361
+ }
1362
+ function syncHoldActive(st) {
1363
+ const wanted = local.holdView === true;
1364
+ const active = wanted && local.manual !== true && local.getSubRows == null && !(st.grouping || []).length;
1365
+ const wasHolding = holdCtrl.isHolding();
1366
+ holdCtrl.setActive(active);
1367
+ if (wasHolding && !holdCtrl.isHolding()) pendingViewChange = true;
1368
+ if (wanted && !active && !holdFallbackWarned) {
1369
+ holdFallbackWarned = true;
1370
+ 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.");
1371
+ }
1372
+ }
1063
1373
  let expandedTouched = false;
1064
1374
  function groupingActiveDefault() {
1065
1375
  return ((grouping() != null ? grouping() : groupingDefault()) || []).length > 0;
@@ -1192,6 +1502,7 @@ function DataTable(_props) {
1192
1502
  expandable: c.expandable === true,
1193
1503
  groupable: c.groupable !== false,
1194
1504
  aggregationFn: wrapAggregationFn(c.aggregationFn),
1505
+ ...columnRuleKeys(c, id),
1195
1506
  pinned: c.pinned != null ? c.pinned : "",
1196
1507
  width: c.width != null ? c.width : "",
1197
1508
  ...parseWidthToSize(c.width) != null ? { size: parseWidthToSize(c.width) } : {},
@@ -1235,6 +1546,7 @@ function DataTable(_props) {
1235
1546
  expandable: spec.expandable === true,
1236
1547
  groupable: spec.groupable !== false,
1237
1548
  aggregationFn: wrapAggregationFn(spec.aggregationFn),
1549
+ ...columnRuleKeys(spec, id),
1238
1550
  pinned: spec.pinned != null ? spec.pinned : "",
1239
1551
  width: spec.width != null ? spec.width : "",
1240
1552
  ...parseWidthToSize(spec.width) != null ? { size: parseWidthToSize(spec.width) } : {},
@@ -1391,6 +1703,9 @@ function DataTable(_props) {
1391
1703
  recordSnapshot(currentData());
1392
1704
  emitHistoryChangeIfEdged(prevU, prevR);
1393
1705
  }
1706
+ if (table) holdCtrl.capture(table);
1707
+ holdCtrl.noteWrite(currentData() || [], Array.isArray(next) ? next : []);
1708
+ pendingWrite = true;
1394
1709
  const fresh = Array.isArray(next) ? next.slice() : next;
1395
1710
  try {
1396
1711
  Object.defineProperty(fresh, DATA_WRITE_TOKEN_KEY, {
@@ -2014,13 +2329,60 @@ function DataTable(_props) {
2014
2329
  if (local.selectionMode === "none") return false;
2015
2330
  return lazyRowsActive() ? (row) => !rowIsLazyPlaceholder(row) : true;
2016
2331
  }
2332
+ function writePaginationSoon(next) {
2333
+ if (!programmatic) {
2334
+ writePagination(next);
2335
+ return;
2336
+ }
2337
+ const run = () => writePagination(next);
2338
+ if (typeof queueMicrotask !== "undefined") queueMicrotask(run);
2339
+ else Promise.resolve().then(run);
2340
+ }
2017
2341
  function reFeed() {
2018
2342
  if (!table) return;
2343
+ const st0 = currentState();
2344
+ syncHoldActive(st0);
2345
+ let st = st0;
2346
+ let pageReset = null;
2347
+ const groupingChanged = st0.grouping !== lastPageGrouping;
2348
+ lastPageGrouping = st0.grouping;
2349
+ const viewChanged = st0.sorting !== lastHoldSorting || st0.columnFilters !== lastHoldColumnFilters || st0.globalFilter !== lastHoldGlobalFilter;
2350
+ if (viewChanged) {
2351
+ lastHoldSorting = st0.sorting;
2352
+ lastHoldColumnFilters = st0.columnFilters;
2353
+ lastHoldGlobalFilter = st0.globalFilter;
2354
+ holdCtrl.release();
2355
+ pendingViewChange = true;
2356
+ }
2357
+ if ((viewChanged || groupingChanged) && local.manual !== true && st0.pagination && st0.pagination.pageIndex !== 0) {
2358
+ pageReset = {
2359
+ pageIndex: 0,
2360
+ pageSize: st0.pagination.pageSize
2361
+ };
2362
+ st = {
2363
+ ...st0,
2364
+ pagination: pageReset
2365
+ };
2366
+ }
2367
+ const cols = tableColumns();
2368
+ const colSig = columnSetSignature(cols);
2369
+ if (colSig !== lastColumnSig) {
2370
+ lastColumnSig = colSig;
2371
+ st = {
2372
+ ...st,
2373
+ sorting: [...st.sorting || []],
2374
+ columnFilters: [...st.columnFilters || []]
2375
+ };
2376
+ }
2377
+ if (holdCtrl.isHolding() && isExternalSwap()) holdCtrl.release();
2378
+ if (pendingWrite && isExternalSwap()) pendingWrite = false;
2019
2379
  table.setOptions((prev) => ({
2020
2380
  ...prev,
2021
2381
  data: feedData(),
2022
- columns: tableColumns(),
2023
- state: currentState(),
2382
+ columns: cols,
2383
+ state: st,
2384
+ getFilteredRowModel: heldFilteredRowModel,
2385
+ getSortedRowModel: heldSortedRowModel,
2024
2386
  enableRowSelection: rowSelectionOption(),
2025
2387
  enableMultiRowSelection: local.selectionMode === "multiple",
2026
2388
  rowCount: local.rowCount ?? void 0,
@@ -2048,15 +2410,19 @@ function DataTable(_props) {
2048
2410
  onColumnSizingInfoChange: onColumnSizingInfoChangeCb
2049
2411
  }));
2050
2412
  if (refreshRowModel) refreshRowModel();
2413
+ if (pageReset) writePaginationSoon(pageReset);
2051
2414
  }
2052
- let lastPropsData = null;
2053
2415
  function maybeClearHistoryOnExternalSwap() {
2054
2416
  const pd = data();
2055
2417
  if (pd === lastPropsData) return;
2056
2418
  lastPropsData = pd;
2057
- if (!local.undoable) return;
2058
2419
  if (pd != null && pd[DATA_WRITE_TOKEN_KEY] != null) return;
2059
- clearHistory();
2420
+ pendingWrite = false;
2421
+ if (holdCtrl.isHolding()) {
2422
+ holdCtrl.release();
2423
+ if (refreshRowModel) refreshRowModel();
2424
+ }
2425
+ if (local.undoable) clearHistory();
2060
2426
  }
2061
2427
  let lastData = null;
2062
2428
  let lastDataLen = -1;
@@ -2433,6 +2799,23 @@ function DataTable(_props) {
2433
2799
  function cut() {
2434
2800
  return cutRange();
2435
2801
  }
2802
+ function refreshView() {
2803
+ holdCtrl.release();
2804
+ pendingViewChange = true;
2805
+ if (!table) return;
2806
+ table.setOptions((p) => ({
2807
+ ...p,
2808
+ state: {
2809
+ ...p.state,
2810
+ columnFilters: [...p.state.columnFilters || []],
2811
+ sorting: [...p.state.sorting || []]
2812
+ }
2813
+ }));
2814
+ if (refreshRowModel) refreshRowModel();
2815
+ }
2816
+ function getViewState() {
2817
+ return holdCtrl.viewState(table);
2818
+ }
2436
2819
  function isGrid() {
2437
2820
  return local.interactionMode === "grid";
2438
2821
  }
@@ -2965,6 +3348,7 @@ function DataTable(_props) {
2965
3348
  if (!tgt || !tgt.closest) return;
2966
3349
  const cellEl = tgt.closest("[data-grid-cell]");
2967
3350
  if (!cellEl) return;
3351
+ activeCellEngaged = true;
2968
3352
  const rowAttr = cellEl.getAttribute("data-row");
2969
3353
  const colAttr = cellEl.getAttribute("data-col-index");
2970
3354
  if (rowAttr == null || colAttr == null) return;
@@ -3138,13 +3522,62 @@ function DataTable(_props) {
3138
3522
  if (typeof requestAnimationFrame === "function") requestAnimationFrame(tryFocus);
3139
3523
  else setTimeout(tryFocus, 0);
3140
3524
  }
3141
- function clampActiveCell(rowCount, colCount) {
3525
+ function followOpenEditors(prevIds, nextIds) {
3526
+ if (!prevIds || sameIdSequence(prevIds, nextIds)) return false;
3527
+ let owns = false;
3528
+ const er = editingRow();
3529
+ if (er >= 0) {
3530
+ const ef = resolveFollow(prevIds, er, nextIds, true);
3531
+ if (ef.kind === "move") {
3532
+ setEditingRow(ef.index);
3533
+ focusEditorWhenReady(ef.index, editingCol(), false);
3534
+ owns = true;
3535
+ } else if (ef.kind !== "stay") {
3536
+ committedThisSession = true;
3537
+ editTransition = true;
3538
+ endEdit();
3539
+ editTransition = false;
3540
+ }
3541
+ }
3542
+ const rr = editingRowIndex();
3543
+ if (rr != null && rr >= 0) {
3544
+ const rf = resolveFollow(prevIds, rr, nextIds, true);
3545
+ if (rf.kind === "move") {
3546
+ setEditingRowIndex(rf.index);
3547
+ owns = true;
3548
+ } else if (rf.kind !== "stay") {
3549
+ editTransition = true;
3550
+ endRowEdit();
3551
+ editTransition = false;
3552
+ }
3553
+ }
3554
+ return owns;
3555
+ }
3556
+ function rowIdInModel(index) {
3557
+ const row = windowSource()[index];
3558
+ return row ? row.id : null;
3559
+ }
3560
+ function modelIndexOfRowId(id) {
3561
+ const rows = windowSource();
3562
+ for (let i = 0; i < rows.length; i++) if (rows[i].id === id) return i;
3563
+ return -1;
3564
+ }
3565
+ function followActiveCell(prevIds, nextIds, viewChangeOrWrite, rowCount, colCount, editFollowPending = false) {
3566
+ const editorOwnsFocus = followOpenEditors(prevIds, nextIds);
3567
+ if (!isGrid()) return;
3568
+ let follow = null;
3569
+ if (activeCellEngaged && rowCount > 0 && !activeIsHeader() && !gridEmptyFallback) follow = resolveFollow(prevIds, activeRow(), nextIds, viewChangeOrWrite);
3570
+ clampActiveCell(rowCount, colCount, follow, editFollowPending || editorOwnsFocus, rowCount <= 0 && viewChangeOrWrite);
3571
+ if (viewChangeOrWrite && !sameIdSequence(prevIds, nextIds)) clearRange();
3572
+ }
3573
+ function clampActiveCell(rowCount, colCount, follow = null, editFollowPending = false, focusEmptyPark = false) {
3142
3574
  if (!isGrid()) return;
3143
3575
  const colN = colCount != null ? colCount : visibleColCount();
3144
3576
  const rowN = rowCount != null ? rowCount : bodyRowCount();
3145
3577
  let recoverFocus = false;
3146
3578
  let doomedRow = -1;
3147
3579
  let doomedCol = 0;
3580
+ let focusOnBody = false;
3148
3581
  if (gridRoot) {
3149
3582
  const rootNode = gridRoot.getRootNode ? gridRoot.getRootNode() : null;
3150
3583
  const focusedEl = rootNode ? rootNode.activeElement : null;
@@ -3153,6 +3586,7 @@ function DataTable(_props) {
3153
3586
  const fRowAttr = focusedCell.getAttribute("data-row");
3154
3587
  const fColAttr = focusedCell.getAttribute("data-col-index");
3155
3588
  if (fRowAttr != null && fRowAttr !== "__header") {
3589
+ focusOnBody = true;
3156
3590
  const fr = parseInt(fRowAttr, 10);
3157
3591
  const fc = parseInt(fColAttr, 10);
3158
3592
  if (Number.isFinite(fr) && fr > rowN - 1) {
@@ -3172,6 +3606,7 @@ function DataTable(_props) {
3172
3606
  setActiveColIndex(0);
3173
3607
  gridEmptyFallback = true;
3174
3608
  clampRange(rowN - 1, colN - 1);
3609
+ if (focusEmptyPark && (focusOnBody || editFollowPending)) recoverGridFocus("__header", 0, headerLeafLevel());
3175
3610
  return;
3176
3611
  }
3177
3612
  if (gridEmptyFallback) {
@@ -3179,6 +3614,31 @@ function DataTable(_props) {
3179
3614
  setActiveIsHeader(false);
3180
3615
  setActiveRow(0);
3181
3616
  }
3617
+ if (follow && follow.kind === "move") {
3618
+ const nextRow = follow.index;
3619
+ setActiveRow(nextRow);
3620
+ clampRange(rowN - 1, colN - 1);
3621
+ _props.onActivecellChange?.({
3622
+ rowIndex: toAbsRow(nextRow),
3623
+ colIndex: col,
3624
+ isHeader: false
3625
+ });
3626
+ if (focusOnBody && !editFollowPending) focusCellWhenReady(nextRow, col);
3627
+ return;
3628
+ }
3629
+ if (follow && follow.kind === "park") {
3630
+ const level = headerLeafLevel();
3631
+ setActiveIsHeader(true);
3632
+ setActiveHeaderLevel(level);
3633
+ clampRange(rowN - 1, colN - 1);
3634
+ _props.onActivecellChange?.({
3635
+ rowIndex: null,
3636
+ colIndex: col,
3637
+ isHeader: true
3638
+ });
3639
+ if (focusOnBody || editFollowPending) recoverGridFocus("__header", col, level);
3640
+ return;
3641
+ }
3182
3642
  if (!activeIsHeader()) {
3183
3643
  const lastRow = rowN - 1;
3184
3644
  const maxRow = lastRow < 0 ? 0 : lastRow;
@@ -3244,6 +3704,7 @@ function DataTable(_props) {
3244
3704
  colVirtualizer._willUpdate();
3245
3705
  }
3246
3706
  let gridEmptyFallback = false;
3707
+ let activeCellEngaged = false;
3247
3708
  let rangeTransition = false;
3248
3709
  let rangeClickPending = null;
3249
3710
  let rangeActive = false;
@@ -3964,6 +4425,7 @@ function DataTable(_props) {
3964
4425
  const colId = columnIdAt(rowIndex, colIndex);
3965
4426
  if (colId == null || !columnEditable(colId)) return;
3966
4427
  committedThisSession = false;
4428
+ outsidePointerDown = false;
3967
4429
  setInvalid("");
3968
4430
  setEditingRowIndex(null);
3969
4431
  setRowDraft({});
@@ -4414,12 +4876,14 @@ function DataTable(_props) {
4414
4876
  const fromRow = editingRow();
4415
4877
  const fromCol = editingCol();
4416
4878
  const target = e.shiftKey ? prevEditableCell(fromRow, fromCol) : nextEditableCell(fromRow, fromCol);
4879
+ const targetRowId = target ? rowIdInModel(target.row) : null;
4417
4880
  const committed = commitEdit(void 0, true);
4418
- if (committed && target) {
4419
- setActiveRow(target.row);
4881
+ const advanceRow = targetRowId != null ? modelIndexOfRowId(targetRowId) : -1;
4882
+ if (committed && target && advanceRow >= 0) {
4883
+ setActiveRow(advanceRow);
4420
4884
  setActiveColIndex(target.col);
4421
- beginEdit(target.row, target.col, null);
4422
- } else if (committed) focusCellWhenReady(fromRow, fromCol);
4885
+ beginEdit(advanceRow, target.col, null);
4886
+ } else if (committed && target) {} else if (committed) focusCellWhenReady(fromRow, fromCol);
4423
4887
  } else if (key === "Escape") {
4424
4888
  e.preventDefault();
4425
4889
  cancelEdit();
@@ -5361,6 +5825,9 @@ function DataTable(_props) {
5361
5825
  _el$64.addEventListener("change", ($event) => {
5362
5826
  onCellEditorInput(cell().column.id, $event);
5363
5827
  });
5828
+ (0, solid_js_web.use)((el) => {
5829
+ (0, _rozie_runtime_solid.rozieSelectValue)(el, () => editorValueFor(cell().column.id));
5830
+ }, _el$64);
5364
5831
  (0, solid_js_web.insert)(_el$64, (0, solid_js_web.createComponent)(_solid_primitives_keyed.Key, {
5365
5832
  get each() {
5366
5833
  return editorOptionsOf(cell().column.id);
@@ -5374,7 +5841,6 @@ function DataTable(_props) {
5374
5841
  })()
5375
5842
  }));
5376
5843
  (0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$64, "aria-invalid", (0, _rozie_runtime_solid.rozieAttr)(invalidMsg() ? "true" : null)));
5377
- (0, solid_js_web.effect)(() => _el$64.value = editorValueFor(cell().column.id));
5378
5844
  return _el$64;
5379
5845
  }
5380
5846
  });
@@ -6242,6 +6708,9 @@ function DataTable(_props) {
6242
6708
  _el$122.addEventListener("change", ($event) => {
6243
6709
  onCellEditorInput(cell().column.id, $event);
6244
6710
  });
6711
+ (0, solid_js_web.use)((el) => {
6712
+ (0, _rozie_runtime_solid.rozieSelectValue)(el, () => editorValueFor(cell().column.id));
6713
+ }, _el$122);
6245
6714
  (0, solid_js_web.insert)(_el$122, (0, solid_js_web.createComponent)(_solid_primitives_keyed.Key, {
6246
6715
  get each() {
6247
6716
  return editorOptionsOf(cell().column.id);
@@ -6255,7 +6724,6 @@ function DataTable(_props) {
6255
6724
  })()
6256
6725
  }));
6257
6726
  (0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$122, "aria-invalid", (0, _rozie_runtime_solid.rozieAttr)(invalidMsg() ? "true" : null)));
6258
- (0, solid_js_web.effect)(() => _el$122.value = editorValueFor(cell().column.id));
6259
6727
  return _el$122;
6260
6728
  }
6261
6729
  });
@@ -6571,6 +7039,9 @@ function DataTable(_props) {
6571
7039
  _el$139.addEventListener("change", ($event) => {
6572
7040
  onPageSizeChange($event);
6573
7041
  });
7042
+ (0, solid_js_web.use)((el) => {
7043
+ (0, _rozie_runtime_solid.rozieSelectValue)(el, () => pageSize());
7044
+ }, _el$139);
6574
7045
  (0, solid_js_web.effect)((_p$) => {
6575
7046
  var _v$97 = !canPrevPage(), _v$98 = !canNextPage();
6576
7047
  _v$97 !== _p$.e && (_el$136.disabled = _p$.e = _v$97);
@@ -6580,7 +7051,6 @@ function DataTable(_props) {
6580
7051
  e: void 0,
6581
7052
  t: void 0
6582
7053
  });
6583
- (0, solid_js_web.effect)(() => _el$139.value = pageSize());
6584
7054
  return _el$135;
6585
7055
  }
6586
7056
  }), null);
@@ -6615,6 +7085,8 @@ function Column(_props) {
6615
7085
  expandable: false,
6616
7086
  groupable: true,
6617
7087
  aggregationFn: null,
7088
+ filterFn: null,
7089
+ sortingFn: null,
6618
7090
  editable: false,
6619
7091
  editor: "text",
6620
7092
  editorOptions: [],
@@ -6630,12 +7102,36 @@ function Column(_props) {
6630
7102
  "expandable",
6631
7103
  "groupable",
6632
7104
  "aggregationFn",
7105
+ "filterFn",
7106
+ "sortingFn",
6633
7107
  "editable",
6634
7108
  "editor",
6635
7109
  "editorOptions",
6636
7110
  "validate"
6637
7111
  ]);
6638
7112
  const registry = (0, solid_js.useContext)((0, _rozie_runtime_solid.rozieContext)("data-table:columns"));
7113
+ (0, solid_js.createEffect)((0, solid_js.on)(() => [
7114
+ local.id,
7115
+ local.field,
7116
+ local.header,
7117
+ local.sortable,
7118
+ local.filterable,
7119
+ local.pinned,
7120
+ local.width,
7121
+ local.expandable,
7122
+ local.groupable,
7123
+ local.aggregationFn,
7124
+ local.filterFn,
7125
+ local.sortingFn,
7126
+ local.editable,
7127
+ local.editor,
7128
+ local.editorOptions,
7129
+ local.validate
7130
+ ], (v) => (0, solid_js.untrack)(() => (() => {
7131
+ latestFilterFn = local.filterFn;
7132
+ latestSortingFn = local.sortingFn;
7133
+ if (reg) reg.registerColumn(colId(), buildSpec());
7134
+ })()), { defer: true }));
6639
7135
  (0, solid_js.onMount)(() => {
6640
7136
  const _cleanup = (() => {
6641
7137
  if (reg && !registered) {
@@ -6656,31 +7152,24 @@ function Column(_props) {
6656
7152
  registered = true;
6657
7153
  reg.registerColumn(colId(), buildSpec());
6658
7154
  });
6659
- (0, solid_js.createEffect)((0, solid_js.on)(() => [
6660
- local.id,
6661
- local.field,
6662
- local.header,
6663
- local.sortable,
6664
- local.filterable,
6665
- local.pinned,
6666
- local.width,
6667
- local.expandable,
6668
- local.groupable,
6669
- local.aggregationFn,
6670
- local.editable,
6671
- local.editor,
6672
- local.editorOptions,
6673
- local.validate
6674
- ], (v) => (0, solid_js.untrack)(() => (() => {
6675
- if (reg) reg.registerColumn(colId(), buildSpec());
6676
- })()), { defer: true }));
6677
7155
  let reg = null;
6678
7156
  reg = registry;
6679
7157
  let registered = false;
7158
+ let latestFilterFn = null;
7159
+ let latestSortingFn = null;
7160
+ const filterTrampoline = Object.assign((...args) => typeof latestFilterFn === "function" ? latestFilterFn(...args) : true, {
7161
+ autoRemove: (value, column) => typeof latestFilterFn === "function" && typeof latestFilterFn.autoRemove === "function" ? latestFilterFn.autoRemove(value, column) : false,
7162
+ resolveFilterValue: (value) => typeof latestFilterFn === "function" && typeof latestFilterFn.resolveFilterValue === "function" ? latestFilterFn.resolveFilterValue(value) : value
7163
+ });
7164
+ function sortingTrampoline(...args) {
7165
+ return typeof latestSortingFn === "function" ? latestSortingFn(...args) : 0;
7166
+ }
6680
7167
  function colId() {
6681
7168
  return local.id !== "" ? local.id : local.field;
6682
7169
  }
6683
7170
  function buildSpec() {
7171
+ latestFilterFn = local.filterFn;
7172
+ latestSortingFn = local.sortingFn;
6684
7173
  return {
6685
7174
  id: colId(),
6686
7175
  field: local.field !== "" ? local.field : colId(),
@@ -6692,6 +7181,8 @@ function Column(_props) {
6692
7181
  expandable: local.expandable,
6693
7182
  groupable: local.groupable,
6694
7183
  aggregationFn: local.aggregationFn,
7184
+ filterFn: typeof local.filterFn === "function" ? filterTrampoline : local.filterFn,
7185
+ sortingFn: typeof local.sortingFn === "function" ? sortingTrampoline : local.sortingFn,
6695
7186
  editable: local.editable,
6696
7187
  editor: local.editor,
6697
7188
  editorOptions: local.editorOptions,
@@ -6729,12 +7220,12 @@ function EditorText(_props) {
6729
7220
  ]);
6730
7221
  const [draft, setDraft] = (0, solid_js.createSignal)("");
6731
7222
  const [touched, setTouched] = (0, solid_js.createSignal)(false);
6732
- (0, solid_js.onMount)(() => {
6733
- if (local.autofocus) inputElRef?.focus();
6734
- });
6735
7223
  (0, solid_js.createEffect)((0, solid_js.on)(() => local.autofocus, (v) => (0, solid_js.untrack)(() => ((v) => {
6736
7224
  if (v) inputElRef?.focus();
6737
7225
  })(v)), { defer: true }));
7226
+ (0, solid_js.onMount)(() => {
7227
+ if (local.autofocus) inputElRef?.focus();
7228
+ });
6738
7229
  let inputElRef = null;
6739
7230
  function draftValue() {
6740
7231
  return touched() ? draft() : local.value != null ? String(local.value) : "";
@@ -6810,12 +7301,12 @@ function EditorNumber(_props) {
6810
7301
  ]);
6811
7302
  const [draft, setDraft] = (0, solid_js.createSignal)("");
6812
7303
  const [touched, setTouched] = (0, solid_js.createSignal)(false);
6813
- (0, solid_js.onMount)(() => {
6814
- if (local.autofocus) inputElRef?.focus();
6815
- });
6816
7304
  (0, solid_js.createEffect)((0, solid_js.on)(() => local.autofocus, (v) => (0, solid_js.untrack)(() => ((v) => {
6817
7305
  if (v) inputElRef?.focus();
6818
7306
  })(v)), { defer: true }));
7307
+ (0, solid_js.onMount)(() => {
7308
+ if (local.autofocus) inputElRef?.focus();
7309
+ });
6819
7310
  let inputElRef = null;
6820
7311
  function draftValue() {
6821
7312
  return touched() ? draft() : local.value != null ? String(local.value) : "";
@@ -6900,12 +7391,12 @@ function EditorSelect(_props) {
6900
7391
  ]);
6901
7392
  const [draft, setDraft] = (0, solid_js.createSignal)("");
6902
7393
  const [touched, setTouched] = (0, solid_js.createSignal)(false);
6903
- (0, solid_js.onMount)(() => {
6904
- if (local.autofocus) selectElRef?.focus();
6905
- });
6906
7394
  (0, solid_js.createEffect)((0, solid_js.on)(() => local.autofocus, (v) => (0, solid_js.untrack)(() => ((v) => {
6907
7395
  if (v) selectElRef?.focus();
6908
7396
  })(v)), { defer: true }));
7397
+ (0, solid_js.onMount)(() => {
7398
+ if (local.autofocus) selectElRef?.focus();
7399
+ });
6909
7400
  let selectElRef = null;
6910
7401
  function draftValue() {
6911
7402
  return touched() ? draft() : local.value != null ? String(local.value) : "";
@@ -6948,6 +7439,7 @@ function EditorSelect(_props) {
6948
7439
  onChange($event);
6949
7440
  });
6950
7441
  (0, solid_js_web.use)((el) => {
7442
+ (0, _rozie_runtime_solid.rozieSelectValue)(el, () => draftValue());
6951
7443
  selectElRef = el;
6952
7444
  }, _el$);
6953
7445
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(_solid_primitives_keyed.Key, {
@@ -6963,7 +7455,6 @@ function EditorSelect(_props) {
6963
7455
  })()
6964
7456
  }));
6965
7457
  (0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", (0, _rozie_runtime_solid.rozieAttr)(a11yLabel())));
6966
- (0, solid_js_web.effect)(() => _el$.value = draftValue());
6967
7458
  return _el$;
6968
7459
  })();
6969
7460
  }
@@ -6991,12 +7482,12 @@ function EditorCheckbox(_props) {
6991
7482
  "autofocus",
6992
7483
  "columnLabel"
6993
7484
  ]);
6994
- (0, solid_js.onMount)(() => {
6995
- if (local.autofocus) inputElRef?.focus();
6996
- });
6997
7485
  (0, solid_js.createEffect)((0, solid_js.on)(() => local.autofocus, (v) => (0, solid_js.untrack)(() => ((v) => {
6998
7486
  if (v) inputElRef?.focus();
6999
7487
  })(v)), { defer: true }));
7488
+ (0, solid_js.onMount)(() => {
7489
+ if (local.autofocus) inputElRef?.focus();
7490
+ });
7000
7491
  let inputElRef = null;
7001
7492
  function onChange(e) {
7002
7493
  local.commit && local.commit(!!(e && e.target ? e.target.checked : false));
@@ -7086,12 +7577,12 @@ function EditorDate(_props) {
7086
7577
  ]);
7087
7578
  const [draft, setDraft] = (0, solid_js.createSignal)("");
7088
7579
  const [touched, setTouched] = (0, solid_js.createSignal)(false);
7089
- (0, solid_js.onMount)(() => {
7090
- if (local.autofocus) inputElRef?.focus();
7091
- });
7092
7580
  (0, solid_js.createEffect)((0, solid_js.on)(() => local.autofocus, (v) => (0, solid_js.untrack)(() => ((v) => {
7093
7581
  if (v) inputElRef?.focus();
7094
7582
  })(v)), { defer: true }));
7583
+ (0, solid_js.onMount)(() => {
7584
+ if (local.autofocus) inputElRef?.focus();
7585
+ });
7095
7586
  let inputElRef = null;
7096
7587
  function draftValue() {
7097
7588
  return touched() ? draft() : toIsoDateString(local.value);
@@ -7354,6 +7845,9 @@ function FilterSelect(_props) {
7354
7845
  _el$.addEventListener("change", ($event) => {
7355
7846
  onChange($event);
7356
7847
  });
7848
+ (0, solid_js_web.use)((el) => {
7849
+ (0, _rozie_runtime_solid.rozieSelectValue)(el, () => selectValue());
7850
+ }, _el$);
7357
7851
  (0, solid_js_web.insert)(_el$, (0, solid_js_web.createComponent)(_solid_primitives_keyed.Key, {
7358
7852
  get each() {
7359
7853
  return local.uniqueValues;
@@ -7367,7 +7861,6 @@ function FilterSelect(_props) {
7367
7861
  })()
7368
7862
  }), null);
7369
7863
  (0, solid_js_web.effect)(() => (0, solid_js_web.setAttribute)(_el$, "aria-label", (0, _rozie_runtime_solid.rozieAttr)(a11yLabel())));
7370
- (0, solid_js_web.effect)(() => _el$.value = selectValue());
7371
7864
  return _el$;
7372
7865
  })();
7373
7866
  }