argus-table 0.2.2 → 0.3.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/README.md +1 -1
- package/dist/argus-column.js +24 -1
- package/dist/argus-column.js.map +1 -1
- package/dist/argus-table.js +1024 -165
- package/dist/argus-table.js.map +1 -1
- package/dist/cdn/argus-table.js +74 -50
- package/dist/cdn/argus-table.js.map +1 -1
- package/dist/controllers/auto-width.js +11 -0
- package/dist/controllers/auto-width.js.map +1 -1
- package/dist/controllers/column-window.js +139 -0
- package/dist/controllers/column-window.js.map +1 -0
- package/dist/controllers/data-controller.js +9 -4
- package/dist/controllers/data-controller.js.map +1 -1
- package/dist/controllers/plugins.js +102 -0
- package/dist/controllers/plugins.js.map +1 -0
- package/dist/controllers/reorder-drag.js +9 -10
- package/dist/controllers/reorder-drag.js.map +1 -1
- package/dist/controllers/row-measure.js +121 -0
- package/dist/controllers/row-measure.js.map +1 -0
- package/dist/controllers/virtual-controller.js +311 -10
- package/dist/controllers/virtual-controller.js.map +1 -1
- package/dist/core/src/columns/column-order.js +14 -10
- package/dist/core/src/columns/column-order.js.map +1 -1
- package/dist/core/src/columns/resolve-columns.js +18 -4
- package/dist/core/src/columns/resolve-columns.js.map +1 -1
- package/dist/core/src/data/page-cache.js +4 -0
- package/dist/core/src/data/page-cache.js.map +1 -1
- package/dist/core/src/filters/filter.js +185 -0
- package/dist/core/src/filters/filter.js.map +1 -0
- package/dist/core/src/state/selection.js +70 -0
- package/dist/core/src/state/selection.js.map +1 -0
- package/dist/core/src/table/create-table.js +239 -64
- package/dist/core/src/table/create-table.js.map +1 -1
- package/dist/core/src/table/filtered-row-model.js +48 -0
- package/dist/core/src/table/filtered-row-model.js.map +1 -0
- package/dist/core/src/table/sorted-row-model.js +13 -2
- package/dist/core/src/table/sorted-row-model.js.map +1 -1
- package/dist/core/src/virtual/column-window.js +72 -0
- package/dist/core/src/virtual/column-window.js.map +1 -0
- package/dist/core/src/virtual/row-pool.js +2 -1
- package/dist/core/src/virtual/row-pool.js.map +1 -1
- package/dist/core/src/virtual/row-sizes.js +156 -0
- package/dist/core/src/virtual/row-sizes.js.map +1 -0
- package/dist/core/src/virtual/scroll-scale.js +41 -3
- package/dist/core/src/virtual/scroll-scale.js.map +1 -1
- package/dist/custom-elements.json +1273 -45
- package/dist/events.js +9 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +609 -74
- package/dist/index.js +3 -2
- package/dist/interactive.js +22 -0
- package/dist/interactive.js.map +1 -0
- package/dist/max-height.js +22 -8
- package/dist/max-height.js.map +1 -1
- package/dist/render/body.js +47 -7
- package/dist/render/body.js.map +1 -1
- package/dist/render/cells.js +14 -11
- package/dist/render/cells.js.map +1 -1
- package/dist/render/content-directive.js +115 -0
- package/dist/render/content-directive.js.map +1 -0
- package/dist/render/content.js +20 -9
- package/dist/render/content.js.map +1 -1
- package/dist/render/header.js +24 -5
- package/dist/render/header.js.map +1 -1
- package/dist/render/pinned-rows.js +1 -1
- package/dist/render/pinned-rows.js.map +1 -1
- package/dist/styles/base.js +1 -1
- package/dist/styles/base.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// ../core/src/state/selection.ts
|
|
2
|
+
/** Whether two selections hold the same ids, in any order. */
|
|
3
|
+
function sameSelection(a, b) {
|
|
4
|
+
if (a.length !== b.length) return false;
|
|
5
|
+
const ids = new Set(a);
|
|
6
|
+
return b.every((id) => ids.has(id));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Selects or deselects one row and makes it the anchor. In `'single'` mode,
|
|
10
|
+
* selecting a row replaces the selection.
|
|
11
|
+
*/
|
|
12
|
+
function toggleRow(current, mode, id) {
|
|
13
|
+
if (mode === "none") return void 0;
|
|
14
|
+
if (current.includes(id)) return {
|
|
15
|
+
selection: current.filter((s) => s !== id),
|
|
16
|
+
anchor: id
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
selection: mode === "single" ? [id] : [...current, id],
|
|
20
|
+
anchor: id
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The rows from index `from` to `to` (either order, both inclusive), in row
|
|
25
|
+
* order. With `add`, they join the current selection instead of replacing it.
|
|
26
|
+
* The anchor stays where it was.
|
|
27
|
+
*/
|
|
28
|
+
function selectRange(current, from, to, idAt, add) {
|
|
29
|
+
const ids = add ? [...current] : [];
|
|
30
|
+
const have = new Set(ids);
|
|
31
|
+
const [first, last] = (to >= from ? 1 : -1) === 1 ? [from, to] : [to, from];
|
|
32
|
+
for (let index = first; index <= last; index++) {
|
|
33
|
+
const id = idAt(index);
|
|
34
|
+
if (id === void 0 || have.has(id)) continue;
|
|
35
|
+
have.add(id);
|
|
36
|
+
ids.push(id);
|
|
37
|
+
}
|
|
38
|
+
return ids;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Every row of `ids` selected, keeping the rows already selected (with a
|
|
42
|
+
* `dataSource`, `ids` are only the loaded rows: selected rows elsewhere stay).
|
|
43
|
+
*/
|
|
44
|
+
function selectAll(current, ids) {
|
|
45
|
+
const have = new Set(current);
|
|
46
|
+
return [...current, ...ids.filter((id) => !have.has(id))];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A click on a row, desktop style. A plain click selects only that row; Ctrl or
|
|
50
|
+
* Cmd toggles it. In `'multi'` mode, Shift selects the range from the anchor
|
|
51
|
+
* (at `anchorIndex`) to the row, and Ctrl+Shift adds that range. Without an
|
|
52
|
+
* anchor in the current rows, Shift acts like a plain click. `undefined` in
|
|
53
|
+
* `'none'` mode. The selection may come back unchanged (a click on the one
|
|
54
|
+
* selected row): check with `sameSelection` before reporting a change.
|
|
55
|
+
*/
|
|
56
|
+
function clickSelection(current, mode, target, anchor, modifiers, idAt) {
|
|
57
|
+
if (mode === "none") return void 0;
|
|
58
|
+
if (mode === "multi" && modifiers.range && anchor) return {
|
|
59
|
+
selection: selectRange(current, anchor.index, target.index, idAt, modifiers.toggle),
|
|
60
|
+
anchor: anchor.id
|
|
61
|
+
};
|
|
62
|
+
if (modifiers.toggle) return toggleRow(current, mode, target.id);
|
|
63
|
+
return {
|
|
64
|
+
selection: [target.id],
|
|
65
|
+
anchor: target.id
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export { clickSelection, sameSelection, selectAll, selectRange, toggleRow };
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selection.js","names":[],"sources":["../../../../../core/src/state/selection.ts"],"sourcesContent":["import type { SelectionMode, SelectionState } from '../types.js';\n\n/**\n * Row selection rules, DOM-free. The element owns the state (through\n * `controllable`) and the anchor; these functions only compute the next ones.\n *\n * The anchor is the row a range starts from: the last row clicked or toggled\n * without Shift. Ranges are by index in the current row order, so they follow\n * sorting; `idAt` returns `undefined` for a row that can't be selected (a\n * `dataSource` row not loaded), and such rows are left out.\n */\n\n/** The selection after a step, and the row later ranges start from. */\nexport interface SelectionStep {\n selection: SelectionState;\n anchor: string | undefined;\n}\n\n/** The row a click or key acts on: its id and its index in the current row order. */\nexport interface SelectionTarget {\n id: string;\n index: number;\n}\n\n/** Modifier keys of a click: Ctrl or Cmd toggles, Shift selects a range. */\nexport interface SelectionModifiers {\n toggle: boolean;\n range: boolean;\n}\n\n/** Whether two selections hold the same ids, in any order. */\nexport function sameSelection(a: readonly string[], b: readonly string[]): boolean {\n if (a.length !== b.length) return false;\n const ids = new Set(a);\n return b.every((id) => ids.has(id));\n}\n\n/**\n * Selects or deselects one row and makes it the anchor. In `'single'` mode,\n * selecting a row replaces the selection.\n */\nexport function toggleRow(\n current: readonly string[],\n mode: SelectionMode,\n id: string,\n): SelectionStep | undefined {\n if (mode === 'none') return undefined;\n if (current.includes(id)) return { selection: current.filter((s) => s !== id), anchor: id };\n return { selection: mode === 'single' ? [id] : [...current, id], anchor: id };\n}\n\n/**\n * The rows from index `from` to `to` (either order, both inclusive), in row\n * order. With `add`, they join the current selection instead of replacing it.\n * The anchor stays where it was.\n */\nexport function selectRange(\n current: readonly string[],\n from: number,\n to: number,\n idAt: (index: number) => string | undefined,\n add: boolean,\n): SelectionState {\n const ids: string[] = add ? [...current] : [];\n const have = new Set(ids);\n const step = to >= from ? 1 : -1;\n const [first, last] = step === 1 ? [from, to] : [to, from];\n for (let index = first; index <= last; index++) {\n const id = idAt(index);\n if (id === undefined || have.has(id)) continue;\n have.add(id);\n ids.push(id);\n }\n return ids;\n}\n\n/**\n * Every row of `ids` selected, keeping the rows already selected (with a\n * `dataSource`, `ids` are only the loaded rows: selected rows elsewhere stay).\n */\nexport function selectAll(current: readonly string[], ids: readonly string[]): SelectionState {\n const have = new Set(current);\n return [...current, ...ids.filter((id) => !have.has(id))];\n}\n\n/**\n * A click on a row, desktop style. A plain click selects only that row; Ctrl or\n * Cmd toggles it. In `'multi'` mode, Shift selects the range from the anchor\n * (at `anchorIndex`) to the row, and Ctrl+Shift adds that range. Without an\n * anchor in the current rows, Shift acts like a plain click. `undefined` in\n * `'none'` mode. The selection may come back unchanged (a click on the one\n * selected row): check with `sameSelection` before reporting a change.\n */\nexport function clickSelection(\n current: readonly string[],\n mode: SelectionMode,\n target: SelectionTarget,\n anchor: { id: string; index: number } | undefined,\n modifiers: SelectionModifiers,\n idAt: (index: number) => string | undefined,\n): SelectionStep | undefined {\n if (mode === 'none') return undefined;\n if (mode === 'multi' && modifiers.range && anchor) {\n return {\n selection: selectRange(current, anchor.index, target.index, idAt, modifiers.toggle),\n anchor: anchor.id,\n };\n }\n if (modifiers.toggle) return toggleRow(current, mode, target.id);\n return { selection: [target.id], anchor: target.id };\n}\n"],"mappings":";;AA+BA,SAAgB,cAAc,GAAsB,GAA+B;CACjF,IAAI,EAAE,WAAW,EAAE,QAAQ,OAAO;CAClC,MAAM,MAAM,IAAI,IAAI,CAAC;CACrB,OAAO,EAAE,OAAO,OAAO,IAAI,IAAI,EAAE,CAAC;AACpC;;;;;AAMA,SAAgB,UACd,SACA,MACA,IAC2B;CAC3B,IAAI,SAAS,QAAQ,OAAO,KAAA;CAC5B,IAAI,QAAQ,SAAS,EAAE,GAAG,OAAO;EAAE,WAAW,QAAQ,QAAQ,MAAM,MAAM,EAAE;EAAG,QAAQ;CAAG;CAC1F,OAAO;EAAE,WAAW,SAAS,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,SAAS,EAAE;EAAG,QAAQ;CAAG;AAC9E;;;;;;AAOA,SAAgB,YACd,SACA,MACA,IACA,MACA,KACgB;CAChB,MAAM,MAAgB,MAAM,CAAC,GAAG,OAAO,IAAI,CAAC;CAC5C,MAAM,OAAO,IAAI,IAAI,GAAG;CAExB,MAAM,CAAC,OAAO,SADD,MAAM,OAAO,IAAI,QACC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI;CACzD,KAAK,IAAI,QAAQ,OAAO,SAAS,MAAM,SAAS;EAC9C,MAAM,KAAK,KAAK,KAAK;EACrB,IAAI,OAAO,KAAA,KAAa,KAAK,IAAI,EAAE,GAAG;EACtC,KAAK,IAAI,EAAE;EACX,IAAI,KAAK,EAAE;CACb;CACA,OAAO;AACT;;;;;AAMA,SAAgB,UAAU,SAA4B,KAAwC;CAC5F,MAAM,OAAO,IAAI,IAAI,OAAO;CAC5B,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,QAAQ,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AAC1D;;;;;;;;;AAUA,SAAgB,eACd,SACA,MACA,QACA,QACA,WACA,MAC2B;CAC3B,IAAI,SAAS,QAAQ,OAAO,KAAA;CAC5B,IAAI,SAAS,WAAW,UAAU,SAAS,QACzC,OAAO;EACL,WAAW,YAAY,SAAS,OAAO,OAAO,OAAO,OAAO,MAAM,UAAU,MAAM;EAClF,QAAQ,OAAO;CACjB;CAEF,IAAI,UAAU,QAAQ,OAAO,UAAU,SAAS,MAAM,OAAO,EAAE;CAC/D,OAAO;EAAE,WAAW,CAAC,OAAO,EAAE;EAAG,QAAQ,OAAO;CAAG;AACrD"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { moveColumn, normalizeOrder } from "../columns/column-order.js";
|
|
2
2
|
import { resolveColumns } from "../columns/resolve-columns.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { distinctValues, rowPredicate } from "../filters/filter.js";
|
|
4
|
+
import { filteredRowModel, setRowPredicate } from "./filtered-row-model.js";
|
|
5
|
+
import { sortedRowModel, valuesChanged } from "./sorted-row-model.js";
|
|
6
|
+
import { columnSizingFeature, constructTable, rowSortingFeature, sortFn_alphanumeric, sortFn_basic, sortFn_datetime, sortFn_text, tableFeatures } from "@tanstack/table-core";
|
|
5
7
|
import { storeReactivityBindings } from "@tanstack/table-core/store-reactivity-bindings";
|
|
6
8
|
// ../core/src/table/create-table.ts
|
|
7
9
|
var features = tableFeatures({
|
|
8
10
|
coreReactivityFeature: storeReactivityBindings(),
|
|
9
|
-
columnPinningFeature,
|
|
10
11
|
columnSizingFeature,
|
|
11
12
|
rowSortingFeature,
|
|
13
|
+
filteredRowModel: filteredRowModel(),
|
|
12
14
|
sortedRowModel: sortedRowModel(),
|
|
13
15
|
sortFns: {
|
|
14
16
|
alphanumeric: sortFn_alphanumeric,
|
|
@@ -17,7 +19,51 @@ var features = tableFeatures({
|
|
|
17
19
|
text: sortFn_text
|
|
18
20
|
}
|
|
19
21
|
});
|
|
22
|
+
/**
|
|
23
|
+
* Id of the selection column, the checkbox column the model adds first when
|
|
24
|
+
* `selectionColumn` is set. Not a column of `columns`: it never appears in the
|
|
25
|
+
* column order, sizing or events.
|
|
26
|
+
*/
|
|
27
|
+
var SELECTION_COLUMN_ID = "--argus-selection";
|
|
20
28
|
var defaultRowId = (_row, index) => String(index);
|
|
29
|
+
/**
|
|
30
|
+
* Ids of the columns kept from `before` whose accessor changed: a new function,
|
|
31
|
+
* or a different path. A new column has nothing cached and isn't listed.
|
|
32
|
+
*/
|
|
33
|
+
function changedAccessors(before, after) {
|
|
34
|
+
const old = new Map(before.map((c) => [c.id, c.accessor]));
|
|
35
|
+
return after.filter((c) => old.has(c.id) && old.get(c.id) !== c.accessor).map((c) => c.id);
|
|
36
|
+
}
|
|
37
|
+
/** The selection column's view: first, pinned to the start, fixed, and inert to sorting, sizing and moves. */
|
|
38
|
+
function selectionView(pinEdge) {
|
|
39
|
+
return {
|
|
40
|
+
id: SELECTION_COLUMN_ID,
|
|
41
|
+
kind: "selection",
|
|
42
|
+
colIndex: 1,
|
|
43
|
+
pin: "start",
|
|
44
|
+
offset: 0,
|
|
45
|
+
pinEdge,
|
|
46
|
+
hidden: false,
|
|
47
|
+
width: 40,
|
|
48
|
+
flex: void 0,
|
|
49
|
+
auto: false,
|
|
50
|
+
minWidth: 40,
|
|
51
|
+
maxWidth: 40,
|
|
52
|
+
sortable: false,
|
|
53
|
+
resizable: false,
|
|
54
|
+
reorderable: false,
|
|
55
|
+
pinnable: false,
|
|
56
|
+
hideable: false,
|
|
57
|
+
filter: void 0,
|
|
58
|
+
filtered: false,
|
|
59
|
+
align: "center",
|
|
60
|
+
wrap: false,
|
|
61
|
+
sorted: false,
|
|
62
|
+
header: void 0,
|
|
63
|
+
cell: void 0,
|
|
64
|
+
hasAccessor: false
|
|
65
|
+
};
|
|
66
|
+
}
|
|
21
67
|
function toTanStack(column) {
|
|
22
68
|
return {
|
|
23
69
|
id: column.id,
|
|
@@ -30,9 +76,12 @@ function toTanStack(column) {
|
|
|
30
76
|
};
|
|
31
77
|
}
|
|
32
78
|
/**
|
|
33
|
-
* Creates the table model over TanStack Table. It owns no state: sorting, sizing
|
|
34
|
-
* come in through `update()`, and
|
|
79
|
+
* Creates the table model over TanStack Table. It owns no state: sorting, sizing, order,
|
|
80
|
+
* pinning and visibility come in through `update()`, and the `next*()` methods only propose
|
|
35
81
|
* changes, so the caller decides (controlled or uncontrolled) whether to apply them.
|
|
82
|
+
*
|
|
83
|
+
* Hidden columns stay in TanStack, so their values still sort and read; only the
|
|
84
|
+
* views leave them out. Pin groups, sticky offsets and the order are the model's own.
|
|
36
85
|
*/
|
|
37
86
|
function createTableModel(initial) {
|
|
38
87
|
let options = initial;
|
|
@@ -40,40 +89,56 @@ function createTableModel(initial) {
|
|
|
40
89
|
let byId = new Map(resolved.map((c) => [c.id, c]));
|
|
41
90
|
let tanStackById = new Map(resolved.map((c) => [c.id, toTanStack(c)]));
|
|
42
91
|
let views;
|
|
92
|
+
const pinOf = (column, pinning = options.columnPinning) => {
|
|
93
|
+
const state = pinning?.[column.id];
|
|
94
|
+
if (state === "start" || state === "end") return state;
|
|
95
|
+
return state === false ? void 0 : column.pin;
|
|
96
|
+
};
|
|
97
|
+
const hiddenOf = (column, visibility = options.columnVisibility) => {
|
|
98
|
+
const state = visibility?.[column.id];
|
|
99
|
+
return typeof state === "boolean" ? !state : column.hidden;
|
|
100
|
+
};
|
|
101
|
+
const shown = (id) => {
|
|
102
|
+
const column = byId.get(id);
|
|
103
|
+
return column !== void 0 && !hiddenOf(column);
|
|
104
|
+
};
|
|
43
105
|
let sizing;
|
|
44
106
|
const sizingState = () => {
|
|
45
107
|
if (sizing) return sizing;
|
|
46
108
|
const auto = options.autoWidths;
|
|
47
|
-
if (!auto) return sizing = options.columnSizing;
|
|
48
109
|
const merged = {};
|
|
110
|
+
let any = false;
|
|
49
111
|
for (const column of resolved) {
|
|
50
|
-
|
|
112
|
+
if (column.flex !== void 0 && pinOf(column) !== void 0) {
|
|
113
|
+
merged[column.id] = column.pinnedWidth;
|
|
114
|
+
any = true;
|
|
115
|
+
}
|
|
116
|
+
const px = auto?.[column.id];
|
|
51
117
|
if (!column.auto || px === void 0 || !Number.isFinite(px)) continue;
|
|
52
118
|
merged[column.id] = Math.min(column.maxWidth, Math.max(column.minWidth, px));
|
|
119
|
+
any = true;
|
|
53
120
|
}
|
|
54
|
-
return sizing = {
|
|
121
|
+
return sizing = any ? {
|
|
55
122
|
...merged,
|
|
56
123
|
...options.columnSizing
|
|
57
|
-
};
|
|
124
|
+
} : options.columnSizing;
|
|
58
125
|
};
|
|
126
|
+
const orderable = () => resolved.map((c) => ({
|
|
127
|
+
id: c.id,
|
|
128
|
+
pin: pinOf(c),
|
|
129
|
+
reorderable: c.reorderable
|
|
130
|
+
}));
|
|
59
131
|
let order;
|
|
60
|
-
const orderState = () => order ??= normalizeOrder(options.columnOrder ?? [],
|
|
132
|
+
const orderState = () => order ??= normalizeOrder(options.columnOrder ?? [], orderable());
|
|
61
133
|
const rowViews = /* @__PURE__ */ new WeakMap();
|
|
62
134
|
let indexById;
|
|
63
135
|
let ordered;
|
|
64
136
|
const orderedColumns = () => {
|
|
65
137
|
const current = orderState();
|
|
66
|
-
if (ordered?.order !== current) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
columns: current.flatMap((id) => tanStackById.get(id) ?? []),
|
|
71
|
-
pinning: {
|
|
72
|
-
start: current.filter((id) => pinOf(id) === "start"),
|
|
73
|
-
end: current.filter((id) => pinOf(id) === "end")
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
}
|
|
138
|
+
if (ordered?.order !== current) ordered = {
|
|
139
|
+
order: current,
|
|
140
|
+
columns: current.flatMap((id) => tanStackById.get(id) ?? [])
|
|
141
|
+
};
|
|
77
142
|
return ordered;
|
|
78
143
|
};
|
|
79
144
|
const tableOptions = () => ({
|
|
@@ -83,51 +148,95 @@ function createTableModel(initial) {
|
|
|
83
148
|
getRowId: options.getRowId ?? defaultRowId,
|
|
84
149
|
state: {
|
|
85
150
|
sorting: options.sorting,
|
|
86
|
-
columnSizing: sizingState()
|
|
87
|
-
columnPinning: orderedColumns().pinning
|
|
151
|
+
columnSizing: sizingState()
|
|
88
152
|
},
|
|
89
153
|
onSortingChange: () => void 0,
|
|
90
|
-
onColumnSizingChange: () => void 0
|
|
91
|
-
onColumnPinningChange: () => void 0
|
|
154
|
+
onColumnSizingChange: () => void 0
|
|
92
155
|
});
|
|
93
156
|
const table = constructTable(tableOptions());
|
|
157
|
+
const predicateFor = (except) => options.remote ? void 0 : rowPredicate(byId, options.columnFilters, options.quickFilter, resolved.filter((c) => c.hasAccessor && !hiddenOf(c)), except);
|
|
158
|
+
setRowPredicate(table, predicateFor());
|
|
94
159
|
const rows = () => table.getRowModel().rows;
|
|
95
160
|
const pinned = (side) => options.pinnedRows?.[side] ?? [];
|
|
161
|
+
const widthOf = (id) => table.getColumn(id)?.getSize() ?? 0;
|
|
162
|
+
const view = (def, colIndex, offset, pinEdge, width) => {
|
|
163
|
+
const sort = options.sorting.find((s) => s.id === def.id);
|
|
164
|
+
const pin = pinOf(def);
|
|
165
|
+
const resized = options.columnSizing[def.id] !== void 0;
|
|
166
|
+
return {
|
|
167
|
+
id: def.id,
|
|
168
|
+
kind: "data",
|
|
169
|
+
colIndex,
|
|
170
|
+
pin,
|
|
171
|
+
offset,
|
|
172
|
+
pinEdge,
|
|
173
|
+
hidden: colIndex === 0,
|
|
174
|
+
width,
|
|
175
|
+
flex: pin === void 0 && !resized ? def.flex : void 0,
|
|
176
|
+
auto: def.auto && !resized,
|
|
177
|
+
minWidth: def.minWidth,
|
|
178
|
+
maxWidth: def.maxWidth,
|
|
179
|
+
sortable: def.sortable,
|
|
180
|
+
resizable: def.resizable,
|
|
181
|
+
reorderable: def.reorderable,
|
|
182
|
+
pinnable: def.pinnable,
|
|
183
|
+
hideable: def.hideable,
|
|
184
|
+
filter: def.filter,
|
|
185
|
+
filtered: options.columnFilters?.[def.id] !== void 0,
|
|
186
|
+
align: def.align,
|
|
187
|
+
wrap: def.wrap,
|
|
188
|
+
sorted: sort ? sort.desc ? "desc" : "asc" : false,
|
|
189
|
+
header: def.header,
|
|
190
|
+
cell: def.cell,
|
|
191
|
+
hasAccessor: def.hasAccessor
|
|
192
|
+
};
|
|
193
|
+
};
|
|
96
194
|
const buildViews = () => {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const view = (column, colIndex, offset, pinEdge) => {
|
|
102
|
-
const def = byId.get(column.id);
|
|
103
|
-
if (!def) throw new Error(`argus-table: unknown column '${column.id}'.`);
|
|
104
|
-
const sort = sorting.find((s) => s.id === column.id);
|
|
105
|
-
return {
|
|
106
|
-
id: def.id,
|
|
107
|
-
colIndex,
|
|
108
|
-
pin: def.pin,
|
|
109
|
-
offset,
|
|
110
|
-
pinEdge,
|
|
111
|
-
width: column.getSize(),
|
|
112
|
-
flex: options.columnSizing[def.id] === void 0 ? def.flex : void 0,
|
|
113
|
-
auto: def.auto && options.columnSizing[def.id] === void 0,
|
|
114
|
-
minWidth: def.minWidth,
|
|
115
|
-
maxWidth: def.maxWidth,
|
|
116
|
-
sortable: def.sortable,
|
|
117
|
-
resizable: def.resizable,
|
|
118
|
-
reorderable: def.reorderable,
|
|
119
|
-
align: def.align,
|
|
120
|
-
sorted: sort ? sort.desc ? "desc" : "asc" : false,
|
|
121
|
-
header: def.header,
|
|
122
|
-
cell: def.cell,
|
|
123
|
-
hasAccessor: def.hasAccessor
|
|
124
|
-
};
|
|
195
|
+
const groups = {
|
|
196
|
+
start: [],
|
|
197
|
+
center: [],
|
|
198
|
+
end: []
|
|
125
199
|
};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
200
|
+
for (const id of orderState()) {
|
|
201
|
+
const def = byId.get(id);
|
|
202
|
+
if (def && !hiddenOf(def)) groups[pinOf(def) ?? "center"].push(def);
|
|
203
|
+
}
|
|
204
|
+
const { start, center, end } = groups;
|
|
205
|
+
const lead = options.selectionColumn ? 1 : 0;
|
|
206
|
+
if (lead && byId.has("--argus-selection")) throw new Error(`argus-table: the column id '${SELECTION_COLUMN_ID}' is reserved.`);
|
|
207
|
+
let x = lead * 40;
|
|
208
|
+
const list = start.map((def, i) => {
|
|
209
|
+
const width = widthOf(def.id);
|
|
210
|
+
const v = view(def, lead + i + 1, x, i === start.length - 1, width);
|
|
211
|
+
x += width;
|
|
212
|
+
return v;
|
|
213
|
+
});
|
|
214
|
+
x = 0;
|
|
215
|
+
for (const [i, def] of center.entries()) {
|
|
216
|
+
const width = widthOf(def.id);
|
|
217
|
+
list.push(view(def, lead + start.length + i + 1, x, false, width));
|
|
218
|
+
x += width;
|
|
219
|
+
}
|
|
220
|
+
const ends = [];
|
|
221
|
+
x = 0;
|
|
222
|
+
for (const [i, def] of [...end.entries()].reverse()) {
|
|
223
|
+
const width = widthOf(def.id);
|
|
224
|
+
ends.unshift(view(def, lead + start.length + center.length + i + 1, x, i === 0, width));
|
|
225
|
+
x += width;
|
|
226
|
+
}
|
|
227
|
+
list.push(...ends);
|
|
228
|
+
if (lead) list.unshift(selectionView(start.length === 0));
|
|
229
|
+
return list;
|
|
230
|
+
};
|
|
231
|
+
let allViews;
|
|
232
|
+
const buildAllViews = (shownViews) => {
|
|
233
|
+
const byShownId = new Map(shownViews.map((v) => [v.id, v]));
|
|
234
|
+
return orderState().flatMap((id) => {
|
|
235
|
+
const shownView = byShownId.get(id);
|
|
236
|
+
if (shownView) return [shownView];
|
|
237
|
+
const def = byId.get(id);
|
|
238
|
+
return def ? [view(def, 0, 0, false, widthOf(id))] : [];
|
|
239
|
+
});
|
|
131
240
|
};
|
|
132
241
|
return {
|
|
133
242
|
update(next) {
|
|
@@ -136,28 +245,44 @@ function createTableModel(initial) {
|
|
|
136
245
|
...next
|
|
137
246
|
};
|
|
138
247
|
if (!Object.keys(next).some((key) => next[key] !== options[key])) return;
|
|
248
|
+
let reread = [];
|
|
139
249
|
if (next.columns && next.columns !== options.columns) {
|
|
250
|
+
reread = changedAccessors(options.columns, next.columns);
|
|
140
251
|
resolved = resolveColumns(next.columns);
|
|
141
252
|
byId = new Map(resolved.map((c) => [c.id, c]));
|
|
142
253
|
tanStackById = new Map(resolved.map((c) => [c.id, toTanStack(c)]));
|
|
143
254
|
}
|
|
144
|
-
|
|
145
|
-
if (merged.columns !== options.columns || merged.
|
|
255
|
+
const pinningChanged = merged.columnPinning !== options.columnPinning;
|
|
256
|
+
if (merged.columns !== options.columns || merged.columnSizing !== options.columnSizing || merged.autoWidths !== options.autoWidths || pinningChanged) sizing = void 0;
|
|
257
|
+
if (merged.columns !== options.columns || merged.columnOrder !== options.columnOrder || pinningChanged) order = void 0;
|
|
258
|
+
const refilter = merged.columns !== options.columns || merged.columnFilters !== options.columnFilters || merged.quickFilter !== options.quickFilter || merged.columnVisibility !== options.columnVisibility || merged.remote !== options.remote;
|
|
146
259
|
options = merged;
|
|
147
260
|
views = void 0;
|
|
261
|
+
allViews = void 0;
|
|
262
|
+
if (refilter) setRowPredicate(table, predicateFor());
|
|
148
263
|
table.setOptions((prev) => ({
|
|
149
264
|
...prev,
|
|
150
265
|
...tableOptions()
|
|
151
266
|
}));
|
|
267
|
+
if (reread.length && !options.remote) {
|
|
268
|
+
for (const row of table.getCoreRowModel().rows) for (const id of reread) Reflect.deleteProperty(row._valuesCache, id);
|
|
269
|
+
valuesChanged(table);
|
|
270
|
+
}
|
|
152
271
|
},
|
|
153
272
|
get columns() {
|
|
154
273
|
return views ??= buildViews();
|
|
155
274
|
},
|
|
275
|
+
get allColumns() {
|
|
276
|
+
return allViews ??= buildAllViews(this.columns);
|
|
277
|
+
},
|
|
156
278
|
get rowCount() {
|
|
157
279
|
return options.remote?.rowCount ?? rows().length;
|
|
158
280
|
},
|
|
281
|
+
get rowOrder() {
|
|
282
|
+
return options.remote ?? rows();
|
|
283
|
+
},
|
|
159
284
|
get totalWidth() {
|
|
160
|
-
return
|
|
285
|
+
return this.columns.reduce((sum, column) => sum + column.width, 0);
|
|
161
286
|
},
|
|
162
287
|
rowAt(index) {
|
|
163
288
|
if (options.remote) {
|
|
@@ -190,6 +315,10 @@ function createTableModel(initial) {
|
|
|
190
315
|
};
|
|
191
316
|
return indexById.map.get(rowId);
|
|
192
317
|
},
|
|
318
|
+
selectableIds() {
|
|
319
|
+
if (options.remote) return options.remote.loadedIds();
|
|
320
|
+
return rows().map((r) => r.id);
|
|
321
|
+
},
|
|
193
322
|
valueAt(index, columnId) {
|
|
194
323
|
if (options.remote) {
|
|
195
324
|
const entry = options.remote.entryAt(index);
|
|
@@ -242,10 +371,56 @@ function createTableModel(initial) {
|
|
|
242
371
|
};
|
|
243
372
|
},
|
|
244
373
|
orderOf(base) {
|
|
245
|
-
return base === void 0 ? orderState() : normalizeOrder(base,
|
|
374
|
+
return base === void 0 ? orderState() : normalizeOrder(base, orderable());
|
|
246
375
|
},
|
|
247
376
|
nextOrder(columnId, to, base) {
|
|
248
|
-
return moveColumn(base ?? orderState(),
|
|
377
|
+
return moveColumn(base ?? orderState(), orderable(), columnId, to, shown);
|
|
378
|
+
},
|
|
379
|
+
nextPinning(columnId, pin, base = options.columnPinning) {
|
|
380
|
+
const column = byId.get(columnId);
|
|
381
|
+
if (!column?.pinnable || (pinOf(column, base) ?? false) === pin) return void 0;
|
|
382
|
+
return {
|
|
383
|
+
...base,
|
|
384
|
+
[columnId]: pin
|
|
385
|
+
};
|
|
386
|
+
},
|
|
387
|
+
nextVisibility(columnId, hidden, base = options.columnVisibility) {
|
|
388
|
+
const column = byId.get(columnId);
|
|
389
|
+
if (!column || hiddenOf(column, base) === hidden) return void 0;
|
|
390
|
+
const othersShown = resolved.some((c) => c !== column && !hiddenOf(c, base));
|
|
391
|
+
if (hidden && (!column.hideable || !othersShown)) return void 0;
|
|
392
|
+
return {
|
|
393
|
+
...base,
|
|
394
|
+
[columnId]: !hidden
|
|
395
|
+
};
|
|
396
|
+
},
|
|
397
|
+
nextFilters(columnId, filter, base = options.columnFilters ?? {}) {
|
|
398
|
+
const column = byId.get(columnId);
|
|
399
|
+
if (!column) return void 0;
|
|
400
|
+
const current = base[columnId];
|
|
401
|
+
if (filter === void 0) {
|
|
402
|
+
if (current === void 0) return void 0;
|
|
403
|
+
const next = { ...base };
|
|
404
|
+
Reflect.deleteProperty(next, columnId);
|
|
405
|
+
return next;
|
|
406
|
+
}
|
|
407
|
+
if (column.filter === void 0) return void 0;
|
|
408
|
+
if (current && JSON.stringify(current) === JSON.stringify(filter)) return void 0;
|
|
409
|
+
return {
|
|
410
|
+
...base,
|
|
411
|
+
[columnId]: filter
|
|
412
|
+
};
|
|
413
|
+
},
|
|
414
|
+
filterValues(columnId, limit = 1e3) {
|
|
415
|
+
const column = byId.get(columnId);
|
|
416
|
+
if (!column) return void 0;
|
|
417
|
+
if (column.filterOptions) return {
|
|
418
|
+
values: [...column.filterOptions],
|
|
419
|
+
truncated: false
|
|
420
|
+
};
|
|
421
|
+
if (options.remote) return void 0;
|
|
422
|
+
const rows = table.getCoreRowModel().rows;
|
|
423
|
+
return distinctValues(rows, column, predicateFor(columnId), limit);
|
|
249
424
|
},
|
|
250
425
|
pinnedCount(side) {
|
|
251
426
|
return pinned(side).length;
|
|
@@ -278,6 +453,6 @@ function createTableModel(initial) {
|
|
|
278
453
|
}
|
|
279
454
|
};
|
|
280
455
|
}
|
|
281
|
-
export { createTableModel };
|
|
456
|
+
export { SELECTION_COLUMN_ID, createTableModel };
|
|
282
457
|
|
|
283
458
|
//# sourceMappingURL=create-table.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-table.js","names":[],"sources":["../../../../../core/src/table/create-table.ts"],"sourcesContent":["import {\n columnPinningFeature,\n columnSizingFeature,\n constructTable,\n rowSortingFeature,\n sortFn_alphanumeric,\n sortFn_basic,\n sortFn_datetime,\n sortFn_text,\n tableFeatures,\n type Column,\n type ColumnDef as TanStackColumnDef,\n type Row,\n type Table,\n type TableOptions,\n} from '@tanstack/table-core';\nimport { storeReactivityBindings } from '@tanstack/table-core/store-reactivity-bindings';\nimport { moveColumn, normalizeOrder } from '../columns/column-order.js';\nimport { resolveColumns, type ResolvedColumn } from '../columns/resolve-columns.js';\nimport { sortedRowModel } from './sorted-row-model.js';\nimport type {\n CellContext,\n ColumnAlign,\n ColumnDef,\n ColumnOrderState,\n ColumnPin,\n ColumnSizingState,\n PinnedRows,\n RowPin,\n SortState,\n} from '../types.js';\n\n// The TanStack adapter. Everything TanStack stays in this module: callers only see\n// the view types below, so TanStack can be upgraded or replaced without touching\n// `argus-table`'s public API.\n\nconst features = tableFeatures({\n // Vanilla (framework-free) reactivity; required by `constructTable`.\n coreReactivityFeature: storeReactivityBindings(),\n columnPinningFeature,\n columnSizingFeature,\n rowSortingFeature,\n // Our own: TanStack's is very slow in Firefox at scale (see sorted-row-model.ts).\n sortedRowModel: sortedRowModel(),\n // Registered by name so `sortFn: 'auto'` can pick one by value type.\n sortFns: {\n alphanumeric: sortFn_alphanumeric,\n basic: sortFn_basic,\n datetime: sortFn_datetime,\n text: sortFn_text,\n },\n});\ntype Features = typeof features;\ntype AnyRow = Record<string, unknown>;\n\n/** Sort direction of a column, or `false` when it isn't sorted. */\nexport type SortDirection = 'asc' | 'desc' | false;\n\n/** A column as the renderer sees it, in visual order: start-pinned, scrolling, end-pinned. */\nexport interface ColumnView<TData, TContent> {\n id: string;\n /** 1-based position in visual order, for `aria-colindex`. */\n colIndex: number;\n pin: ColumnPin | undefined;\n /**\n * Sticky inset in px: from the start edge for `'start'` columns, from the end edge\n * for `'end'` columns. For scrolling columns, the start within the scrolling area.\n */\n offset: number;\n /** `true` on the pinned column next to the scrolling area (one per pinned side). */\n pinEdge: boolean;\n /** Current width in px (a resized width wins over the column's own). */\n width: number;\n /** Share of free space, or `undefined` for a fixed width. A resized column stops flexing. */\n flex: number | undefined;\n /**\n * `true` for a `width: 'auto'` column that hasn't been resized: the table measures\n * its content and passes the width in as `autoWidths`.\n */\n auto: boolean;\n minWidth: number;\n maxWidth: number;\n sortable: boolean;\n resizable: boolean;\n reorderable: boolean;\n align: ColumnAlign;\n sorted: SortDirection;\n header: ColumnDef<TData, TContent>['header'];\n cell: ColumnDef<TData, TContent>['cell'];\n hasAccessor: boolean;\n}\n\n/** A row of the current (sorted) row model. */\nexport interface RowView<TData> {\n id: string;\n /** Index in the current row model, 0-based. */\n index: number;\n original: TData;\n}\n\n/**\n * Rows that live outside the model, loaded page by page (`dataSource`). The\n * source sorts them, so the model reads them as they are. `PageCache` implements it.\n */\nexport interface RemoteRows<TData> {\n readonly rowCount: number;\n /** The loaded row at an index, with its id; `undefined` while it isn't loaded. */\n entryAt(index: number): { id: string; row: TData } | undefined;\n /** The index of a loaded row's id, or `undefined`. */\n indexOf(rowId: string): number | undefined;\n}\n\nexport interface TableModelOptions<TData, TContent> {\n columns: readonly ColumnDef<TData, TContent>[];\n data: readonly TData[];\n /**\n * Remote rows. When set, rows come from here instead of `data`, and the model\n * doesn't sort them (the source does).\n */\n remote?: RemoteRows<TData> | undefined;\n /** Row id function. Default: the row's index in `data`, as a string. */\n getRowId: ((row: TData, index: number) => string) | undefined;\n /** Current sort state; its owner is the caller (see `controllable`). */\n sorting: SortState;\n /** Current resized widths; its owner is the caller. */\n columnSizing: ColumnSizingState;\n /**\n * Current column order; its owner is the caller. Each pin group follows it; an\n * empty array (the default) keeps the order of `columns`.\n */\n columnOrder?: ColumnOrderState | undefined;\n /**\n * Measured widths of `width: 'auto'` columns, in px by id. Clamped to the column's\n * bounds; a resized width wins. Ids of other columns are ignored.\n */\n autoWidths?: ColumnSizingState | undefined;\n /** Rows fixed above or below the body. They stay out of the row model: never sorted, not counted. */\n pinnedRows?: PinnedRows<TData> | undefined;\n}\n\nexport interface TableModel<TData, TContent> {\n /** Updates any subset of the options. Unchanged references are ignored. */\n update(options: Partial<TableModelOptions<TData, TContent>>): void;\n /** Columns in visual order. */\n readonly columns: readonly ColumnView<TData, TContent>[];\n /** Number of rows in the current row model. */\n readonly rowCount: number;\n /** Sum of all column widths in px (flex columns count their minimum). */\n readonly totalWidth: number;\n /** The row at an index of the current row model; `undefined` for a remote row not loaded yet. */\n rowAt(index: number): RowView<TData> | undefined;\n /** The index of a row id in the current row model (after sorting), or `undefined`. */\n indexOf(rowId: string): number | undefined;\n /** The value a column reads from the row at `index`. */\n valueAt(index: number, columnId: string): unknown;\n /** What a column's `cell` function receives for the row at `index`. */\n cellContext(index: number, columnId: string): CellContext<TData> | undefined;\n /**\n * The sort state that clicking this column's header would produce:\n * asc → desc → unsorted, one column at a time. `undefined` if it can't sort.\n */\n nextSorting(columnId: string): SortState | undefined;\n /**\n * The sizing state after setting a column to `width` px, clamped to its bounds.\n * `undefined` if the column can't be resized.\n */\n nextSizing(columnId: string, width: number): ColumnSizingState | undefined;\n /**\n * The full column order as the table shows it: start-pinned, scrolling and\n * end-pinned ids. `base` defaults to the current `columnOrder`.\n */\n orderOf(base?: readonly string[]): ColumnOrderState;\n /**\n * The order after moving a column to position `to` (0-based, in the whole order,\n * counted after the move), starting from `base` (default: the current order).\n * `undefined` if the column can't move, `to` is outside its pin group, or nothing changes.\n */\n nextOrder(columnId: string, to: number, base?: readonly string[]): ColumnOrderState | undefined;\n /** Number of rows pinned to a side. */\n pinnedCount(side: RowPin): number;\n /**\n * A pinned row, `index` counted within its side. Its id comes from `getRowId`,\n * else it is `'top-{index}'` or `'bottom-{index}'`, apart from the data rows' index ids.\n */\n pinnedRowAt(side: RowPin, index: number): RowView<TData> | undefined;\n /** The value a column reads from a pinned row. */\n pinnedValueAt(side: RowPin, index: number, columnId: string): unknown;\n /** What a column's `cell` function receives for a pinned row (with `pinned` set). */\n pinnedCellContext(side: RowPin, index: number, columnId: string): CellContext<TData> | undefined;\n}\n\nconst defaultRowId = (_row: unknown, index: number) => String(index);\n\nfunction toTanStack<TData, TContent>(\n column: ResolvedColumn<TData, TContent>,\n): TanStackColumnDef<Features, AnyRow> {\n return {\n id: column.id,\n accessorFn: column.getValue as (row: AnyRow, index: number) => unknown,\n size: column.width,\n minSize: column.minWidth,\n maxSize: column.maxWidth,\n enableSorting: column.sortable,\n sortUndefined: 'last',\n };\n}\n\n/**\n * Creates the table model over TanStack Table. It owns no state: sorting, sizing and order\n * come in through `update()`, and `nextSorting()`, `nextSizing()` and `nextOrder()` only propose\n * changes, so the caller decides (controlled or uncontrolled) whether to apply them.\n */\nexport function createTableModel<TData, TContent>(\n initial: TableModelOptions<TData, TContent>,\n): TableModel<TData, TContent> {\n let options = initial;\n let resolved = resolveColumns(options.columns);\n let byId = new Map(resolved.map((c) => [c.id, c]));\n // TanStack column defs by id, kept between updates that don't change `columns`.\n let tanStackById = new Map(resolved.map((c) => [c.id, toTanStack(c)]));\n let views: ColumnView<TData, TContent>[] | undefined;\n // TanStack's sizing state: measured auto widths under the resized ones. Kept stable\n // between updates that don't touch either.\n let sizing: ColumnSizingState | undefined;\n const sizingState = (): ColumnSizingState => {\n if (sizing) return sizing;\n const auto = options.autoWidths;\n if (!auto) return (sizing = options.columnSizing);\n const merged: ColumnSizingState = {};\n for (const column of resolved) {\n const px = auto[column.id];\n if (!column.auto || px === undefined || !Number.isFinite(px)) continue;\n merged[column.id] = Math.min(column.maxWidth, Math.max(column.minWidth, px));\n }\n return (sizing = { ...merged, ...options.columnSizing });\n };\n // The normalized order, kept stable between updates that touch neither columns nor order.\n let order: ColumnOrderState | undefined;\n const orderState = (): ColumnOrderState =>\n (order ??= normalizeOrder(options.columnOrder ?? [], resolved));\n const rowViews = new WeakMap<Row<Features, AnyRow>, RowView<TData>>();\n // Built lazily per row model (sorting or new data gives a new array).\n let indexById: { rows: readonly Row<Features, AnyRow>[]; map: Map<string, number> } | undefined;\n\n // The order reaches TanStack as the order of its column defs (the scrolling\n // columns follow it) and of the pinning arrays (the pinned ones do). Rebuilt only\n // when the order changes: a new columns array makes TanStack rebuild its columns,\n // though not its row models, which depend on data and sorting alone.\n let ordered:\n | {\n order: ColumnOrderState;\n columns: TanStackColumnDef<Features, AnyRow>[];\n pinning: { start: string[]; end: string[] };\n }\n | undefined;\n const orderedColumns = () => {\n const current = orderState();\n if (ordered?.order !== current) {\n const pinOf = (id: string) => byId.get(id)?.pin;\n ordered = {\n order: current,\n columns: current.flatMap((id) => tanStackById.get(id) ?? []),\n pinning: {\n start: current.filter((id) => pinOf(id) === 'start'),\n end: current.filter((id) => pinOf(id) === 'end'),\n },\n };\n }\n return ordered;\n };\n\n const tableOptions = (): TableOptions<Features, AnyRow> => ({\n features,\n columns: orderedColumns().columns,\n // Remote rows bypass TanStack's row models; it still handles columns and state.\n data: (options.remote ? [] : options.data) as AnyRow[],\n getRowId: (options.getRowId ?? defaultRowId) as (row: AnyRow, index: number) => string,\n state: {\n sorting: options.sorting,\n columnSizing: sizingState(),\n columnPinning: orderedColumns().pinning,\n },\n // State is owned by the caller; TanStack's own setters must not change it.\n onSortingChange: () => undefined,\n onColumnSizingChange: () => undefined,\n onColumnPinningChange: () => undefined,\n });\n\n const table: Table<Features, AnyRow> = constructTable(tableOptions());\n\n const rows = () => table.getRowModel().rows;\n const pinned = (side: RowPin): readonly TData[] => options.pinnedRows?.[side] ?? [];\n\n const buildViews = (): ColumnView<TData, TContent>[] => {\n const start = table.getStartLeafColumns();\n const center = table.getCenterLeafColumns();\n const end = table.getEndLeafColumns();\n const sorting = options.sorting;\n const view = (\n column: Column<Features, AnyRow>,\n colIndex: number,\n offset: number,\n pinEdge: boolean,\n ): ColumnView<TData, TContent> => {\n const def = byId.get(column.id);\n if (!def) throw new Error(`argus-table: unknown column '${column.id}'.`);\n const sort = sorting.find((s) => s.id === column.id);\n return {\n id: def.id,\n colIndex,\n pin: def.pin,\n offset,\n pinEdge,\n width: column.getSize(),\n flex: options.columnSizing[def.id] === undefined ? def.flex : undefined,\n auto: def.auto && options.columnSizing[def.id] === undefined,\n minWidth: def.minWidth,\n maxWidth: def.maxWidth,\n sortable: def.sortable,\n resizable: def.resizable,\n reorderable: def.reorderable,\n align: def.align,\n sorted: sort ? (sort.desc ? 'desc' : 'asc') : false,\n header: def.header,\n cell: def.cell,\n hasAccessor: def.hasAccessor,\n };\n };\n return [\n ...start.map((c, i) => view(c, i + 1, c.getStart('start'), i === start.length - 1)),\n ...center.map((c, i) => view(c, start.length + i + 1, c.getStart('center'), false)),\n ...end.map((c, i) =>\n view(c, start.length + center.length + i + 1, c.getAfter('end'), i === 0),\n ),\n ];\n };\n\n return {\n update(next) {\n const merged = { ...options, ...next };\n const changed = (Object.keys(next) as (keyof typeof next)[]).some(\n (key) => next[key] !== options[key],\n );\n if (!changed) return;\n if (next.columns && next.columns !== options.columns) {\n resolved = resolveColumns(next.columns);\n byId = new Map(resolved.map((c) => [c.id, c]));\n tanStackById = new Map(resolved.map((c) => [c.id, toTanStack(c)]));\n }\n if (\n merged.columns !== options.columns ||\n merged.columnSizing !== options.columnSizing ||\n merged.autoWidths !== options.autoWidths\n ) {\n sizing = undefined;\n }\n if (merged.columns !== options.columns || merged.columnOrder !== options.columnOrder) {\n order = undefined;\n }\n options = merged;\n views = undefined;\n table.setOptions((prev) => ({ ...prev, ...tableOptions() }));\n },\n\n get columns() {\n return (views ??= buildViews());\n },\n\n get rowCount() {\n return options.remote?.rowCount ?? rows().length;\n },\n\n get totalWidth() {\n return table.getTotalSize();\n },\n\n rowAt(index) {\n if (options.remote) {\n const entry = options.remote.entryAt(index);\n return entry && { id: entry.id, index, original: entry.row };\n }\n const row = rows()[index];\n if (!row) return undefined;\n let view = rowViews.get(row);\n if (view?.index !== index) {\n view = { id: row.id, index, original: row.original as TData };\n rowViews.set(row, view);\n }\n return view;\n },\n\n indexOf(rowId) {\n if (options.remote) return options.remote.indexOf(rowId);\n const current = rows();\n if (indexById?.rows !== current) {\n indexById = { rows: current, map: new Map(current.map((r, i) => [r.id, i])) };\n }\n return indexById.map.get(rowId);\n },\n\n valueAt(index, columnId) {\n if (options.remote) {\n const entry = options.remote.entryAt(index);\n return entry && byId.get(columnId)?.getValue(entry.row, index);\n }\n return rows()[index]?.getValue(columnId);\n },\n\n cellContext(index, columnId) {\n if (options.remote) {\n const entry = options.remote.entryAt(index);\n const column = byId.get(columnId);\n if (!entry || !column) return undefined;\n return {\n row: entry.row,\n rowId: entry.id,\n index,\n columnId,\n value: column.getValue(entry.row, index),\n };\n }\n const row = rows()[index];\n if (!row || !byId.has(columnId)) return undefined;\n return {\n row: row.original as TData,\n rowId: row.id,\n index,\n columnId,\n value: row.getValue(columnId),\n };\n },\n\n nextSorting(columnId) {\n if (byId.get(columnId)?.sortable !== true) return undefined;\n const current = options.sorting.find((s) => s.id === columnId);\n if (!current) return [{ id: columnId, desc: false }];\n return current.desc ? [] : [{ id: columnId, desc: true }];\n },\n\n nextSizing(columnId, width) {\n const column = byId.get(columnId);\n if (!column?.resizable || !Number.isFinite(width)) return undefined;\n const clamped = Math.round(Math.min(column.maxWidth, Math.max(column.minWidth, width)));\n return { ...options.columnSizing, [columnId]: clamped };\n },\n\n orderOf(base) {\n return base === undefined ? orderState() : normalizeOrder(base, resolved);\n },\n\n nextOrder(columnId, to, base) {\n return moveColumn(base ?? orderState(), resolved, columnId, to);\n },\n\n pinnedCount(side) {\n return pinned(side).length;\n },\n\n pinnedRowAt(side, index) {\n if (index < 0 || index >= pinned(side).length) return undefined;\n const row = pinned(side)[index] as TData;\n const id = options.getRowId ? options.getRowId(row, index) : `${side}-${String(index)}`;\n return { id, index, original: row };\n },\n\n pinnedValueAt(side, index, columnId) {\n if (index < 0 || index >= pinned(side).length) return undefined;\n return byId.get(columnId)?.getValue(pinned(side)[index] as TData, index);\n },\n\n pinnedCellContext(side, index, columnId) {\n const row = this.pinnedRowAt(side, index);\n const column = byId.get(columnId);\n if (!row || !column) return undefined;\n return {\n row: row.original,\n rowId: row.id,\n index,\n columnId,\n value: column.getValue(row.original, index),\n pinned: side,\n };\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"create-table.js","names":[],"sources":["../../../../../core/src/table/create-table.ts"],"sourcesContent":["import {\n columnSizingFeature,\n constructTable,\n rowSortingFeature,\n sortFn_alphanumeric,\n sortFn_basic,\n sortFn_datetime,\n sortFn_text,\n tableFeatures,\n type ColumnDef as TanStackColumnDef,\n type Row,\n type Table,\n type TableOptions,\n} from '@tanstack/table-core';\nimport { storeReactivityBindings } from '@tanstack/table-core/store-reactivity-bindings';\nimport { moveColumn, normalizeOrder } from '../columns/column-order.js';\nimport { resolveColumns, type ResolvedColumn } from '../columns/resolve-columns.js';\nimport { distinctValues, rowPredicate } from '../filters/filter.js';\nimport { filteredRowModel, setRowPredicate } from './filtered-row-model.js';\nimport { sortedRowModel, valuesChanged } from './sorted-row-model.js';\nimport type {\n CellContext,\n ColumnAlign,\n ColumnDef,\n ColumnFilter,\n ColumnFilterState,\n ColumnOrderState,\n ColumnPin,\n ColumnPinningState,\n ColumnSizingState,\n ColumnVisibilityState,\n FilterKind,\n FilterValue,\n PinnedRows,\n RowPin,\n SortState,\n} from '../types.js';\n\n// The TanStack adapter. Everything TanStack stays in this module: callers only see\n// the view types below, so TanStack can be upgraded or replaced without touching\n// `argus-table`'s public API.\n\nconst features = tableFeatures({\n // Vanilla (framework-free) reactivity; required by `constructTable`.\n coreReactivityFeature: storeReactivityBindings(),\n // No pinning, ordering or visibility feature: the model groups, orders and hides\n // columns itself (see `buildViews`), so they cost no bundle size.\n columnSizingFeature,\n rowSortingFeature,\n // Our own filtering, without TanStack's filtering feature (see filtered-row-model.ts).\n // TanStack's types tie this slot to that feature; at runtime the core row models read it.\n ...({ filteredRowModel: filteredRowModel() } as object),\n // Our own: TanStack's is very slow in Firefox at scale (see sorted-row-model.ts).\n sortedRowModel: sortedRowModel(),\n // Registered by name so `sortFn: 'auto'` can pick one by value type.\n sortFns: {\n alphanumeric: sortFn_alphanumeric,\n basic: sortFn_basic,\n datetime: sortFn_datetime,\n text: sortFn_text,\n },\n});\ntype Features = typeof features;\ntype AnyRow = Record<string, unknown>;\n\n/** Sort direction of a column, or `false` when it isn't sorted. */\nexport type SortDirection = 'asc' | 'desc' | false;\n\n/**\n * Id of the selection column, the checkbox column the model adds first when\n * `selectionColumn` is set. Not a column of `columns`: it never appears in the\n * column order, sizing or events.\n */\nexport const SELECTION_COLUMN_ID = '--argus-selection';\n\n/** Width of the selection column in px. */\nexport const SELECTION_COLUMN_WIDTH = 40;\n\n/** A column as the renderer sees it, in visual order: start-pinned, scrolling, end-pinned. */\nexport interface ColumnView<TData, TContent> {\n id: string;\n /** `'data'` for a column of `columns`; `'selection'` for the checkbox column. */\n kind: 'data' | 'selection';\n /** 1-based position in visual order, for `aria-colindex`. `0` for a hidden column. */\n colIndex: number;\n /** The pin in effect: `columnPinning`'s, else the column's own. */\n pin: ColumnPin | undefined;\n /**\n * Sticky inset in px: from the start edge for `'start'` columns, from the end edge\n * for `'end'` columns. For scrolling columns, the start within the scrolling area.\n */\n offset: number;\n /** `true` on the pinned column next to the scrolling area (one per pinned side). */\n pinEdge: boolean;\n /**\n * `true` for a hidden column. Only `allColumns` lists hidden columns; `columns`\n * holds the ones the table shows.\n */\n hidden: boolean;\n /** Current width in px (a resized width wins over the column's own). */\n width: number;\n /** Share of free space, or `undefined` for a fixed width. A resized column stops flexing. */\n flex: number | undefined;\n /**\n * `true` for a `width: 'auto'` column that hasn't been resized: the table measures\n * its content and passes the width in as `autoWidths`.\n */\n auto: boolean;\n minWidth: number;\n maxWidth: number;\n sortable: boolean;\n resizable: boolean;\n reorderable: boolean;\n pinnable: boolean;\n hideable: boolean;\n /** The kind of filter users can set, or `undefined` when they can't filter the column. */\n filter: FilterKind | undefined;\n /** `true` when `columnFilters` has a filter for the column. */\n filtered: boolean;\n align: ColumnAlign;\n /** Whether the cell text wraps (`ColumnDef.wrap`). */\n wrap: boolean;\n sorted: SortDirection;\n header: ColumnDef<TData, TContent>['header'];\n cell: ColumnDef<TData, TContent>['cell'];\n hasAccessor: boolean;\n}\n\n/** A row of the current (filtered and sorted) row model. */\nexport interface RowView<TData> {\n id: string;\n /** Index in the current row model, 0-based. */\n index: number;\n original: TData;\n}\n\n/**\n * Rows that live outside the model, loaded page by page (`dataSource`). The\n * source sorts them, so the model reads them as they are. `PageCache` implements it.\n */\nexport interface RemoteRows<TData> {\n readonly rowCount: number;\n /** The loaded row at an index, with its id; `undefined` while it isn't loaded. */\n entryAt(index: number): { id: string; row: TData } | undefined;\n /** The index of a loaded row's id, or `undefined`. */\n indexOf(rowId: string): number | undefined;\n /** The ids of every loaded row, in row order. */\n loadedIds(): string[];\n}\n\nexport interface TableModelOptions<TData, TContent> {\n columns: readonly ColumnDef<TData, TContent>[];\n data: readonly TData[];\n /**\n * Remote rows. When set, rows come from here instead of `data`, and the model\n * doesn't sort them (the source does).\n */\n remote?: RemoteRows<TData> | undefined;\n /** Row id function. Default: the row's index in `data`, as a string. */\n getRowId: ((row: TData, index: number) => string) | undefined;\n /** Current sort state; its owner is the caller (see `controllable`). */\n sorting: SortState;\n /** Current resized widths; its owner is the caller. */\n columnSizing: ColumnSizingState;\n /**\n * Current column order; its owner is the caller. Each pin group follows it; an\n * empty array (the default) keeps the order of `columns`.\n */\n columnOrder?: ColumnOrderState | undefined;\n /** Pins set at runtime, over the columns' own `pin`; its owner is the caller. */\n columnPinning?: ColumnPinningState | undefined;\n /** Visibility set at runtime, over the columns' own `hidden`; its owner is the caller. */\n columnVisibility?: ColumnVisibilityState | undefined;\n /**\n * Column filters; its owner is the caller. Rows that fail one leave the row model.\n * Remote rows aren't filtered: the source does it.\n */\n columnFilters?: ColumnFilterState | undefined;\n /**\n * Words to find in the shown columns' values as text, ignoring case: a row stays\n * when each word is in one of its values. Remote rows aren't filtered.\n */\n quickFilter?: string | undefined;\n /**\n * Measured widths of `width: 'auto'` columns, in px by id. Clamped to the column's\n * bounds; a resized width wins. Ids of other columns are ignored.\n */\n autoWidths?: ColumnSizingState | undefined;\n /** Rows fixed above or below the body. They stay out of the row model: never sorted, not counted. */\n pinnedRows?: PinnedRows<TData> | undefined;\n /**\n * Adds the selection (checkbox) column first among the start-pinned columns. It\n * has the id `SELECTION_COLUMN_ID`, a fixed width, and no part in sorting,\n * sizing or the column order.\n */\n selectionColumn?: boolean | undefined;\n}\n\nexport interface TableModel<TData, TContent> {\n /** Updates any subset of the options. Unchanged references are ignored. */\n update(options: Partial<TableModelOptions<TData, TContent>>): void;\n /** The columns the table shows, in visual order. */\n readonly columns: readonly ColumnView<TData, TContent>[];\n /**\n * Every column of `columns`, hidden ones included (with `hidden: true` and\n * `colIndex: 0`), in the order of `orderOf()`. Not the selection column.\n */\n readonly allColumns: readonly ColumnView<TData, TContent>[];\n /** Number of rows in the current row model. */\n readonly rowCount: number;\n /**\n * Changes identity whenever the row at an index may have changed: new data, a\n * sort, a filter, a new remote source. Compare it by identity only.\n */\n readonly rowOrder: object;\n /** Sum of the shown columns' widths in px (flex columns count their minimum). */\n readonly totalWidth: number;\n /** The row at an index of the current row model; `undefined` for a remote row not loaded yet. */\n rowAt(index: number): RowView<TData> | undefined;\n /** The index of a row id in the current row model (after filtering and sorting), or `undefined`. */\n indexOf(rowId: string): number | undefined;\n /**\n * The ids of the rows that can be selected, in row order: every row of the row\n * model, or only the loaded ones for remote rows.\n */\n selectableIds(): string[];\n /** The value a column reads from the row at `index`. */\n valueAt(index: number, columnId: string): unknown;\n /** What a column's `cell` function receives for the row at `index`. */\n cellContext(index: number, columnId: string): CellContext<TData> | undefined;\n /**\n * The sort state that clicking this column's header would produce:\n * asc → desc → unsorted, one column at a time. `undefined` if it can't sort.\n */\n nextSorting(columnId: string): SortState | undefined;\n /**\n * The sizing state after setting a column to `width` px, clamped to its bounds.\n * `undefined` if the column can't be resized.\n */\n nextSizing(columnId: string, width: number): ColumnSizingState | undefined;\n /**\n * The full column order as the table shows it: start-pinned, scrolling and\n * end-pinned ids. `base` defaults to the current `columnOrder`.\n */\n orderOf(base?: readonly string[]): ColumnOrderState;\n /**\n * The order after moving a column to position `to` (0-based among the shown data\n * columns, in visual order, counted after the move; hidden columns keep their place),\n * starting from `base` (default: the current order). `undefined` if the column can't\n * move or is hidden, `to` is outside its pin group, or nothing changes.\n */\n nextOrder(columnId: string, to: number, base?: readonly string[]): ColumnOrderState | undefined;\n /**\n * The pinning state after pinning a column to a side, or unpinning it with `false`,\n * starting from `base` (default: the current `columnPinning`). `undefined` for an\n * unknown column, one with `pinnable: false`, or no change.\n */\n nextPinning(\n columnId: string,\n pin: ColumnPin | false,\n base?: ColumnPinningState,\n ): ColumnPinningState | undefined;\n /**\n * The visibility state after hiding or showing a column, starting from `base`\n * (default: the current `columnVisibility`). `undefined` for an unknown column,\n * hiding one with `hideable: false` or the last one shown, or no change.\n */\n nextVisibility(\n columnId: string,\n hidden: boolean,\n base?: ColumnVisibilityState,\n ): ColumnVisibilityState | undefined;\n /**\n * The filter state after setting a column's filter, or clearing it with `undefined`,\n * starting from `base` (default: the current `columnFilters`). `undefined` for an\n * unknown column, setting a filter on a column without `filter`, or no change.\n */\n nextFilters(\n columnId: string,\n filter: ColumnFilter | undefined,\n base?: ColumnFilterState,\n ): ColumnFilterState | undefined;\n /**\n * The values a `'set'` filter on the column offers: its `filterOptions`, else (not for\n * remote rows) the distinct values of the rows the other filters keep, sorted, at most\n * `limit` of them (`truncated` when there are more). `undefined` for an unknown column,\n * or remote rows without `filterOptions`.\n */\n filterValues(\n columnId: string,\n limit?: number,\n ): { values: FilterValue[]; truncated: boolean } | undefined;\n /** Number of rows pinned to a side. */\n pinnedCount(side: RowPin): number;\n /**\n * A pinned row, `index` counted within its side. Its id comes from `getRowId`,\n * else it is `'top-{index}'` or `'bottom-{index}'`, apart from the data rows' index ids.\n */\n pinnedRowAt(side: RowPin, index: number): RowView<TData> | undefined;\n /** The value a column reads from a pinned row. */\n pinnedValueAt(side: RowPin, index: number, columnId: string): unknown;\n /** What a column's `cell` function receives for a pinned row (with `pinned` set). */\n pinnedCellContext(side: RowPin, index: number, columnId: string): CellContext<TData> | undefined;\n}\n\nconst defaultRowId = (_row: unknown, index: number) => String(index);\n\n/**\n * Ids of the columns kept from `before` whose accessor changed: a new function,\n * or a different path. A new column has nothing cached and isn't listed.\n */\nfunction changedAccessors<TData, TContent>(\n before: readonly ColumnDef<TData, TContent>[],\n after: readonly ColumnDef<TData, TContent>[],\n): string[] {\n const old = new Map(before.map((c) => [c.id, c.accessor]));\n return after.filter((c) => old.has(c.id) && old.get(c.id) !== c.accessor).map((c) => c.id);\n}\n\n/** The selection column's view: first, pinned to the start, fixed, and inert to sorting, sizing and moves. */\nfunction selectionView<TData, TContent>(pinEdge: boolean): ColumnView<TData, TContent> {\n return {\n id: SELECTION_COLUMN_ID,\n kind: 'selection',\n colIndex: 1,\n pin: 'start',\n offset: 0,\n pinEdge,\n hidden: false,\n width: SELECTION_COLUMN_WIDTH,\n flex: undefined,\n auto: false,\n minWidth: SELECTION_COLUMN_WIDTH,\n maxWidth: SELECTION_COLUMN_WIDTH,\n sortable: false,\n resizable: false,\n reorderable: false,\n pinnable: false,\n hideable: false,\n filter: undefined,\n filtered: false,\n align: 'center',\n wrap: false,\n sorted: false,\n header: undefined,\n cell: undefined,\n hasAccessor: false,\n };\n}\n\nfunction toTanStack<TData, TContent>(\n column: ResolvedColumn<TData, TContent>,\n): TanStackColumnDef<Features, AnyRow> {\n return {\n id: column.id,\n accessorFn: column.getValue as (row: AnyRow, index: number) => unknown,\n size: column.width,\n minSize: column.minWidth,\n maxSize: column.maxWidth,\n enableSorting: column.sortable,\n sortUndefined: 'last',\n };\n}\n\n/**\n * Creates the table model over TanStack Table. It owns no state: sorting, sizing, order,\n * pinning and visibility come in through `update()`, and the `next*()` methods only propose\n * changes, so the caller decides (controlled or uncontrolled) whether to apply them.\n *\n * Hidden columns stay in TanStack, so their values still sort and read; only the\n * views leave them out. Pin groups, sticky offsets and the order are the model's own.\n */\nexport function createTableModel<TData, TContent>(\n initial: TableModelOptions<TData, TContent>,\n): TableModel<TData, TContent> {\n let options = initial;\n let resolved = resolveColumns(options.columns);\n let byId = new Map(resolved.map((c) => [c.id, c]));\n // TanStack column defs by id, kept between updates that don't change `columns`.\n let tanStackById = new Map(resolved.map((c) => [c.id, toTanStack(c)]));\n let views: ColumnView<TData, TContent>[] | undefined;\n // The pin and visibility in effect: the state's, else the column's own.\n const pinOf = (\n column: ResolvedColumn<TData, TContent>,\n pinning = options.columnPinning,\n ): ColumnPin | undefined => {\n const state = pinning?.[column.id];\n if (state === 'start' || state === 'end') return state;\n return state === false ? undefined : column.pin;\n };\n const hiddenOf = (\n column: ResolvedColumn<TData, TContent>,\n visibility = options.columnVisibility,\n ): boolean => {\n const state = visibility?.[column.id];\n return typeof state === 'boolean' ? !state : column.hidden;\n };\n const shown = (id: string) => {\n const column = byId.get(id);\n return column !== undefined && !hiddenOf(column);\n };\n // TanStack's sizing state: measured auto widths and the widths of pinned flex columns\n // under the resized ones. Kept stable between updates that don't touch them.\n let sizing: ColumnSizingState | undefined;\n const sizingState = (): ColumnSizingState => {\n if (sizing) return sizing;\n const auto = options.autoWidths;\n const merged: ColumnSizingState = {};\n let any = false;\n for (const column of resolved) {\n // A pinned column can't flex: it takes a fixed width for its sticky offsets.\n if (column.flex !== undefined && pinOf(column) !== undefined) {\n merged[column.id] = column.pinnedWidth;\n any = true;\n }\n const px = auto?.[column.id];\n if (!column.auto || px === undefined || !Number.isFinite(px)) continue;\n merged[column.id] = Math.min(column.maxWidth, Math.max(column.minWidth, px));\n any = true;\n }\n return (sizing = any ? { ...merged, ...options.columnSizing } : options.columnSizing);\n };\n // What ordering needs, with the pin in effect.\n const orderable = () =>\n resolved.map((c) => ({ id: c.id, pin: pinOf(c), reorderable: c.reorderable }));\n // The normalized order, kept stable between updates that touch neither columns,\n // order nor pinning.\n let order: ColumnOrderState | undefined;\n const orderState = (): ColumnOrderState =>\n (order ??= normalizeOrder(options.columnOrder ?? [], orderable()));\n const rowViews = new WeakMap<Row<Features, AnyRow>, RowView<TData>>();\n // Built lazily per row model (sorting or new data gives a new array).\n let indexById: { rows: readonly Row<Features, AnyRow>[]; map: Map<string, number> } | undefined;\n\n // TanStack gets its column defs in the order, hidden ones included. Rebuilt only when\n // the order changes: a new columns array makes TanStack rebuild its columns, though\n // not its row models, which depend on data and sorting alone.\n let ordered:\n { order: ColumnOrderState; columns: TanStackColumnDef<Features, AnyRow>[] } | undefined;\n const orderedColumns = () => {\n const current = orderState();\n if (ordered?.order !== current) {\n ordered = { order: current, columns: current.flatMap((id) => tanStackById.get(id) ?? []) };\n }\n return ordered;\n };\n\n const tableOptions = (): TableOptions<Features, AnyRow> => ({\n features,\n columns: orderedColumns().columns,\n // Remote rows bypass TanStack's row models; it still handles columns and state.\n data: (options.remote ? [] : options.data) as AnyRow[],\n getRowId: (options.getRowId ?? defaultRowId) as (row: AnyRow, index: number) => string,\n state: {\n sorting: options.sorting,\n columnSizing: sizingState(),\n },\n // State is owned by the caller; TanStack's own setters must not change it.\n onSortingChange: () => undefined,\n onColumnSizingChange: () => undefined,\n });\n\n const table: Table<Features, AnyRow> = constructTable(tableOptions());\n\n // The row test of the filters, the quick filter and the shown columns (which the quick\n // filter reads). Remote rows are filtered by their source.\n const predicateFor = (except?: string) =>\n options.remote\n ? undefined\n : rowPredicate(\n byId,\n options.columnFilters,\n options.quickFilter,\n resolved.filter((c) => c.hasAccessor && !hiddenOf(c)),\n except,\n );\n setRowPredicate(table, predicateFor());\n\n const rows = () => table.getRowModel().rows;\n const pinned = (side: RowPin): readonly TData[] => options.pinnedRows?.[side] ?? [];\n\n const widthOf = (id: string) => table.getColumn(id)?.getSize() ?? 0;\n const view = (\n def: ResolvedColumn<TData, TContent>,\n colIndex: number,\n offset: number,\n pinEdge: boolean,\n width: number,\n ): ColumnView<TData, TContent> => {\n const sort = options.sorting.find((s) => s.id === def.id);\n const pin = pinOf(def);\n const resized = options.columnSizing[def.id] !== undefined;\n return {\n id: def.id,\n kind: 'data',\n colIndex,\n pin,\n offset,\n pinEdge,\n hidden: colIndex === 0,\n width,\n flex: pin === undefined && !resized ? def.flex : undefined,\n auto: def.auto && !resized,\n minWidth: def.minWidth,\n maxWidth: def.maxWidth,\n sortable: def.sortable,\n resizable: def.resizable,\n reorderable: def.reorderable,\n pinnable: def.pinnable,\n hideable: def.hideable,\n filter: def.filter,\n filtered: options.columnFilters?.[def.id] !== undefined,\n align: def.align,\n wrap: def.wrap,\n sorted: sort ? (sort.desc ? 'desc' : 'asc') : false,\n header: def.header,\n cell: def.cell,\n hasAccessor: def.hasAccessor,\n };\n };\n\n const buildViews = (): ColumnView<TData, TContent>[] => {\n const groups: Record<ColumnPin | 'center', ResolvedColumn<TData, TContent>[]> = {\n start: [],\n center: [],\n end: [],\n };\n for (const id of orderState()) {\n const def = byId.get(id);\n if (def && !hiddenOf(def)) groups[pinOf(def) ?? 'center'].push(def);\n }\n const { start, center, end } = groups;\n // The selection column comes first: it shifts every column one place on, and\n // the other start-pinned columns its width further from the start edge.\n const lead = options.selectionColumn ? 1 : 0;\n if (lead && byId.has(SELECTION_COLUMN_ID)) {\n throw new Error(`argus-table: the column id '${SELECTION_COLUMN_ID}' is reserved.`);\n }\n // Offsets: start columns from the start edge (after the selection column), the\n // scrolling ones within the scrolling area, end columns from the end edge.\n let x = lead * SELECTION_COLUMN_WIDTH;\n const list = start.map((def, i) => {\n const width = widthOf(def.id);\n const v = view(def, lead + i + 1, x, i === start.length - 1, width);\n x += width;\n return v;\n });\n x = 0;\n for (const [i, def] of center.entries()) {\n const width = widthOf(def.id);\n list.push(view(def, lead + start.length + i + 1, x, false, width));\n x += width;\n }\n const ends: ColumnView<TData, TContent>[] = [];\n x = 0;\n for (const [i, def] of [...end.entries()].reverse()) {\n const width = widthOf(def.id);\n ends.unshift(view(def, lead + start.length + center.length + i + 1, x, i === 0, width));\n x += width;\n }\n list.push(...ends);\n if (lead) list.unshift(selectionView(start.length === 0));\n return list;\n };\n\n let allViews: ColumnView<TData, TContent>[] | undefined;\n const buildAllViews = (shownViews: readonly ColumnView<TData, TContent>[]) => {\n const byShownId = new Map(shownViews.map((v) => [v.id, v]));\n return orderState().flatMap((id) => {\n const shownView = byShownId.get(id);\n if (shownView) return [shownView];\n const def = byId.get(id);\n return def ? [view(def, 0, 0, false, widthOf(id))] : [];\n });\n };\n\n return {\n update(next) {\n const merged = { ...options, ...next };\n const changed = (Object.keys(next) as (keyof typeof next)[]).some(\n (key) => next[key] !== options[key],\n );\n if (!changed) return;\n let reread: string[] = [];\n if (next.columns && next.columns !== options.columns) {\n reread = changedAccessors(options.columns, next.columns);\n resolved = resolveColumns(next.columns);\n byId = new Map(resolved.map((c) => [c.id, c]));\n tanStackById = new Map(resolved.map((c) => [c.id, toTanStack(c)]));\n }\n const pinningChanged = merged.columnPinning !== options.columnPinning;\n if (\n merged.columns !== options.columns ||\n merged.columnSizing !== options.columnSizing ||\n merged.autoWidths !== options.autoWidths ||\n pinningChanged\n ) {\n sizing = undefined;\n }\n if (\n merged.columns !== options.columns ||\n merged.columnOrder !== options.columnOrder ||\n pinningChanged\n ) {\n order = undefined;\n }\n const refilter =\n merged.columns !== options.columns ||\n merged.columnFilters !== options.columnFilters ||\n merged.quickFilter !== options.quickFilter ||\n merged.columnVisibility !== options.columnVisibility ||\n merged.remote !== options.remote;\n options = merged;\n views = undefined;\n allViews = undefined;\n if (refilter) setRowPredicate(table, predicateFor());\n table.setOptions((prev) => ({ ...prev, ...tableOptions() }));\n if (reread.length && !options.remote) {\n // TanStack caches each value on its row by column id, and keeps rows\n // while the data is the same: drop the values of the columns that now\n // read differently, and sort again.\n for (const row of table.getCoreRowModel().rows) {\n for (const id of reread) Reflect.deleteProperty(row._valuesCache, id);\n }\n valuesChanged(table);\n }\n },\n\n get columns() {\n return (views ??= buildViews());\n },\n\n get allColumns() {\n return (allViews ??= buildAllViews(this.columns));\n },\n\n get rowCount() {\n return options.remote?.rowCount ?? rows().length;\n },\n get rowOrder() {\n return options.remote ?? rows();\n },\n\n get totalWidth() {\n return this.columns.reduce((sum, column) => sum + column.width, 0);\n },\n\n rowAt(index) {\n if (options.remote) {\n const entry = options.remote.entryAt(index);\n return entry && { id: entry.id, index, original: entry.row };\n }\n const row = rows()[index];\n if (!row) return undefined;\n let view = rowViews.get(row);\n if (view?.index !== index) {\n view = { id: row.id, index, original: row.original as TData };\n rowViews.set(row, view);\n }\n return view;\n },\n\n indexOf(rowId) {\n if (options.remote) return options.remote.indexOf(rowId);\n const current = rows();\n if (indexById?.rows !== current) {\n indexById = { rows: current, map: new Map(current.map((r, i) => [r.id, i])) };\n }\n return indexById.map.get(rowId);\n },\n\n selectableIds() {\n if (options.remote) return options.remote.loadedIds();\n return rows().map((r) => r.id);\n },\n\n valueAt(index, columnId) {\n if (options.remote) {\n const entry = options.remote.entryAt(index);\n return entry && byId.get(columnId)?.getValue(entry.row, index);\n }\n return rows()[index]?.getValue(columnId);\n },\n\n cellContext(index, columnId) {\n if (options.remote) {\n const entry = options.remote.entryAt(index);\n const column = byId.get(columnId);\n if (!entry || !column) return undefined;\n return {\n row: entry.row,\n rowId: entry.id,\n index,\n columnId,\n value: column.getValue(entry.row, index),\n };\n }\n const row = rows()[index];\n if (!row || !byId.has(columnId)) return undefined;\n return {\n row: row.original as TData,\n rowId: row.id,\n index,\n columnId,\n value: row.getValue(columnId),\n };\n },\n\n nextSorting(columnId) {\n if (byId.get(columnId)?.sortable !== true) return undefined;\n const current = options.sorting.find((s) => s.id === columnId);\n if (!current) return [{ id: columnId, desc: false }];\n return current.desc ? [] : [{ id: columnId, desc: true }];\n },\n\n nextSizing(columnId, width) {\n const column = byId.get(columnId);\n if (!column?.resizable || !Number.isFinite(width)) return undefined;\n const clamped = Math.round(Math.min(column.maxWidth, Math.max(column.minWidth, width)));\n return { ...options.columnSizing, [columnId]: clamped };\n },\n\n orderOf(base) {\n return base === undefined ? orderState() : normalizeOrder(base, orderable());\n },\n\n nextOrder(columnId, to, base) {\n return moveColumn(base ?? orderState(), orderable(), columnId, to, shown);\n },\n\n nextPinning(columnId, pin, base = options.columnPinning) {\n const column = byId.get(columnId);\n if (!column?.pinnable || (pinOf(column, base) ?? false) === pin) return undefined;\n return { ...base, [columnId]: pin };\n },\n\n nextVisibility(columnId, hidden, base = options.columnVisibility) {\n const column = byId.get(columnId);\n if (!column || hiddenOf(column, base) === hidden) return undefined;\n const othersShown = resolved.some((c) => c !== column && !hiddenOf(c, base));\n if (hidden && (!column.hideable || !othersShown)) return undefined;\n return { ...base, [columnId]: !hidden };\n },\n\n nextFilters(columnId, filter, base = options.columnFilters ?? {}) {\n const column = byId.get(columnId);\n if (!column) return undefined;\n const current = base[columnId];\n if (filter === undefined) {\n if (current === undefined) return undefined;\n const next = { ...base };\n Reflect.deleteProperty(next, columnId);\n return next;\n }\n if (column.filter === undefined) return undefined;\n if (current && JSON.stringify(current) === JSON.stringify(filter)) return undefined;\n return { ...base, [columnId]: filter };\n },\n\n filterValues(columnId, limit = 1000) {\n const column = byId.get(columnId);\n if (!column) return undefined;\n if (column.filterOptions) return { values: [...column.filterOptions], truncated: false };\n if (options.remote) return undefined;\n const rows = table.getCoreRowModel().rows as unknown as Iterable<{\n original: TData;\n index: number;\n }>;\n return distinctValues(rows, column, predicateFor(columnId), limit);\n },\n\n pinnedCount(side) {\n return pinned(side).length;\n },\n\n pinnedRowAt(side, index) {\n if (index < 0 || index >= pinned(side).length) return undefined;\n const row = pinned(side)[index] as TData;\n const id = options.getRowId ? options.getRowId(row, index) : `${side}-${String(index)}`;\n return { id, index, original: row };\n },\n\n pinnedValueAt(side, index, columnId) {\n if (index < 0 || index >= pinned(side).length) return undefined;\n return byId.get(columnId)?.getValue(pinned(side)[index] as TData, index);\n },\n\n pinnedCellContext(side, index, columnId) {\n const row = this.pinnedRowAt(side, index);\n const column = byId.get(columnId);\n if (!row || !column) return undefined;\n return {\n row: row.original,\n rowId: row.id,\n index,\n columnId,\n value: column.getValue(row.original, index),\n pinned: side,\n };\n },\n };\n}\n"],"mappings":"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"}
|