@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
@@ -171,6 +171,60 @@ export function createSvGridController(rawProps, domIdBase) {
171
171
  // preserves reference identity for non-overridden keys, which the columns-identity
172
172
  // column cache and the `data`/`columns` sync effects rely on.
173
173
  let optionOverrides = $state({});
174
+ /**
175
+ * A `rowModel` answers for the props it can, so a server-backed grid is
176
+ * one prop rather than a dozen.
177
+ *
178
+ * Bumped by the model itself through `subscribe` (see the effect below),
179
+ * which is what makes `getRows()` and `isLoading()` - plain method calls,
180
+ * invisible to the reactive system - re-read when the model changes.
181
+ */
182
+ let rowModelVersion = $state(0);
183
+ const rowModelProps = $derived.by(function rowModelProps_d() {
184
+ const model = rawProps.rowModel;
185
+ if (!model)
186
+ return null;
187
+ rowModelVersion; // read, so a notification re-derives
188
+ const paging = model.pagination;
189
+ return {
190
+ data: model.getRows(),
191
+ loading: model.isLoading(),
192
+ loadingOverlay: true,
193
+ getRowId: model.getRowId,
194
+ // A model that sorts or filters server-side is telling the grid not
195
+ // to do it locally; one that does neither leaves the grid in charge.
196
+ externalSort: model.setSort ? true : undefined,
197
+ externalFilter: model.setFilter ? true : undefined,
198
+ onSortingChange: model.setSort ? (s) => model.setSort(s) : undefined,
199
+ onFiltersChange: model.setFilter ? (f) => model.setFilter(f) : undefined,
200
+ onVisibleRangeChange: model.setViewport
201
+ ? (r) => model.setViewport(r.startIndex, r.endIndex)
202
+ : undefined,
203
+ rowPlaceholder: model.rowPlaceholder,
204
+ onRetryRow: model.retryRow,
205
+ serverGroup: model.group,
206
+ rowSelectionModel: model.selection,
207
+ serverFilterValues: model.filterValues
208
+ ? (columnId) => model.filterValues(columnId)
209
+ : undefined,
210
+ pinnedTopRows: model.pinnedTopRows,
211
+ pinnedBottomRows: model.pinnedBottomRows,
212
+ pivotResultColumns: model.pivotResultColumns ?? undefined,
213
+ externalPagination: paging ? true : undefined,
214
+ rowCount: paging?.rowCount,
215
+ pageIndex: paging?.pageIndex,
216
+ pageSize: paging?.pageSize,
217
+ pageSizeOptions: paging?.pageSizes,
218
+ onPaginationChange: paging
219
+ ? (p) => {
220
+ if (p.pageSize !== paging.pageSize)
221
+ paging.setPageSize(p.pageSize);
222
+ else
223
+ paging.setPage(p.pageIndex);
224
+ }
225
+ : undefined,
226
+ };
227
+ });
174
228
  const props = new Proxy(rawProps, {
175
229
  // Read the override as a PROPERTY (tracked by `$state`), not via `in` (the `has`
176
230
  // trap is not tracked) - so a reactive read of `props.X` re-runs when an override
@@ -179,7 +233,23 @@ export function createSvGridController(rawProps, domIdBase) {
179
233
  // undefined too. Whole-object reassignment on write makes the signal fire.
180
234
  get: (t, k) => {
181
235
  const v = typeof k === "string" ? optionOverrides[k] : undefined;
182
- return v !== undefined ? v : Reflect.get(t, k);
236
+ if (v !== undefined)
237
+ return v;
238
+ // Pivot mode swaps the column list: `pivotResultColumns` (the prop, or
239
+ // the row model's) stands in for `columns` while it is set, and
240
+ // `columns` itself stays the app's own list for when pivot ends.
241
+ if (k === "columns") {
242
+ const pivot = Reflect.get(t, "pivotResultColumns") ??
243
+ rowModelProps?.pivotResultColumns;
244
+ if (pivot)
245
+ return pivot;
246
+ }
247
+ const own = Reflect.get(t, k);
248
+ // A prop written on the grid always beats the row model, so adopting
249
+ // `rowModel` is never all-or-nothing.
250
+ if (own !== undefined || typeof k !== "string")
251
+ return own;
252
+ return rowModelProps?.[k];
183
253
  },
184
254
  });
185
255
  // Resolved capability gates. Capabilities are OFF by default - a bare
@@ -257,7 +327,11 @@ export function createSvGridController(rawProps, domIdBase) {
257
327
  // grows with rows x columns and a Map lookup per cell per render.
258
328
  let editedCellValues = $state.raw({});
259
329
  const UNDO_LIMIT = 200;
260
- let history = $state([]);
330
+ // Raw: pushHistory always assigns a fresh array and nothing renders from a
331
+ // step, so deep proxies would cost 200 wrapped objects for nothing. It also
332
+ // keeps a consumer's `tag` the object it passed, which a proxy would not be:
333
+ // the sheet shell compares tags by identity.
334
+ let history = $state.raw([]);
261
335
  /** Index in `history` of the LAST applied step. -1 means "nothing applied".
262
336
  * undo() decrements; redo() increments. New edits truncate everything
263
337
  * past the pointer (the classic "you can't redo after editing" rule). */
@@ -270,6 +344,9 @@ export function createSvGridController(rawProps, domIdBase) {
270
344
  * $state: it is written and read synchronously inside a single call and
271
345
  * nothing renders from it. */
272
346
  let historyGroupId = undefined;
347
+ /** The consumer's mark for the steps recorded from now on (`api.setHistoryTag`);
348
+ * not $state for the same reason. */
349
+ let historyTag = undefined;
273
350
  let tooltip = $state(null);
274
351
  let tooltipTimer = null;
275
352
  // ---- Find-in-grid ----------------------------------------------------
@@ -340,7 +417,28 @@ export function createSvGridController(rawProps, domIdBase) {
340
417
  // catch-all gridStateVersion, so navigation doesn't rebuild 1M rows.
341
418
  let dataStateVersion = $state(0);
342
419
  const selectionColumnWidth = 44;
420
+ const detailToggleColumnWidth = 36;
343
421
  const rowNumberColumnWidth = $derived(props.rowNumberWidth ?? 56);
422
+ const showDetailToggleEffective = $derived(props.showDetailToggle === true);
423
+ /**
424
+ * What the chevron on a row does, or null when the row has no detail to
425
+ * open: a detail row itself, a group or placeholder on a server model, a
426
+ * row `hasDetail` rules out, or a grid with nothing to call.
427
+ */
428
+ function detailToggleOf(row, rowIndex) {
429
+ const data = row.original;
430
+ if (props.isDetailRow?.(data, rowIndex))
431
+ return null;
432
+ const sg = props.serverGroup;
433
+ if (sg) {
434
+ if (!sg.toggleDetail || sg.isGroup(data) || (sg.hasDetail && !sg.hasDetail(data)))
435
+ return null;
436
+ return { open: sg.detailOpen?.(data) ?? false, toggle: () => sg.toggleDetail(data) };
437
+ }
438
+ if (!props.onDetailToggle || (props.hasDetail && !props.hasDetail(data)))
439
+ return null;
440
+ return { open: props.isDetailOpen?.(data) ?? false, toggle: () => props.onDetailToggle(data, rowIndex) };
441
+ }
344
442
  // A per-row `rowHeight` function already supplies heights, so auto-measuring
345
443
  // would fight it. Fixed numbers are fine - they become the pre-measure estimate.
346
444
  const autoRowHeightOn = $derived(props.autoRowHeight === true && typeof props.rowHeight !== "function");
@@ -493,6 +591,12 @@ export function createSvGridController(rawProps, domIdBase) {
493
591
  const showRowSelectionEffective = $derived(props.showRowSelection ??
494
592
  ((props.selectionMode ?? "both") === "row" ||
495
593
  (props.selectionMode ?? "both") === "both"));
594
+ /** The system columns to the left of the data: row numbers, selection, the detail toggle. */
595
+ const systemColumnsWidth = $derived((showRowNumbersEffective ? rowNumberColumnWidth : 0) +
596
+ (showRowSelectionEffective ? selectionColumnWidth : 0) +
597
+ (showDetailToggleEffective ? detailToggleColumnWidth : 0));
598
+ /** Where the detail-toggle column sticks: after the row numbers and the selection column. */
599
+ const detailToggleColumnLeft = $derived((showRowNumbersEffective ? rowNumberColumnWidth : 0) + (showRowSelectionEffective ? selectionColumnWidth : 0));
496
600
  // `selectable` is the shortcut alias, so it wins over the fine-grained prop,
497
601
  // which in turn wins over `selectionMode` - the same precedence the other
498
602
  // shortcuts use. Unlike them it starts ON (selectionMode defaults to 'both'),
@@ -518,7 +622,10 @@ export function createSvGridController(rawProps, domIdBase) {
518
622
  // re-synced whenever the parent passes a new array; the imperative API
519
623
  // mutates these so add/remove operations don't need a callback round-trip.
520
624
  // svelte-ignore state_referenced_locally
521
- let internalData = $state.raw(props.data);
625
+ // `data` is optional on the type (a `rowModel` may supply the rows
626
+ // instead), so every read falls back to empty rather than to undefined.
627
+ const EMPTY_DATA = [];
628
+ let internalData = $state.raw(props.data ?? EMPTY_DATA);
522
629
  // Resolve `cellDataType` / `inferColumnTypes` into concrete editorType +
523
630
  // format defaults once, up front, so every downstream reader sees a normal
524
631
  // column. Explicit fields on the ColumnDef always win.
@@ -563,7 +670,7 @@ export function createSvGridController(rawProps, domIdBase) {
563
670
  // accumulated cell-edit overrides - otherwise `getCellDisplayValue`
564
671
  // would keep returning the old edited values from `editedCellValues`
565
672
  // even though the underlying data has been replaced.
566
- internalData = props.data;
673
+ internalData = props.data ?? EMPTY_DATA;
567
674
  editedCellValues = {};
568
675
  });
569
676
  $effect(() => {
@@ -588,35 +695,41 @@ export function createSvGridController(rawProps, domIdBase) {
588
695
  // the row-model pipeline is read before any later prop change could apply.
589
696
  // svelte-ignore state_referenced_locally
590
697
  const treeDataConfig = props.treeData;
698
+ // Pagination is intentionally NOT in the grid's row-model pipeline. The
699
+ // wrapper applies its own filters (filterMenuValues, globalFilter,
700
+ // valueFilters) on top of `grid.getRowModel().rows`. If pagination ran
701
+ // first, those filters would only see the visible page. Instead the wrapper
702
+ // paginates last - see `allRows` below.
703
+ //
704
+ // Built ONCE. Both inputs are captured at mount, and the stages keep state
705
+ // between runs: the sorted and filtered stages hold their last output so a
706
+ // data tick can repair it instead of recomputing (core.ts, `replacedRowsOf`).
707
+ // This used to be a getter that built fresh stages on every read, which
708
+ // threw that cache away on each run - a live feed re-sorted 100k rows on
709
+ // every tick and the row-model memo's `cachedPipeline` never matched.
710
+ const rowModels = {
711
+ coreRowModel: createCoreRowModel(),
712
+ filteredRowModel: createFilteredRowModel(),
713
+ // External-sort mode: pass the rows through untouched so the consumer
714
+ // controls ordering (e.g. tree data that must preserve hierarchy).
715
+ sortedRowModel: externalSortEnabled
716
+ ? passthroughSortedRowModel
717
+ : createSortedRowModel(sortFns),
718
+ // Tree nesting replaces grouping when `treeData` is set - a row cannot
719
+ // be both a hierarchy node and bucketed under a group banner.
720
+ groupedRowModel: treeDataConfig
721
+ ? createTreeRowModel({
722
+ parentField: treeDataConfig.parentField,
723
+ idField: treeDataConfig.idField,
724
+ })
725
+ : createGroupedRowModel(),
726
+ expandedRowModel: createExpandedRowModel(),
727
+ };
591
728
  const grid = createSvGrid({
592
729
  get _features() {
593
730
  return resolveEffectiveFeatures();
594
731
  },
595
- get _rowModels() {
596
- // Pagination is intentionally NOT in the grid's row-model pipeline.
597
- // The wrapper applies its own filters (filterMenuValues, globalFilter,
598
- // valueFilters) on top of `grid.getRowModel().rows`. If pagination
599
- // ran first, those filters would only see the visible page. Instead
600
- // the wrapper paginates last - see `allRows` below.
601
- return {
602
- coreRowModel: createCoreRowModel(),
603
- filteredRowModel: createFilteredRowModel(),
604
- // External-sort mode: pass the rows through untouched so the consumer
605
- // controls ordering (e.g. tree data that must preserve hierarchy).
606
- sortedRowModel: externalSortEnabled
607
- ? passthroughSortedRowModel
608
- : createSortedRowModel(sortFns),
609
- // Tree nesting replaces grouping when `treeData` is set - a row cannot
610
- // be both a hierarchy node and bucketed under a group banner.
611
- groupedRowModel: treeDataConfig
612
- ? createTreeRowModel({
613
- parentField: treeDataConfig.parentField,
614
- idField: treeDataConfig.idField,
615
- })
616
- : createGroupedRowModel(),
617
- expandedRowModel: createExpandedRowModel(),
618
- };
619
- },
732
+ _rowModels: rowModels,
620
733
  get columns() {
621
734
  return internalColumns;
622
735
  },
@@ -796,6 +909,20 @@ export function createSvGridController(rawProps, domIdBase) {
796
909
  *
797
910
  * Returns null when the cell should render nothing.
798
911
  */
912
+ /**
913
+ * Why a row has no data yet, or null when it does.
914
+ *
915
+ * Group rows are never placeholders, so the check is skipped for them:
916
+ * their `original` is a synthetic bucket, not a row the consumer handed
917
+ * us, and passing it to `rowPlaceholder` would ask a question about a row
918
+ * that does not exist.
919
+ */
920
+ function placeholderStateOf(row) {
921
+ const ask = props.rowPlaceholder;
922
+ if (!ask || isGroupRow(row))
923
+ return null;
924
+ return ask(row.original, row.index);
925
+ }
799
926
  function autoGroupCell(row, columnId) {
800
927
  if (!isGroupRow(row))
801
928
  return null;
@@ -1004,10 +1131,8 @@ export function createSvGridController(rawProps, domIdBase) {
1004
1131
  });
1005
1132
  /** Cumulative pixel offsets for left- and right-pinned columns. */
1006
1133
  const pinnedOffsets = $derived.by(function pinnedOffsets_d() {
1007
- const rowNumberWidth = showRowNumbersEffective ? rowNumberColumnWidth : 0;
1008
- const selectionWidth = showRowSelectionEffective ? selectionColumnWidth : 0;
1009
1134
  const left = {};
1010
- let leftAcc = rowNumberWidth + selectionWidth;
1135
+ let leftAcc = systemColumnsWidth;
1011
1136
  for (const id of effectivePinning.left) {
1012
1137
  // Hidden pinned columns don't render, so they must contribute neither an
1013
1138
  // offset entry nor width - otherwise the next visible pinned column is
@@ -1458,16 +1583,44 @@ export function createSvGridController(rawProps, domIdBase) {
1458
1583
  const ids = [];
1459
1584
  if (!selectionBarOn)
1460
1585
  return { rows, ids };
1586
+ // Under an external selection model the loaded rows are the ones the
1587
+ // model says are selected; rows that never loaded are not in `allRows`
1588
+ // and are counted by `selectionBarCount` below instead. This walks
1589
+ // every loaded row, so it runs on every block a row model delivers:
1590
+ // a model that can say "nothing is selected" spares the walk, and the
1591
+ // props it needs are read once, not through the proxy per row.
1592
+ const model = props.rowSelectionModel;
1593
+ if (model && model.selectedCount?.() === 0)
1594
+ return { rows, ids };
1595
+ const ask = props.rowPlaceholder;
1596
+ const isPlaceholder = ask
1597
+ ? (row) => !isGroupRow(row) && !!ask(row.original, row.index)
1598
+ : () => false;
1461
1599
  for (const row of allRows) {
1462
- if (isGroupRow(row))
1600
+ if (isGroupRow(row) || isPlaceholder(row))
1463
1601
  continue;
1464
- if (rowSelectionState[row.id]) {
1602
+ const selected = model
1603
+ ? model.isSelected(row.id, row.original)
1604
+ : !!rowSelectionState[row.id];
1605
+ if (selected) {
1465
1606
  rows.push(row.original);
1466
1607
  ids.push(row.id);
1467
1608
  }
1468
1609
  }
1469
1610
  return { rows, ids };
1470
1611
  });
1612
+ /**
1613
+ * What the selection bar's count chip says. A model that stores the rule
1614
+ * ("everything except these") knows about rows the grid never loaded, so
1615
+ * its number wins over counting ticks on screen; `null` from it means it
1616
+ * cannot say, and the bar falls back to the loaded count.
1617
+ */
1618
+ const selectionBarCount = $derived.by(function selectionBarCount_d() {
1619
+ const fromModel = props.rowSelectionModel?.selectedCount?.();
1620
+ return fromModel ?? selectionBarTarget.ids.length;
1621
+ });
1622
+ /** Whether the bar has anything to show: the model's count when it has one, else the loaded ticks. */
1623
+ const selectionBarVisible = $derived(selectionBarOn && selectionBarCount > 0);
1471
1624
  // Forward selection changes to the consumer. Skips the very first invocation
1472
1625
  // (the initial empty state) so consumers don't get a spurious callback on mount.
1473
1626
  let lastSelectionSerialized = "";
@@ -1496,16 +1649,13 @@ export function createSvGridController(rawProps, domIdBase) {
1496
1649
  // so consumers don't see spurious callbacks during re-renders.
1497
1650
  let lastCellRangeSerialized = "";
1498
1651
  $effect(() => {
1499
- const a = selectionRange.anchor;
1500
- const f = selectionRange.focus;
1501
- const ranges = a && f
1502
- ? [[
1503
- Math.min(a.rowIndex, f.rowIndex),
1504
- Math.min(a.colIndex, f.colIndex),
1505
- Math.max(a.rowIndex, f.rowIndex),
1506
- Math.max(a.colIndex, f.colIndex),
1507
- ]]
1508
- : [];
1652
+ // Every rectangle, the committed ones a Ctrl+click added and the
1653
+ // active one last, the order getSelectionRects gives: a consumer's
1654
+ // status bar and shading cover the whole selection, not only its last
1655
+ // range. Depend on selectionRanges so a change to the committed set
1656
+ // re-runs this too.
1657
+ void selectionRanges;
1658
+ const ranges = getSelectionRects().map((r) => [r.minRow, r.minCol, r.maxRow, r.maxCol]);
1509
1659
  const serialized = JSON.stringify(ranges);
1510
1660
  if (serialized === lastCellRangeSerialized)
1511
1661
  return;
@@ -2419,6 +2569,59 @@ export function createSvGridController(rawProps, domIdBase) {
2419
2569
  const virtualRowStart = $derived.by(() => virtualRows[0]?.start ?? 0);
2420
2570
  const virtualRowEnd = $derived.by(() => virtualRows[virtualRows.length - 1]?.end ?? 0);
2421
2571
  const virtualRowBottomSpacer = $derived.by(() => Math.max(virtualRowTotalSize - virtualRowEnd, 0));
2572
+ // A row model tells us when to re-read it. Subscribing here (rather than
2573
+ // polling, or asking the consumer to wrap the model in a rune) is what lets
2574
+ // `getRows()` be a plain method call on a plain object.
2575
+ $effect(() => {
2576
+ const model = rawProps.rowModel;
2577
+ if (!model)
2578
+ return;
2579
+ return model.subscribe(() => {
2580
+ rowModelVersion += 1;
2581
+ });
2582
+ });
2583
+ // The index range on screen, for data sources that fetch by block.
2584
+ // `virtualRowStart` / `virtualRowEnd` above are PIXEL offsets; a fetcher
2585
+ // needs row numbers, and needs them whether or not virtualization is on.
2586
+ const visibleRowRange = $derived.by(function visibleRowRange_d() {
2587
+ if (!rowVirtualizationEnabled) {
2588
+ return { startIndex: 0, endIndex: Math.max(0, allRows.length - 1) };
2589
+ }
2590
+ const first = virtualRows[0];
2591
+ const last = virtualRows[virtualRows.length - 1];
2592
+ if (!first || !last)
2593
+ return { startIndex: 0, endIndex: 0 };
2594
+ return { startIndex: first.index, endIndex: last.index };
2595
+ });
2596
+ // Emitted from an effect rather than the derived so a consumer that
2597
+ // fetches (and therefore changes `data`) cannot re-enter the derivation.
2598
+ let lastReportedRange = "";
2599
+ $effect(() => {
2600
+ const report = props.onVisibleRangeChange;
2601
+ if (!report)
2602
+ return;
2603
+ const range = visibleRowRange;
2604
+ const key = range.startIndex + ":" + range.endIndex;
2605
+ if (key === lastReportedRange)
2606
+ return;
2607
+ lastReportedRange = key;
2608
+ report(range);
2609
+ });
2610
+ // A paging row model that asks for `autoPageSize` gets as many rows as
2611
+ // the body shows without scrolling, re-measured as the viewport changes.
2612
+ $effect(() => {
2613
+ rowModelVersion;
2614
+ const paging = rawProps.rowModel?.pagination;
2615
+ if (!paging?.autoPageSize)
2616
+ return;
2617
+ const height = viewportHeight;
2618
+ if (height <= 0)
2619
+ return;
2620
+ const rowPx = rowSizePxOf(0) || 30;
2621
+ const fit = Math.max(1, Math.floor(height / rowPx));
2622
+ if (fit !== paging.pageSize)
2623
+ paging.setPageSize(fit);
2624
+ });
2422
2625
  // --- Huge-list scroll scaling -----------------------------------------
2423
2626
  // Browsers cap how tall a single element may be, and mobile caps sit well
2424
2627
  // below desktop. Past a few hundred thousand rows the true content height
@@ -2483,6 +2686,16 @@ export function createSvGridController(rawProps, domIdBase) {
2483
2686
  return total;
2484
2687
  });
2485
2688
  /** The declared or dragged height of one row; measured under auto height. */
2689
+ /** A detail row's declared height, or null when the row is not one (or none is declared). */
2690
+ function detailRowHeightPx(i) {
2691
+ const dh = props.detailRowHeight;
2692
+ if (dh == null || !props.isDetailRow)
2693
+ return null;
2694
+ const row = allRows[i];
2695
+ if (!row || !props.isDetailRow(row.original, i))
2696
+ return null;
2697
+ return typeof dh === "function" ? dh(row.original) : dh;
2698
+ }
2486
2699
  function rowSizePxOf(i) {
2487
2700
  if (isRowCollapsed(i))
2488
2701
  return 0;
@@ -2491,6 +2704,9 @@ export function createSvGridController(rawProps, domIdBase) {
2491
2704
  const own = rowResizeHeightPx(i);
2492
2705
  if (own != null)
2493
2706
  return own;
2707
+ const detail = detailRowHeightPx(i);
2708
+ if (detail != null)
2709
+ return detail;
2494
2710
  const rh = props.rowHeight;
2495
2711
  return typeof rh === "function" ? rh(i) : (rh ?? 30);
2496
2712
  }
@@ -2501,10 +2717,91 @@ export function createSvGridController(rawProps, domIdBase) {
2501
2717
  top += rowSizePxOf(k);
2502
2718
  return top;
2503
2719
  }
2720
+ const NO_STICKY = [];
2721
+ /** Whether a row is a group and how deep it sits, for any of the three tree sources. */
2722
+ function rowGroupLevel(row) {
2723
+ const sg = props.serverGroup;
2724
+ if (sg) {
2725
+ const data = row.original;
2726
+ return { group: sg.isGroup(data), level: sg.level(data) };
2727
+ }
2728
+ // Client grouping and tree data: an expandable row is the group (a tree
2729
+ // row is a data row too, which is why isGroupRow() excludes it, but for
2730
+ // the band it is the parent its children scroll under).
2731
+ if (typeof row.getCanExpand === "function" && row.getCanExpand())
2732
+ return { group: true, level: row.depth ?? 0 };
2733
+ return { group: false, level: row.depth ?? 0 };
2734
+ }
2735
+ /** The first row whose bottom edge is under the header, in row-index space. */
2736
+ const firstRowUnderHeader = $derived.by(function firstRowUnderHeader_d() {
2737
+ if (allRows.length === 0)
2738
+ return -1;
2739
+ if (rowVirtualizationEnabled) {
2740
+ virtualizer.version;
2741
+ const offset = virtualizer.getState().scrollOffset;
2742
+ const hit = virtualRows.find((it) => it.end > offset);
2743
+ return hit ? hit.index : -1;
2744
+ }
2745
+ rowResizeVersion;
2746
+ autoRowHeightVersion;
2747
+ const top = scrollMetrics.scrollTop;
2748
+ let acc = 0;
2749
+ let i = 0;
2750
+ while (i < allRows.length - 1 && acc + rowSizePxOf(i) <= top) {
2751
+ acc += rowSizePxOf(i);
2752
+ i += 1;
2753
+ }
2754
+ return i;
2755
+ });
2756
+ const stickyGroupRows = $derived.by(function stickyGroupRows_d() {
2757
+ if (!props.stickyGroupRows)
2758
+ return NO_STICKY;
2759
+ const first = firstRowUnderHeader;
2760
+ if (first < 0)
2761
+ return NO_STICKY;
2762
+ const head = allRows[first];
2763
+ if (!head)
2764
+ return NO_STICKY;
2765
+ // A group row at level L, or a leaf at level L, has its ancestors at
2766
+ // levels L-1 .. 0, each the nearest group row above at that level.
2767
+ let want = rowGroupLevel(head).level - 1;
2768
+ if (want < 0)
2769
+ return NO_STICKY;
2770
+ const found = [];
2771
+ for (let i = first - 1; i >= frozenRowCount && want >= 0; i -= 1) {
2772
+ const row = allRows[i];
2773
+ const info = rowGroupLevel(row);
2774
+ if (info.group && info.level === want) {
2775
+ found.push({ row, rowIndex: i });
2776
+ want -= 1;
2777
+ }
2778
+ }
2779
+ if (found.length === 0)
2780
+ return NO_STICKY;
2781
+ found.reverse();
2782
+ rowResizeVersion;
2783
+ autoRowHeightVersion;
2784
+ let top = headerHeight + frozenBandHeight;
2785
+ return found.map((f) => {
2786
+ const at = top;
2787
+ const size = rowSizePxOf(f.rowIndex);
2788
+ top += size;
2789
+ return { ...f, top: at, size };
2790
+ });
2791
+ });
2792
+ /** The band's height under virtualization, taken off the top spacer. */
2793
+ const stickyBandHeight = $derived(rowVirtualizationEnabled ? stickyGroupRows.reduce((sum, s) => sum + s.size, 0) : 0);
2794
+ /** Without virtualization the real row sticks: its top, or undefined. */
2795
+ function stickyTopOfRow(rowIndex) {
2796
+ if (rowVirtualizationEnabled || stickyGroupRows.length === 0)
2797
+ return undefined;
2798
+ return stickyGroupRows.find((s) => s.rowIndex === rowIndex)?.top;
2799
+ }
2504
2800
  // Spacer heights in DOM space. With scaling inert these equal the original
2505
- // virtualRowStart / virtualRowBottomSpacer. The frozen band is in the flow
2506
- // before the spacer whatever the window shows, so it comes off the spacer.
2507
- const rowTopSpacer = $derived(Math.max(virtualRowStart - rowOffsetAdjustment - frozenBandHeight, 0));
2801
+ // virtualRowStart / virtualRowBottomSpacer. The frozen band and the sticky
2802
+ // group band are in the flow before the spacer whatever the window shows,
2803
+ // so they come off the spacer.
2804
+ const rowTopSpacer = $derived(Math.max(virtualRowStart - rowOffsetAdjustment - frozenBandHeight - stickyBandHeight, 0));
2508
2805
  const rowBottomSpacer = $derived(Math.max(rowDomTotalSize - (virtualRowEnd - rowOffsetAdjustment), 0));
2509
2806
  const virtualColumns = $derived.by(function virtualColumns_d() {
2510
2807
  columnVirtualizerVersion;
@@ -2589,9 +2886,7 @@ export function createSvGridController(rawProps, domIdBase) {
2589
2886
  * `fittedColumnWidths`, so the overflow decision settles in the same
2590
2887
  * render where fit-scaling lands - no race, no scrollbar flash. */
2591
2888
  const hasHorizontalOverflow = $derived.by(function hasHorizontalOverflow_d() {
2592
- const fixedCols = (showRowNumbersEffective ? rowNumberColumnWidth : 0) +
2593
- (showRowSelectionEffective ? selectionColumnWidth : 0);
2594
- let total = fixedCols;
2889
+ let total = systemColumnsWidth;
2595
2890
  for (const column of allColumns)
2596
2891
  total += getColumnWidth(column.id);
2597
2892
  // +1 to tolerate sub-pixel rounding residue from `fitColumns`.
@@ -3040,8 +3335,12 @@ export function createSvGridController(rawProps, domIdBase) {
3040
3335
  : typeof rh === "function"
3041
3336
  ? rh
3042
3337
  : (rh ?? 30);
3043
- const estimateSize = rowResizeHeights.size > 0 || collapsedRows.size > 0
3338
+ // Detail rows have their own height; only when the props say so does
3339
+ // the per-index lookup replace the uniform fast path.
3340
+ const detailOn = props.detailRowHeight != null && !!props.isDetailRow;
3341
+ const estimateSize = rowResizeHeights.size > 0 || collapsedRows.size > 0 || detailOn
3044
3342
  ? (index) => rowResizeHeightPx(index) ??
3343
+ detailRowHeightPx(index) ??
3045
3344
  (typeof base === "function" ? base(index) : base)
3046
3345
  : base;
3047
3346
  virtualizer.setOptions({
@@ -3147,7 +3446,24 @@ export function createSvGridController(rawProps, domIdBase) {
3147
3446
  // rows (10k iterations on the large-dataset demo, 100k on its top tier) to
3148
3447
  // recount a selection that had not changed.
3149
3448
  const headerSelectionState = $derived.by(function headerSelectionState_d() {
3150
- const selectable = allRows.filter((row) => !isGroupRow(row));
3449
+ // An external model knows about rows the grid has never seen, so it is
3450
+ // the only thing that can answer honestly once the data is a window
3451
+ // onto a server.
3452
+ if (props.rowSelectionModel)
3453
+ return props.rowSelectionModel.headerState();
3454
+ // Nothing checked is the common case and needs no walk: this derived
3455
+ // re-runs on every data change, and on a 100k-row live feed the filter
3456
+ // below was 30 ms per tick spent to conclude "none".
3457
+ let anyChecked = false;
3458
+ for (const id in rowSelectionState) {
3459
+ if (rowSelectionState[id]) {
3460
+ anyChecked = true;
3461
+ break;
3462
+ }
3463
+ }
3464
+ if (!anyChecked)
3465
+ return "none";
3466
+ const selectable = allRows.filter((row) => !isGroupRow(row) && !placeholderStateOf(row));
3151
3467
  if (!selectable.length)
3152
3468
  return "none";
3153
3469
  let selected = 0;
@@ -3194,8 +3510,6 @@ export function createSvGridController(rawProps, domIdBase) {
3194
3510
  const cols = grid.getAllColumns().filter((c) => !hiddenColumns[c.id] && !hiddenByGroupCollapse[c.id] && !collapsedColumns[c.id]);
3195
3511
  if (!cols.length)
3196
3512
  return null;
3197
- const rowNumberWidth = showRowNumbersEffective ? rowNumberColumnWidth : 0;
3198
- const selectionWidth = showRowSelectionEffective ? selectionColumnWidth : 0;
3199
3513
  // Reserve the custom vertical scrollbar's width when it's visible. It
3200
3514
  // overlays the right 16px of the viewport (absolute, z-index 40) and
3201
3515
  // does NOT shrink clientWidth, so without this the last fitted column
@@ -3203,8 +3517,7 @@ export function createSvGridController(rawProps, domIdBase) {
3203
3517
  // is hidden behind the opaque scrollbar.
3204
3518
  const scrollbarWidth = hasVerticalOverflow ? 16 : 0;
3205
3519
  const target = (scrollContainer?.clientWidth ?? 0) -
3206
- rowNumberWidth -
3207
- selectionWidth -
3520
+ systemColumnsWidth -
3208
3521
  scrollbarWidth;
3209
3522
  if (target <= 0)
3210
3523
  return null;
@@ -3300,7 +3613,7 @@ export function createSvGridController(rawProps, domIdBase) {
3300
3613
  const meta = isBucketableColumn(column);
3301
3614
  if (!meta)
3302
3615
  continue;
3303
- const buckets = buildBuckets(column, meta.isDate, props.data, getColumnAccessorValue);
3616
+ const buckets = buildBuckets(column, meta.isDate, props.data ?? EMPTY_DATA, getColumnAccessorValue);
3304
3617
  if (buckets)
3305
3618
  map.set(column.id, buckets);
3306
3619
  }
@@ -3606,6 +3919,8 @@ export function createSvGridController(rawProps, domIdBase) {
3606
3919
  set historyPtr(v) { historyPtr = v; },
3607
3920
  get historyGroupId() { return historyGroupId; },
3608
3921
  set historyGroupId(v) { historyGroupId = v; },
3922
+ get historyTag() { return historyTag; },
3923
+ set historyTag(v) { historyTag = v; },
3609
3924
  get historyVersion() { return historyVersion; },
3610
3925
  set historyVersion(v) { historyVersion = v; },
3611
3926
  get tooltip() { return tooltip; },
@@ -3642,6 +3957,11 @@ export function createSvGridController(rawProps, domIdBase) {
3642
3957
  get gridStateVersion() { return gridStateVersion; },
3643
3958
  set gridStateVersion(v) { gridStateVersion = v; },
3644
3959
  get selectionColumnWidth() { return selectionColumnWidth; },
3960
+ get detailToggleColumnWidth() { return detailToggleColumnWidth; },
3961
+ get detailToggleColumnLeft() { return detailToggleColumnLeft; },
3962
+ get showDetailToggleEffective() { return showDetailToggleEffective; },
3963
+ get systemColumnsWidth() { return systemColumnsWidth; },
3964
+ get detailToggleOf() { return detailToggleOf; },
3645
3965
  get rowNumberColumnWidth() { return rowNumberColumnWidth; },
3646
3966
  get showRowNumbersEffective() { return showRowNumbersEffective; },
3647
3967
  get filterOperatorOptions() { return filterOperatorOptions; },
@@ -3788,6 +4108,8 @@ export function createSvGridController(rawProps, domIdBase) {
3788
4108
  get selectionBarMaxVisible() { return selectionBarMaxVisible; },
3789
4109
  get selectionBarHideClear() { return selectionBarHideClear; },
3790
4110
  get selectionBarTarget() { return selectionBarTarget; },
4111
+ get selectionBarCount() { return selectionBarCount; },
4112
+ get selectionBarVisible() { return selectionBarVisible; },
3791
4113
  get lastSelectionSerialized() { return lastSelectionSerialized; },
3792
4114
  set lastSelectionSerialized(v) { lastSelectionSerialized = v; },
3793
4115
  get lastCellRangeSerialized() { return lastCellRangeSerialized; },
@@ -4059,6 +4381,8 @@ export function createSvGridController(rawProps, domIdBase) {
4059
4381
  get frozenRowList() { return frozenRowList; },
4060
4382
  get frozenBandHeight() { return frozenBandHeight; },
4061
4383
  get frozenRowTop() { return frozenRowTop; },
4384
+ get stickyGroupRows() { return stickyGroupRows; },
4385
+ get stickyTopOfRow() { return stickyTopOfRow; },
4062
4386
  /** Record the height the user dragged a row to. */
4063
4387
  get setRowResizeHeight() { return setRowResizeHeight; },
4064
4388
  get isRowCollapsed() { return isRowCollapsed; },
@@ -4071,6 +4395,12 @@ export function createSvGridController(rawProps, domIdBase) {
4071
4395
  rowResizeVersion;
4072
4396
  return rowResizeHeightPx;
4073
4397
  },
4398
+ /** The height row i is drawn at: dragged, measured, detail, declared or default. */
4399
+ get rowSizePxOf() {
4400
+ rowResizeVersion;
4401
+ autoRowHeightVersion;
4402
+ return rowSizePxOf;
4403
+ },
4074
4404
  get virtualRowTotalSize() { return virtualRowTotalSize; },
4075
4405
  get virtualRowStart() { return virtualRowStart; },
4076
4406
  get virtualRowEnd() { return virtualRowEnd; },
@@ -4125,7 +4455,14 @@ export function createSvGridController(rawProps, domIdBase) {
4125
4455
  get isRowSelected() { return isRowSelected; },
4126
4456
  get toggleRowSelectionById() { return toggleRowSelectionById; },
4127
4457
  get headerSelectionState() { return headerSelectionState; },
4458
+ get visibleRowRange() { return visibleRowRange; },
4459
+ placeholderStateOf,
4460
+ /** Retry a failed placeholder row. No-op without `onRetryRow`. */
4461
+ retryRow(row) {
4462
+ props.onRetryRow?.(row.original, row.index);
4463
+ },
4128
4464
  get toggleSelectAllRows() { return toggleSelectAllRows; },
4465
+ get setSelectAllRows() { return setSelectAllRows; },
4129
4466
  get userHasActivatedCell() { return userHasActivatedCell; },
4130
4467
  set userHasActivatedCell(v) { userHasActivatedCell = v; },
4131
4468
  get tabRunOrigin() { return tabRunOrigin; },
@@ -4274,7 +4611,7 @@ export function createSvGridController(rawProps, domIdBase) {
4274
4611
  const { updateFilterRow, updateFilterOperator, updateFilterMenuValue, updateFilterMenuValueTo, addFilterToken, removeFilterToken, toggleFilterToken, toggleCheckboxWithKeyboard, isColumnFiltered, closeMenus, openInSuggest, closeInSuggest, openChooseColumns, openColumnMenu, openFilterMenu, openOperatorMenu, sortColumnFromMenu, clearColumnSort, groupByColumnFromMenu, clearGroupingFromMenu, isFacetChecked, toggleFacetValue, setFacetSelection, setFilterTokens, isAllFacetsChecked, toggleAllFacets, clearColumnFilter, changePage, goToPage, setPageSize, openContextMenu, closeContextMenu, contextMenuItems, saveComment, removeComment, closeCommentEditor } = createMenus(ctx);
4275
4612
  const { cellConditionalFormat, computeRowClass, computeCellClass, computeCellTooltip, computeCellValidity, computeCellNote, getColumnEditorOptions, areEditorOptionsLoading, formatListCellValue, formatCellValue, formatPinnedValue, computePinnedCellClass } = createCellRender(ctx);
4276
4613
  const { isCellEditable, isCellEditableAt, getRowColumnValue, getCellDisplayValue, startEditingWithChar, startEditing, stopEditing, startFullRowEdit, setFullRowDraft, commitFullRowEdit, cancelFullRowEdit, saveEditingCell, applyHistoryStep, updateEditingCellValue, onEditorKeyDown, commitAndMoveByTab, focusOnMount, onCellDoubleClick, pasteFromClipboard, onGridPaste, armPasteFallback } = createEditing(ctx);
4277
- const { isRowSelected, toggleRowSelectionById, toggleSelectAllRows, setActiveCell, scrollActiveCellIntoView, setSelection, extendSelection, isCellInSelectedRange, getCellRangeEdges, activeRangeRect, cellSelectionState, getSelectionRects, isInFillPreview, dragPreviewRect, fillMarqueeEdges, findColumnById, onCellPointerDown, onCellPointerEnter, endDragSelection, onWindowPointerMove, onCellClick, emitCellDoubleClick } = createSelection(ctx);
4614
+ const { isRowSelected, toggleRowSelectionById, toggleSelectAllRows, setSelectAllRows, setActiveCell, scrollActiveCellIntoView, setSelection, extendSelection, isCellInSelectedRange, getCellRangeEdges, activeRangeRect, cellSelectionState, getSelectionRects, isInFillPreview, dragPreviewRect, fillMarqueeEdges, findColumnById, onCellPointerDown, onCellPointerEnter, endDragSelection, onWindowPointerMove, onCellClick, emitCellDoubleClick } = createSelection(ctx);
4278
4615
  const { cellPinStyle, isColumnPinned, getCurrentColumnOrder, emitColumnOrder, setColumnOrderInternal, applyColumnDrop, onColumnHeaderDragStart, onColumnHeaderDragOver, onColumnHeaderDragLeave, onColumnHeaderDrop, onColumnHeaderDragEnd, pinColumnLeft, pinColumnRight, unpinColumn, toggleColumnVisibleInPanel, moveColumnInPanel, toggleGroupInPanel, getColumnBaseWidth, getColumnWidth, measureText, autosizeColumn, autosizeAllColumns, resetColumns } = createColumns(ctx);
4279
4616
  const { onRowDragStart, onRowDragOver, onRowDragLeave, onRowDrop, onRowsContainerDragOver, onRowsContainerDrop, onRowDragEnd, onRowPointerDown, destroyRowDrag } = createRowDrag(ctx);
4280
4617
  const { register: registerAlignedGrid, broadcastScroll: broadcastAlignedScroll, broadcastWidths: broadcastAlignedWidths } = createAlignedGrids(ctx);
@@ -4313,6 +4650,8 @@ export function createSvGridController(rawProps, domIdBase) {
4313
4650
  pageSize: props.pageSize,
4314
4651
  groupBy: props.groupBy,
4315
4652
  treeData: props.treeData,
4653
+ gantt: props.gantt,
4654
+ serverGroup: props.serverGroup,
4316
4655
  initialColumnPinning: props.initialColumnPinning,
4317
4656
  columnVirtualization: props.columnVirtualization,
4318
4657
  externalPagination: props.externalPagination,