@svgrid/grid 3.0.4 → 3.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +32 -11
  2. package/dist/GridMenus.svelte +34 -4
  3. package/dist/SvGrid.controller.svelte.d.ts +33 -5
  4. package/dist/SvGrid.controller.svelte.js +397 -58
  5. package/dist/SvGrid.css +200 -2
  6. package/dist/SvGrid.svelte +350 -40
  7. package/dist/SvGrid.types.d.ts +433 -7
  8. package/dist/SvGridDropdown.svelte +20 -0
  9. package/dist/SvGridDropdown.svelte.d.ts +12 -0
  10. package/dist/SvModal.svelte +22 -0
  11. package/dist/SvModal.svelte.d.ts +7 -0
  12. package/dist/a11y/dismissable.d.ts +10 -0
  13. package/dist/a11y/dismissable.js +24 -2
  14. package/dist/build-api.js +92 -37
  15. package/dist/cdn/{GridMenus-BL7ZgQvU.js → GridMenus-C-NtjlrJ.js} +155 -146
  16. package/dist/cdn/GridMenus-TssHej3q.js +644 -0
  17. package/dist/cdn/{SvChartMenu-FBSMINA6.js → SvChartMenu-BFSTpvB-.js} +1 -1
  18. package/dist/cdn/{SvChartMenu-Bl6PBbkT.js → SvChartMenu-BZ1Iwv0y.js} +1 -1
  19. package/dist/cdn/{SvDateTimePicker-DQwt4UAs.js → SvDateTimePicker-D9u_cOf8.js} +1 -1
  20. package/dist/cdn/{SvDateTimePicker-vNU6bZ-q.js → SvDateTimePicker-s_6IUpI7.js} +1 -1
  21. package/dist/cdn/{SvGridCellEditor-B1p-vCK5.js → SvGridCellEditor-BlyCSp0q.js} +1 -1
  22. package/dist/cdn/{SvGridCellEditor-D_0q4xAu.js → SvGridCellEditor-ClRRA9lW.js} +1 -1
  23. package/dist/cdn/{SvGridChart-DzLkSwCH.js → SvGridChart-B4EV8U6t.js} +4 -4
  24. package/dist/cdn/{SvGridChart-C3EWAZaM.js → SvGridChart-DsmwTyZF.js} +4 -4
  25. package/dist/cdn/{SvGridChartBuilder-CfII62sZ.js → SvGridChartBuilder-cHloHobN.js} +4 -4
  26. package/dist/cdn/{SvGridChartBuilder-BE2T1ykB.js → SvGridChartBuilder-vOl7C0Za.js} +4 -4
  27. package/dist/cdn/{SvGridChartPanel-xf4sWVTo.js → SvGridChartPanel-AcqF-Ll5.js} +5 -5
  28. package/dist/cdn/{SvGridChartPanel-CCX5_Wgd.js → SvGridChartPanel-biMtSBPA.js} +5 -5
  29. package/dist/cdn/{SvGridChartView-DYwabQWj.js → SvGridChartView-Dx_GmZuL.js} +2 -2
  30. package/dist/cdn/{SvGridChartView-CfuXmY5I.js → SvGridChartView-I3rDHXAq.js} +2 -2
  31. package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-BWeM3lMe.js} +46 -46
  32. package/dist/cdn/{SvGridDropdown-D13MtJ2j.js → SvGridDropdown-CJ6QqTxu.js} +67 -67
  33. package/dist/cdn/{SvModal-CIZWCcad.js → SvModal-ClxGmpAc.js} +187 -186
  34. package/dist/cdn/{SvModal-BAE-pjZX.js → SvModal-DhB_VMFR.js} +148 -147
  35. package/dist/cdn/{cell-formatting-C2Hf5gqd.js → cell-formatting-DVVKOSI9.js} +1 -1
  36. package/dist/cdn/{chart-Dz7SqMXH.js → chart-DEZxwC0i.js} +1 -1
  37. package/dist/cdn/{chart-panel-messages-CUbf2R4i.js → chart-panel-messages-D12XcTZJ.js} +1 -1
  38. package/dist/cdn/{chart-panel-messages-CmNrMdsr.js → chart-panel-messages-DguS7gC5.js} +1 -1
  39. package/dist/cdn/{chart-summary-BJW_tg_X.js → chart-summary-CMAXBGY-.js} +1 -1
  40. package/dist/cdn/{chart-trend-CaN9mDEV.js → chart-trend-BkEp61Gj.js} +1 -1
  41. package/dist/cdn/{dismissable-DAHetSNk.js → dismissable-Brc4EZU1.js} +5 -1
  42. package/dist/cdn/{export-format-CUDLy2yn.js → export-format-YzdwBww2.js} +1 -1
  43. package/dist/cdn/{row-resize-niQCp040.js → row-resize-DtOS1KG6.js} +41 -32
  44. package/dist/cdn/server-block-cache-DIqb3VZn.js +241 -0
  45. package/dist/cdn/{src-V1uu8iE9.js → src-CgoeSM8k.js} +5339 -4753
  46. package/dist/cdn/{src-BKhZ6eXd.js → src-DfwxB1TH.js} +9817 -9231
  47. package/dist/cdn/svgrid.js +28 -27
  48. package/dist/cdn/svgrid.svelte-external.js +28 -27
  49. package/dist/cdn/validate-AZoD8BoR.js +80 -0
  50. package/dist/cell-formatting.js +18 -1
  51. package/dist/cell-render.js +25 -6
  52. package/dist/clipboard.d.ts +2 -2
  53. package/dist/clipboard.js +72 -23
  54. package/dist/columns.js +7 -2
  55. package/dist/conditional-formatting.d.ts +2 -0
  56. package/dist/conditional-formatting.js +2 -0
  57. package/dist/core.d.ts +22 -6
  58. package/dist/core.js +401 -38
  59. package/dist/editing.js +34 -0
  60. package/dist/gantt-view.svelte.d.ts +24 -0
  61. package/dist/gantt-view.svelte.js +13 -0
  62. package/dist/grid-icons.d.ts +2 -2
  63. package/dist/grid-icons.js +2 -2
  64. package/dist/grid-messages.d.ts +10 -0
  65. package/dist/grid-messages.js +9 -0
  66. package/dist/headless.d.ts +5 -0
  67. package/dist/headless.js +12 -0
  68. package/dist/history.d.ts +21 -0
  69. package/dist/history.js +34 -4
  70. package/dist/index.d.ts +5 -4
  71. package/dist/index.js +3 -3
  72. package/dist/keyboard-handlers.js +24 -1
  73. package/dist/keyboard.js +4 -0
  74. package/dist/row-drag-touch.d.ts +1 -1
  75. package/dist/row-drag.js +35 -1
  76. package/dist/row-model.d.ts +139 -0
  77. package/dist/row-model.js +16 -0
  78. package/dist/row-resize.js +22 -1
  79. package/dist/selection.d.ts +2 -1
  80. package/dist/selection.js +31 -3
  81. package/dist/server-block-cache.d.ts +219 -0
  82. package/dist/server-block-cache.js +539 -0
  83. package/dist/server-data-source.d.ts +274 -8
  84. package/dist/server-data-source.js +229 -20
  85. package/dist/server.d.ts +13 -0
  86. package/dist/server.js +13 -0
  87. package/dist/sparkline.js +7 -5
  88. package/dist/svgrid-wrapper.types.d.ts +33 -0
  89. package/dist/validate.d.ts +4 -0
  90. package/dist/validate.js +29 -3
  91. package/package.json +11 -1
  92. package/src/GridMenus.svelte +34 -4
  93. package/src/SvGrid.controller.svelte.ts +397 -61
  94. package/src/SvGrid.css +200 -2
  95. package/src/SvGrid.svelte +350 -40
  96. package/src/SvGrid.types.ts +453 -7
  97. package/src/SvGridDropdown.svelte +20 -0
  98. package/src/SvModal.svelte +22 -0
  99. package/src/SvModal.test.ts +30 -1
  100. package/src/a11y/dismissable.test.ts +10 -1
  101. package/src/a11y/dismissable.ts +22 -2
  102. package/src/build-api.ts +96 -31
  103. package/src/cell-formatting.test.ts +17 -0
  104. package/src/cell-formatting.ts +18 -1
  105. package/src/cell-render.test.ts +24 -2
  106. package/src/cell-render.ts +24 -8
  107. package/src/clipboard.test.ts +107 -0
  108. package/src/clipboard.ts +62 -23
  109. package/src/columns.test.ts +4 -4
  110. package/src/columns.ts +7 -2
  111. package/src/conditional-formatting.test.ts +8 -0
  112. package/src/conditional-formatting.ts +3 -0
  113. package/src/core.rowmodel-cache.test.ts +51 -0
  114. package/src/core.tick-repair.test.ts +287 -0
  115. package/src/core.ts +407 -38
  116. package/src/editing.test.ts +52 -0
  117. package/src/editing.ts +33 -0
  118. package/src/gantt-stub.test.svelte +38 -0
  119. package/src/gantt-view.svelte.ts +35 -0
  120. package/src/grid-icons.ts +2 -2
  121. package/src/grid-messages.test.ts +7 -0
  122. package/src/grid-messages.ts +22 -0
  123. package/src/headless.ts +24 -0
  124. package/src/history.test.ts +49 -1
  125. package/src/history.ts +48 -2
  126. package/src/icon-seam.test.ts +2 -4
  127. package/src/index.ts +38 -10
  128. package/src/keyboard-handlers.coverage.test.ts +65 -0
  129. package/src/keyboard-handlers.ts +26 -1
  130. package/src/keyboard.ts +3 -0
  131. package/src/row-drag-touch.ts +2 -2
  132. package/src/row-drag.test.ts +51 -0
  133. package/src/row-drag.ts +35 -2
  134. package/src/row-model.ts +152 -0
  135. package/src/row-resize.ts +24 -1
  136. package/src/selection.test.ts +3 -0
  137. package/src/selection.ts +33 -3
  138. package/src/server-block-cache.test.ts +672 -0
  139. package/src/server-block-cache.ts +690 -0
  140. package/src/server-data-source.infinite.test.ts +405 -0
  141. package/src/server-data-source.test.ts +19 -0
  142. package/src/server-data-source.ts +496 -29
  143. package/src/server.ts +49 -0
  144. package/src/sparkline.test.ts +7 -0
  145. package/src/sparkline.ts +6 -4
  146. package/src/svgrid-wrapper.types.ts +32 -0
  147. package/src/svgrid.api.test.ts +21 -0
  148. package/src/svgrid.charting.test.ts +12 -4
  149. package/src/svgrid.context-menu.test.ts +12 -0
  150. package/src/svgrid.detail-rows.svelte.test.ts +187 -0
  151. package/src/svgrid.filter-menu-scroll.test.ts +9 -0
  152. package/src/svgrid.gantt-seam.test.ts +199 -0
  153. package/src/svgrid.live-update-paths.svelte.test.ts +184 -0
  154. package/src/svgrid.menu-scroll-close.test.ts +10 -0
  155. package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
  156. package/src/svgrid.row-model-seam.svelte.test.ts +305 -0
  157. package/src/svgrid.row-pinning.test.ts +15 -1
  158. package/src/svgrid.selection-bar-seam.test.ts +1 -1
  159. package/src/svgrid.sticky-groups.svelte.test.ts +145 -0
  160. package/src/svgrid.upsell-license.test.ts +8 -5
  161. package/src/test-setup.ts +12 -0
  162. package/src/transaction.test.ts +58 -0
  163. package/src/validate.test.ts +29 -0
  164. package/src/validate.ts +34 -3
  165. package/dist/SvGroupCell.svelte +0 -141
  166. package/dist/SvGroupCell.svelte.d.ts +0 -49
  167. package/dist/SvRowGroupPanel.svelte +0 -186
  168. package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
  169. package/dist/cdn/GridMenus-7kbpnnBW.js +0 -635
  170. package/dist/cdn/validate-_CDJzgIo.js +0 -75
  171. package/dist/server-group-model.d.ts +0 -98
  172. package/dist/server-group-model.js +0 -263
  173. package/src/SvGroupCell.svelte +0 -141
  174. package/src/SvRowGroupPanel.svelte +0 -186
  175. package/src/server-group-model.test.ts +0 -294
  176. package/src/server-group-model.ts +0 -370
@@ -60,6 +60,16 @@ export function dismissableDepth() {
60
60
  * window listener gets wrong: inner scroll containers don't bubble, so the
61
61
  * capture listener sees them and dismisses the panel the user is scrolling.
62
62
  *
63
+ * The listener arms one animation frame after it is asked for, not at once.
64
+ * Scroll events are queued and dispatched in the next rendering step, so a
65
+ * scroll that FINISHED before the click that opened the panel - the browser
66
+ * pulling a half-hidden funnel button into view as it focuses it, a test
67
+ * driver scrolling the header into place - still lands after the panel has
68
+ * mounted and wired this listener, and used to close it on the spot. The
69
+ * panel measured its anchor after that scroll, so the event carries nothing
70
+ * it needs to react to. Rendering runs the scroll steps before the animation
71
+ * frame callbacks, which is why one frame is exactly the right delay.
72
+ *
63
73
  * Returns the unsubscribe function.
64
74
  */
65
75
  export function onScrollOutside(element, onOutside) {
@@ -70,6 +80,18 @@ export function onScrollOutside(element, onOutside) {
70
80
  return;
71
81
  onOutside();
72
82
  };
73
- window.addEventListener('scroll', handler, true);
74
- return () => window.removeEventListener('scroll', handler, true);
83
+ let armed = false;
84
+ let frame = requestAnimationFrame(() => {
85
+ frame = null;
86
+ armed = true;
87
+ window.addEventListener('scroll', handler, true);
88
+ });
89
+ return () => {
90
+ if (frame !== null)
91
+ cancelAnimationFrame(frame);
92
+ frame = null;
93
+ if (armed)
94
+ window.removeEventListener('scroll', handler, true);
95
+ armed = false;
96
+ };
75
97
  }
package/dist/build-api.js CHANGED
@@ -2,8 +2,30 @@ import "./sv-grid-scrollbar.js";
2
2
  import { untrack } from "svelte";
3
3
  import { isGroupRow, getColumnAlign, columnDefMatchesId, } from "./cell-values.js";
4
4
  import { hasAdvancedFilterEngine } from "./advanced-filter.svelte.js";
5
- import { undoHistory, redoHistory } from "./history.js";
5
+ import { undoHistory, redoHistory, peekUndoHistory, peekRedoHistory } from "./history.js";
6
6
  import { buildCommandContext } from "./command-context.js";
7
+ /**
8
+ * Row id -> index, per data array, for `applyTransaction`.
9
+ *
10
+ * An update batch used to walk every row calling `getRowId` to find the ones
11
+ * it replaced - 100k calls per tick on a 100k-row feed, whatever the batch
12
+ * size. The map is built once per array and, for an update-only transaction,
13
+ * carried to the array it produces: same ids at the same indices. An add or
14
+ * remove changes indices, so those transactions leave the next array to
15
+ * build its own map on first use. Keyed weakly so a replaced array takes its
16
+ * map with it.
17
+ */
18
+ const rowIndexByData = new WeakMap();
19
+ function rowIndexOf(data, getId) {
20
+ let byId = rowIndexByData.get(data);
21
+ if (!byId) {
22
+ byId = new Map();
23
+ for (let i = 0; i < data.length; i++)
24
+ byId.set(getId(data[i], i), i);
25
+ rowIndexByData.set(data, byId);
26
+ }
27
+ return byId;
28
+ }
7
29
  /**
8
30
  * The selection as the user made it: committed ranges first, the active one
9
31
  * last, each keeping its anchor as `from` and its focus as `to`. The active
@@ -69,6 +91,10 @@ export function createGridApi(ctx) {
69
91
  return projectGridRows(exportScopeRows(scope), exportColumns(), { columns, rawValues });
70
92
  };
71
93
  return {
94
+ getElement() {
95
+ const el = ctx.scrollContainer;
96
+ return el?.closest(".sv-grid-root") ?? null;
97
+ },
72
98
  getCellValue(rowIndex, columnId) {
73
99
  const row = ctx.internalData[rowIndex];
74
100
  const column = findColumn(columnId);
@@ -208,39 +234,41 @@ export function createGridApi(ctx) {
208
234
  },
209
235
  applyTransaction(tx) {
210
236
  const getId = ctx.props.getRowId;
211
- let next = ctx.internalData.slice();
237
+ const current = ctx.internalData;
238
+ let next = current.slice();
212
239
  let added = 0;
213
240
  let updated = 0;
214
241
  let removed = 0;
242
+ // Everything resolves against the indices of `current`: the id ->
243
+ // index map answers updates and id removals with one lookup each, a
244
+ // reference removal with one `indexOf`, and no pass over the rows
245
+ // that did not change. A row both updated and removed in the same
246
+ // transaction ends up removed, as it did when removes ran first.
247
+ const removeIdx = new Set();
215
248
  if (tx.remove?.length) {
216
- const removeIds = new Set();
217
- const removeRefs = new Set();
249
+ const byId = getId ? rowIndexOf(current, getId) : null;
218
250
  for (const r of tx.remove) {
219
- if (typeof r === "string")
220
- removeIds.add(r);
221
- else
222
- removeRefs.add(r);
251
+ const idx = typeof r === "string" ? byId?.get(r) : current.indexOf(r);
252
+ if (idx !== undefined && idx >= 0)
253
+ removeIdx.add(idx);
223
254
  }
224
- next = next.filter((row, i) => {
225
- const hit = removeRefs.has(row) ||
226
- (getId ? removeIds.has(getId(row, i)) : false);
227
- if (hit)
228
- removed += 1;
229
- return !hit;
230
- });
231
255
  }
232
256
  if (tx.update?.length && getId) {
233
- const byId = new Map();
234
- for (const u of tx.update)
235
- byId.set(getId(u, 0), u);
236
- next = next.map((row, i) => {
237
- const u = byId.get(getId(row, i));
238
- if (u) {
239
- updated += 1;
240
- return u;
241
- }
242
- return row;
243
- });
257
+ const byId = rowIndexOf(current, getId);
258
+ for (const u of tx.update) {
259
+ const idx = byId.get(getId(u, 0));
260
+ if (idx === undefined)
261
+ continue;
262
+ next[idx] = u;
263
+ updated += 1;
264
+ }
265
+ // Same ids at the same indices: the next array can reuse the map.
266
+ if (!removeIdx.size && !tx.add?.length)
267
+ rowIndexByData.set(next, byId);
268
+ }
269
+ if (removeIdx.size) {
270
+ next = next.filter((_, i) => !removeIdx.has(i));
271
+ removed = removeIdx.size;
244
272
  }
245
273
  if (tx.add?.length) {
246
274
  next.push(...tx.add);
@@ -472,6 +500,26 @@ export function createGridApi(ctx) {
472
500
  getData() {
473
501
  return ctx.internalData;
474
502
  },
503
+ getRowId(row) {
504
+ // The stable id the grid keys a row by: what `getRowId` computed,
505
+ // or the row's position when no `getRowId` prop is set. A number is
506
+ // a DISPLAY index into the rendered rows, the space getActiveCell,
507
+ // scrollToRow and the cell methods work in; a row object is looked
508
+ // up wherever it sits. Null when the index or the object is unknown,
509
+ // so a caller can tell "no such row" from a real id.
510
+ if (typeof row === "number") {
511
+ const found = ctx.allRows[row];
512
+ return found && !isGroupRow(found) ? found.id : null;
513
+ }
514
+ const inRows = ctx.allRows.find((r) => r.original === row);
515
+ if (inRows)
516
+ return inRows.id;
517
+ const getId = ctx.props.getRowId;
518
+ const index = ctx.internalData.indexOf(row);
519
+ if (index < 0)
520
+ return null;
521
+ return getId ? getId(row, index) : String(index);
522
+ },
475
523
  getColumns() {
476
524
  // Snapshot every column with its human-readable label and
477
525
  // visibility flag. Used by external code (exporters, column
@@ -580,11 +628,10 @@ export function createGridApi(ctx) {
580
628
  ctx.autosizeColumn(columnId);
581
629
  },
582
630
  getRowHeight(rowIndex) {
583
- const own = ctx.rowResizeHeightPx(rowIndex);
584
- if (own != null)
585
- return own;
586
- const declared = ctx.props.rowHeight;
587
- return typeof declared === "function" ? declared(rowIndex) : (declared ?? 30);
631
+ // The height the grid draws the row at, whatever decided it: a drag,
632
+ // a measurement under auto height, a detail row's own height, the
633
+ // declared rowHeight or the default.
634
+ return ctx.rowSizePxOf(rowIndex);
588
635
  },
589
636
  setRowHeight(rowIndex, height) {
590
637
  ctx.setRowResizeHeight(rowIndex, height);
@@ -657,6 +704,9 @@ export function createGridApi(ctx) {
657
704
  canUndo() { void ctx.historyVersion; return ctx.historyPtr >= 0; },
658
705
  canRedo() { void ctx.historyVersion; return ctx.historyPtr < ctx.history.length - 1; },
659
706
  clearHistory() { ctx.history = []; ctx.historyPtr = -1; ctx.historyVersion += 1; },
707
+ setHistoryTag(tag) { ctx.historyTag = tag; },
708
+ peekUndo() { void ctx.historyVersion; return peekUndoHistory(ctx); },
709
+ peekRedo() { void ctx.historyVersion; return peekRedoHistory(ctx); },
660
710
  // ---- Find
661
711
  openFind() { ctx.findOpen = true; },
662
712
  closeFind() { ctx.findOpen = false; ctx.findQuery = ''; },
@@ -691,11 +741,10 @@ export function createGridApi(ctx) {
691
741
  });
692
742
  },
693
743
  selectAllRows() {
694
- const next = {};
695
- for (const row of ctx.allRows)
696
- if (!isGroupRow(row))
697
- next[row.id] = true;
698
- ctx.grid.setRowSelection(() => next);
744
+ // One implementation of "select everything", shared with the header
745
+ // checkbox, so it knows about an external selection model and about
746
+ // rows whose data has not arrived.
747
+ ctx.setSelectAllRows(true);
699
748
  },
700
749
  toggleRowSelected(id) {
701
750
  ctx.toggleRowSelectionById(id);
@@ -703,7 +752,13 @@ export function createGridApi(ctx) {
703
752
  // ---- Pagination
704
753
  getPageInfo() {
705
754
  const { pageIndex, pageSize } = ctx.paginationState;
706
- const total = ctx.allRowsBeforePagination.length;
755
+ // Under external pagination the grid holds ONE page, so counting the
756
+ // rows in hand would report a 95-row table as a 20-row one. The
757
+ // consumer tells us the real total through rowCount, which is what
758
+ // the footer has always shown.
759
+ const total = ctx.externalPaginationEnabled
760
+ ? (ctx.props.rowCount ?? ctx.allRowsBeforePagination.length)
761
+ : ctx.allRowsBeforePagination.length;
707
762
  const pageCount = Math.max(1, Math.ceil(total / Math.max(1, pageSize)));
708
763
  return { pageIndex, pageSize, pageCount, total };
709
764
  },