@svgrid/grid 3.0.8 → 3.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/GridMenus.svelte +3 -2
  2. package/dist/SvGrid.controller.svelte.d.ts +60 -8
  3. package/dist/SvGrid.controller.svelte.js +475 -110
  4. package/dist/SvGrid.css +186 -3
  5. package/dist/SvGrid.svelte +281 -163
  6. package/dist/SvGrid.types.d.ts +24 -7
  7. package/dist/cdn/{GridMenus-D15bhpX5.js → GridMenus-B1sipj6y.js} +165 -165
  8. package/dist/cdn/{GridMenus-B8-Gbfq2.js → GridMenus-DlAzfHLk.js} +201 -201
  9. package/dist/cdn/server-block-cache-Dj-KPqEQ.js +1289 -0
  10. package/dist/cdn/{src-Dz625Fhx.js → src-BYsa66I0.js} +9738 -10174
  11. package/dist/cdn/{src-CleI0g9l.js → src-pA4RroLV.js} +10702 -11138
  12. package/dist/cdn/svgrid.js +27 -27
  13. package/dist/cdn/svgrid.svelte-external.js +27 -27
  14. package/dist/cdn/{validate-GEs4ZPSW.js → validate-XuMe4_KR.js} +2 -2
  15. package/dist/cell-render.js +25 -3
  16. package/dist/columns.js +16 -1
  17. package/dist/conditional-formatting.js +9 -2
  18. package/dist/core.d.ts +93 -0
  19. package/dist/core.js +313 -52
  20. package/dist/filtering/excel-filters.js +41 -6
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.js +1 -0
  23. package/dist/selection.d.ts +2 -2
  24. package/dist/selection.js +32 -8
  25. package/dist/server-block-cache.d.ts +7 -32
  26. package/dist/server-block-cache.js +21 -12
  27. package/dist/server-data-source.js +3 -1
  28. package/dist/server.d.ts +1 -0
  29. package/dist/server.js +1 -0
  30. package/dist/spreadsheet.js +7 -0
  31. package/dist/validate.js +3 -11
  32. package/dist/virtualization/column-virtualizer.d.ts +4 -0
  33. package/dist/virtualization/column-virtualizer.js +2 -0
  34. package/dist/virtualization/types.d.ts +20 -0
  35. package/dist/virtualization/virtualizer.js +90 -24
  36. package/dist/windowed-brand.d.ts +22 -0
  37. package/dist/windowed-brand.js +60 -0
  38. package/dist/windowed-data.d.ts +6 -0
  39. package/dist/windowed-data.js +34 -0
  40. package/dist/windowed-row-model.d.ts +1 -0
  41. package/dist/windowed-row-model.js +97 -0
  42. package/package.json +1 -1
  43. package/src/GridMenus.svelte +3 -2
  44. package/src/SvGrid.controller.svelte.ts +469 -114
  45. package/src/SvGrid.css +186 -3
  46. package/src/SvGrid.svelte +281 -163
  47. package/src/SvGrid.types.ts +24 -7
  48. package/src/cell-render.ts +24 -2
  49. package/src/columns.ts +16 -1
  50. package/src/conditional-formatting.ts +6 -4
  51. package/src/core.sort.test.ts +61 -0
  52. package/src/core.ts +309 -52
  53. package/src/counting-cell.test.svelte +11 -0
  54. package/src/filtering/excel-filters.ts +39 -6
  55. package/src/headless.reactivity.svelte.test.ts +1 -1
  56. package/src/index.ts +6 -0
  57. package/src/new-features.test.ts +24 -0
  58. package/src/selection.test.ts +14 -0
  59. package/src/selection.ts +31 -8
  60. package/src/server-block-cache.ts +27 -10
  61. package/src/server-data-source.ts +3 -1
  62. package/src/server.ts +6 -0
  63. package/src/spreadsheet.ts +6 -0
  64. package/src/svgrid.behavior.test.ts +29 -0
  65. package/src/svgrid.column-cell-recycling.test.ts +120 -0
  66. package/src/svgrid.interaction.test.ts +4 -1
  67. package/src/svgrid.new-features.wrapper.test.ts +5 -4
  68. package/src/svgrid.pinned-column-virtualization.test.ts +162 -0
  69. package/src/svgrid.row-model-prop.svelte.test.ts +15 -3
  70. package/src/validate.test.ts +4 -4
  71. package/src/validate.ts +3 -14
  72. package/src/virtualization/column-virtualizer.ts +6 -0
  73. package/src/virtualization/types.ts +20 -0
  74. package/src/virtualization/virtualizer.test.ts +152 -0
  75. package/src/virtualization/virtualizer.ts +93 -27
  76. package/src/windowed-brand.ts +67 -0
  77. package/src/windowed-data.test.ts +105 -0
  78. package/src/windowed-data.ts +36 -0
  79. package/src/windowed-row-model.ts +113 -0
  80. package/dist/cdn/server-block-cache-DIqb3VZn.js +0 -241
@@ -0,0 +1,113 @@
1
+ /**
2
+ * The row model for windowed data (see windowed-data.ts).
3
+ *
4
+ * No build loop and no pipeline stages: `rows` is itself windowed. A row
5
+ * object is made the first time an index is read and kept (up to
6
+ * WINDOWED_ROW_CAP) while its data object is the same one, so scrolling back
7
+ * does not rebuild what is still loaded, and scrolling a 100M-row source end
8
+ * to end keeps a few thousand rows, not 100M.
9
+ *
10
+ * Installed into the core by the first createWindowedData() call rather than
11
+ * imported by core.ts, so a grid that is never handed windowed data does not
12
+ * bundle any of this.
13
+ */
14
+ import {
15
+ BASE_ROW_METHODS,
16
+ ROW_CELLS,
17
+ ROW_CTX,
18
+ ROW_FILTER_GEN,
19
+ ROW_FILTER_POS,
20
+ ROW_SORT_DROPPED,
21
+ ROW_SORT_KEY,
22
+ ROW_VALUES,
23
+ registerWindowedRowModel,
24
+ type BaseRowCtx,
25
+ type BaseRowState,
26
+ type Column,
27
+ type Row,
28
+ type RowData,
29
+ type RowModel,
30
+ } from './core'
31
+ import { makeWindowedArray, windowedSourceOf } from './windowed-brand'
32
+
33
+ /** The windowed-data version a row's memoised values belong to. */
34
+ const ROW_WINDOW_GEN = Symbol('svgrid.row.windowGen')
35
+ const WINDOWED_ROW_CAP = 20_000
36
+
37
+ let installed = false
38
+
39
+ export function enableWindowedRowModel(): void {
40
+ if (installed) return
41
+ installed = true
42
+ registerWindowedRowModel(<TData extends RowData>(ctx: {
43
+ rowCtxFor: (columns: Array<Column<TData>>) => BaseRowCtx<TData>
44
+ getRowId: () => ((row: TData, index: number) => string) | undefined
45
+ }) => {
46
+ // Per grid: the model for the current input, and the row objects built
47
+ // so far, by index.
48
+ let current: { input: unknown; columns: Array<Column<TData>>; model: RowModel<TData> } | null = null
49
+ const rows = new Map<number, BaseRowState<TData>>()
50
+ let generation = 0
51
+
52
+ return (data: unknown, columns: Array<Column<TData>>): RowModel<TData> | null => {
53
+ const source = windowedSourceOf<TData>(data)
54
+ if (!source) return null
55
+ if (current && current.input === data && current.columns === columns) return current.model
56
+ if (!current || current.columns !== columns) rows.clear()
57
+ const rowCtx = ctx.rowCtxFor(columns)
58
+ const getRowId = ctx.getRowId()
59
+ const gen = ++generation
60
+ const m = BASE_ROW_METHODS as unknown as BaseRowState<TData>
61
+ const rowAt = (index: number): Row<TData> | undefined => {
62
+ if (index < 0 || index >= source.length) return undefined
63
+ const original = source.at(index)
64
+ if (original === undefined) return undefined
65
+ const kept = rows.get(index) as (BaseRowState<TData> & { [ROW_WINDOW_GEN]?: number }) | undefined
66
+ if (kept && kept.original === original) {
67
+ // A new data version may follow an in-place edit of the object, as
68
+ // in the dense path: drop the memoised values once per version.
69
+ if (kept[ROW_WINDOW_GEN] !== gen) {
70
+ kept[ROW_VALUES] = null
71
+ kept[ROW_CELLS] = null
72
+ kept[ROW_WINDOW_GEN] = gen
73
+ }
74
+ return kept
75
+ }
76
+ const row = {
77
+ id: getRowId ? getRowId(original, index) : String(index),
78
+ index,
79
+ original,
80
+ depth: 0,
81
+ [ROW_CTX]: rowCtx,
82
+ [ROW_VALUES]: null,
83
+ [ROW_CELLS]: null,
84
+ [ROW_FILTER_GEN]: 0,
85
+ [ROW_FILTER_POS]: -1,
86
+ [ROW_SORT_DROPPED]: 0,
87
+ [ROW_SORT_KEY]: undefined,
88
+ [ROW_WINDOW_GEN]: gen,
89
+ getCanExpand: m.getCanExpand,
90
+ getIsExpanded: m.getIsExpanded,
91
+ toggleExpanded: m.toggleExpanded,
92
+ getIsSelected: m.getIsSelected,
93
+ toggleSelected: m.toggleSelected,
94
+ getAllCells: m.getAllCells,
95
+ getCellValueByColumnId: m.getCellValueByColumnId,
96
+ } as unknown as BaseRowState<TData>
97
+ rows.set(index, row)
98
+ if (rows.size > WINDOWED_ROW_CAP) {
99
+ // Oldest first (Map keeps insertion order); a quarter at a time.
100
+ let drop = WINDOWED_ROW_CAP / 4
101
+ for (const key of rows.keys()) {
102
+ if (drop-- <= 0) break
103
+ rows.delete(key)
104
+ }
105
+ }
106
+ return row
107
+ }
108
+ const model: RowModel<TData> = { rows: makeWindowedArray(source.length, rowAt) as Array<Row<TData>> }
109
+ current = { input: data, columns, model }
110
+ return model
111
+ }
112
+ })
113
+ }
@@ -1,241 +0,0 @@
1
- //#region src/server-block-cache.ts
2
- var e = Symbol.for("svgrid.rowPlaceholder"), t = Object.freeze({ [e]: "loading" }), n = Object.freeze({ [e]: "failed" });
3
- function r(t) {
4
- if (typeof t != "object" || !t) return null;
5
- let n = t[e];
6
- return n === "loading" || n === "failed" ? n : null;
7
- }
8
- function i(t, n) {
9
- return Object.freeze({
10
- ...n,
11
- [e]: t
12
- });
13
- }
14
- var a = (e) => {
15
- Promise.resolve().then(e);
16
- };
17
- function o(e) {
18
- let r = Math.max(1, e.blockSize ?? 100), i = e.maxBlocksInCache ?? Infinity, o = Math.max(1, e.maxConcurrentRequests ?? 2), s = Math.max(0, e.blockLoadDebounceMs ?? 0), c = Math.max(0, e.initialRowCount ?? 1), l = Math.max(0, e.overflowRows ?? 1), u = e.schedule ?? a, d = /* @__PURE__ */ new Map(), f = [], p = 0, m = 0, h = null, g = !1, _ = !1, v = 0, y = 0, b = null, x = !1, S = null, C = (e) => Math.floor(e / r), w = (e) => e * r;
19
- function T() {
20
- if (g && h != null) return h;
21
- let e = 0, t = !1;
22
- for (let e of d.values()) e.status !== "loading" && (t = !0);
23
- for (let [n, i] of d) {
24
- let a = i.status === "loaded" ? w(n) + i.rows.length : i.status === "failed" ? n === 0 ? 0 : w(n) + r : t ? w(n) + r : 0;
25
- a > e && (e = a);
26
- }
27
- return t ? Math.max(c, e + l) : c;
28
- }
29
- function E() {
30
- let e = [];
31
- for (let [t, n] of d) n.status === "failed" && e.push(t);
32
- return {
33
- rowCount: g ? h : null,
34
- lastRowKnown: g,
35
- loading: p > 0,
36
- failedBlocks: e.sort((e, t) => e - t)
37
- };
38
- }
39
- function D() {
40
- S = null, !(_ || x) && (x = !0, u(() => {
41
- x = !1, !_ && e.onChange(E());
42
- }));
43
- }
44
- function O(e) {
45
- _ || d.get(e) || f.includes(e) || (f.push(e), k());
46
- }
47
- function k() {
48
- for (; !_ && p < o && f.length > 0;) {
49
- let e = f.shift();
50
- d.has(e) || A(e);
51
- }
52
- }
53
- async function A(t) {
54
- let n = new AbortController(), i = {
55
- status: "loading",
56
- rows: [],
57
- lastTouched: m += 1,
58
- controller: n
59
- };
60
- d.set(t, i), p += 1, D();
61
- let a = w(t), o = a + r;
62
- try {
63
- let r = await e.fetch(a, o, n.signal);
64
- if (_ || n.signal.aborted || d.get(t) !== i) return;
65
- i.rows = [...r.rows], i.status = "loaded", i.controller = null, j(t, i.rows.length, r.rowCount), M();
66
- } catch {
67
- if (_ || n.signal.aborted || d.get(t) !== i) return;
68
- i.status = "failed", i.rows = [], i.controller = null;
69
- } finally {
70
- !_ && !n.signal.aborted && (--p, D(), k());
71
- }
72
- }
73
- function j(e, t, n) {
74
- if (typeof n == "number" && n >= 0) {
75
- h = n, g = !0;
76
- return;
77
- }
78
- t < r && (h = w(e) + t, g = !0);
79
- }
80
- function M() {
81
- if (!Number.isFinite(i)) return;
82
- let e = C(v), t = C(Math.max(v, y)), n = [...d.entries()].filter(([n, r]) => r.status === "loaded" && (n < e || n > t)).sort((e, t) => e[1].lastTouched - t[1].lastTouched), r = 0;
83
- for (let e of d.values()) e.status === "loaded" && (r += 1);
84
- for (let [e] of n) {
85
- if (r <= i) break;
86
- d.delete(e), --r;
87
- }
88
- }
89
- function N() {
90
- if (_) return;
91
- let e = C(v), t = C(Math.max(v, y));
92
- for (let n = e; n <= t; n += 1) {
93
- let e = d.get(n);
94
- e ? e.lastTouched = m += 1 : O(n);
95
- }
96
- }
97
- function P() {
98
- for (let e of d.values()) e.controller?.abort();
99
- p = 0, f.length = 0;
100
- }
101
- return {
102
- setViewport(e, t) {
103
- if (!_) {
104
- if (v = Math.max(0, e), y = Math.max(v, t), s === 0) {
105
- N();
106
- return;
107
- }
108
- b && clearTimeout(b), b = setTimeout(() => {
109
- b = null, N();
110
- }, s);
111
- }
112
- },
113
- rows() {
114
- if (S) return S;
115
- let e = T(), i = Array(e);
116
- i.fill(t);
117
- for (let [t, a] of d) {
118
- let o = w(t);
119
- if (!(o >= e)) {
120
- if (a.status === "failed") {
121
- let t = Math.min(o + r, e);
122
- for (let e = o; e < t; e += 1) i[e] = n;
123
- continue;
124
- }
125
- for (let t = 0; t < a.rows.length && o + t < e; t += 1) i[o + t] = a.rows[t];
126
- }
127
- }
128
- return S = i, i;
129
- },
130
- getRow(e) {
131
- let r = d.get(C(e));
132
- return r ? r.status === "failed" ? n : r.rows[e - w(C(e))] ?? t : t;
133
- },
134
- rowCount: () => g ? h : null,
135
- lastRowKnown: () => g,
136
- retryFailed() {
137
- let e = !1;
138
- for (let [t, n] of [...d]) n.status === "failed" && (d.delete(t), O(t), e = !0);
139
- e && D();
140
- },
141
- retryFailedAt(e) {
142
- let t = C(Math.max(0, e));
143
- d.get(t)?.status === "failed" && (d.delete(t), O(t), D());
144
- },
145
- refresh() {
146
- for (let [e, t] of [...d]) t.controller?.abort(), d.delete(e), O(e);
147
- D();
148
- },
149
- purge() {
150
- P(), d.clear(), h = null, g = !1, S = null, N(), D();
151
- },
152
- setRowCount(e, t = e != null) {
153
- h = e, g = t && e != null, D();
154
- },
155
- applyRows(e, t, n) {
156
- if (e % r !== 0) throw Error(`createBlockCache.applyRows: startRow ${e} is not a multiple of blockSize ${r}`);
157
- let i = C(e), a = Math.ceil(t.length / r);
158
- for (let e = 0; e < a; e += 1) {
159
- let n = i + e;
160
- d.get(n)?.controller?.abort(), d.set(n, {
161
- status: "loaded",
162
- rows: t.slice(e * r, (e + 1) * r),
163
- lastTouched: m += 1,
164
- controller: null
165
- });
166
- }
167
- let o = d.get(i + a - 1);
168
- o ? j(i + a - 1, o.rows.length, n) : typeof n == "number" && n >= 0 && (h = n, g = !0), D();
169
- },
170
- patch(e, t) {
171
- let n = d.get(C(e));
172
- if (!n || n.status !== "loaded") return !1;
173
- let r = e - w(C(e));
174
- return r < 0 || r >= n.rows.length ? !1 : (n.rows[r] = t, D(), !0);
175
- },
176
- findIndex(e) {
177
- for (let [t, n] of d) {
178
- if (n.status !== "loaded") continue;
179
- let r = w(t);
180
- for (let t = 0; t < n.rows.length; t += 1) if (e(n.rows[t], r + t)) return r + t;
181
- }
182
- return -1;
183
- },
184
- insert(e, t) {
185
- if (t.length === 0) return !1;
186
- let n = Math.max(0, Math.min(e, T())), r = F(n);
187
- return r ? (r.flat.splice(n - w(r.startBlock), 0, ...t), I(r.startBlock, r.flat)) : L(C(n)), g && h != null && (h += t.length), D(), r != null;
188
- },
189
- remove(e, t = 1) {
190
- if (t <= 0) return 0;
191
- let n = F(e);
192
- if (!n) return 0;
193
- let r = n.flat.splice(e - w(n.startBlock), t).length;
194
- return I(n.startBlock, n.flat), g && h != null && (h = Math.max(0, h - r)), D(), r;
195
- },
196
- getCacheState() {
197
- return [...d.entries()].map(([e, t]) => ({
198
- blockIndex: e,
199
- startRow: w(e),
200
- endRow: w(e) + r,
201
- status: t.status,
202
- lastTouched: t.lastTouched
203
- })).sort((e, t) => e.blockIndex - t.blockIndex);
204
- },
205
- dispose() {
206
- _ = !0, b && clearTimeout(b), b = null, P(), d.clear();
207
- }
208
- };
209
- function F(e) {
210
- let t = C(e);
211
- if (d.get(t)?.status !== "loaded") return null;
212
- let n = t;
213
- for (; d.get(n - 1)?.status === "loaded";) --n;
214
- let i = [];
215
- for (let e = n;; e += 1) {
216
- let t = d.get(e);
217
- if (!t || t.status !== "loaded" || (i.push(...t.rows), t.rows.length < r)) break;
218
- }
219
- return {
220
- startBlock: n,
221
- flat: i
222
- };
223
- }
224
- function I(e, t) {
225
- let n = Math.ceil(t.length / r);
226
- L(e);
227
- for (let i = 0; i < n; i += 1) d.set(e + i, {
228
- status: "loaded",
229
- rows: t.slice(i * r, (i + 1) * r),
230
- lastTouched: m += 1,
231
- controller: null
232
- });
233
- S = null;
234
- }
235
- function L(e) {
236
- for (let [t, n] of [...d]) t < e || (n.controller?.abort(), d.delete(t));
237
- S = null;
238
- }
239
- }
240
- //#endregion
241
- export { i as n, r, o as t };