@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.
- package/README.md +32 -11
- package/dist/GridMenus.svelte +34 -4
- package/dist/SvGrid.controller.svelte.d.ts +33 -5
- package/dist/SvGrid.controller.svelte.js +397 -58
- package/dist/SvGrid.css +200 -2
- package/dist/SvGrid.svelte +350 -40
- package/dist/SvGrid.types.d.ts +433 -7
- package/dist/SvGridDropdown.svelte +20 -0
- package/dist/SvGridDropdown.svelte.d.ts +12 -0
- package/dist/SvModal.svelte +22 -0
- package/dist/SvModal.svelte.d.ts +7 -0
- package/dist/a11y/dismissable.d.ts +10 -0
- package/dist/a11y/dismissable.js +24 -2
- package/dist/build-api.js +92 -37
- package/dist/cdn/{GridMenus-BL7ZgQvU.js → GridMenus-C-NtjlrJ.js} +155 -146
- package/dist/cdn/GridMenus-TssHej3q.js +644 -0
- package/dist/cdn/{SvChartMenu-FBSMINA6.js → SvChartMenu-BFSTpvB-.js} +1 -1
- package/dist/cdn/{SvChartMenu-Bl6PBbkT.js → SvChartMenu-BZ1Iwv0y.js} +1 -1
- package/dist/cdn/{SvDateTimePicker-DQwt4UAs.js → SvDateTimePicker-D9u_cOf8.js} +1 -1
- package/dist/cdn/{SvDateTimePicker-vNU6bZ-q.js → SvDateTimePicker-s_6IUpI7.js} +1 -1
- package/dist/cdn/{SvGridCellEditor-B1p-vCK5.js → SvGridCellEditor-BlyCSp0q.js} +1 -1
- package/dist/cdn/{SvGridCellEditor-D_0q4xAu.js → SvGridCellEditor-ClRRA9lW.js} +1 -1
- package/dist/cdn/{SvGridChart-DzLkSwCH.js → SvGridChart-B4EV8U6t.js} +4 -4
- package/dist/cdn/{SvGridChart-C3EWAZaM.js → SvGridChart-DsmwTyZF.js} +4 -4
- package/dist/cdn/{SvGridChartBuilder-CfII62sZ.js → SvGridChartBuilder-cHloHobN.js} +4 -4
- package/dist/cdn/{SvGridChartBuilder-BE2T1ykB.js → SvGridChartBuilder-vOl7C0Za.js} +4 -4
- package/dist/cdn/{SvGridChartPanel-xf4sWVTo.js → SvGridChartPanel-AcqF-Ll5.js} +5 -5
- package/dist/cdn/{SvGridChartPanel-CCX5_Wgd.js → SvGridChartPanel-biMtSBPA.js} +5 -5
- package/dist/cdn/{SvGridChartView-DYwabQWj.js → SvGridChartView-Dx_GmZuL.js} +2 -2
- package/dist/cdn/{SvGridChartView-CfuXmY5I.js → SvGridChartView-I3rDHXAq.js} +2 -2
- package/dist/cdn/{SvGridDropdown-D0VdjeR8.js → SvGridDropdown-BWeM3lMe.js} +46 -46
- package/dist/cdn/{SvGridDropdown-D13MtJ2j.js → SvGridDropdown-CJ6QqTxu.js} +67 -67
- package/dist/cdn/{SvModal-CIZWCcad.js → SvModal-ClxGmpAc.js} +187 -186
- package/dist/cdn/{SvModal-BAE-pjZX.js → SvModal-DhB_VMFR.js} +148 -147
- package/dist/cdn/{cell-formatting-C2Hf5gqd.js → cell-formatting-DVVKOSI9.js} +1 -1
- package/dist/cdn/{chart-Dz7SqMXH.js → chart-DEZxwC0i.js} +1 -1
- package/dist/cdn/{chart-panel-messages-CUbf2R4i.js → chart-panel-messages-D12XcTZJ.js} +1 -1
- package/dist/cdn/{chart-panel-messages-CmNrMdsr.js → chart-panel-messages-DguS7gC5.js} +1 -1
- package/dist/cdn/{chart-summary-BJW_tg_X.js → chart-summary-CMAXBGY-.js} +1 -1
- package/dist/cdn/{chart-trend-CaN9mDEV.js → chart-trend-BkEp61Gj.js} +1 -1
- package/dist/cdn/{dismissable-DAHetSNk.js → dismissable-Brc4EZU1.js} +5 -1
- package/dist/cdn/{export-format-CUDLy2yn.js → export-format-YzdwBww2.js} +1 -1
- package/dist/cdn/{row-resize-niQCp040.js → row-resize-DtOS1KG6.js} +41 -32
- package/dist/cdn/server-block-cache-DIqb3VZn.js +241 -0
- package/dist/cdn/{src-V1uu8iE9.js → src-CgoeSM8k.js} +5339 -4753
- package/dist/cdn/{src-BKhZ6eXd.js → src-DfwxB1TH.js} +9817 -9231
- package/dist/cdn/svgrid.js +28 -27
- package/dist/cdn/svgrid.svelte-external.js +28 -27
- package/dist/cdn/validate-AZoD8BoR.js +80 -0
- package/dist/cell-formatting.js +18 -1
- package/dist/cell-render.js +25 -6
- package/dist/clipboard.d.ts +2 -2
- package/dist/clipboard.js +72 -23
- package/dist/columns.js +7 -2
- package/dist/conditional-formatting.d.ts +2 -0
- package/dist/conditional-formatting.js +2 -0
- package/dist/core.d.ts +22 -6
- package/dist/core.js +401 -38
- package/dist/editing.js +34 -0
- package/dist/gantt-view.svelte.d.ts +24 -0
- package/dist/gantt-view.svelte.js +13 -0
- package/dist/grid-icons.d.ts +2 -2
- package/dist/grid-icons.js +2 -2
- package/dist/grid-messages.d.ts +10 -0
- package/dist/grid-messages.js +9 -0
- package/dist/headless.d.ts +5 -0
- package/dist/headless.js +12 -0
- package/dist/history.d.ts +21 -0
- package/dist/history.js +34 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -3
- package/dist/keyboard-handlers.js +24 -1
- package/dist/keyboard.js +4 -0
- package/dist/row-drag-touch.d.ts +1 -1
- package/dist/row-drag.js +35 -1
- package/dist/row-model.d.ts +139 -0
- package/dist/row-model.js +16 -0
- package/dist/row-resize.js +22 -1
- package/dist/selection.d.ts +2 -1
- package/dist/selection.js +31 -3
- package/dist/server-block-cache.d.ts +219 -0
- package/dist/server-block-cache.js +539 -0
- package/dist/server-data-source.d.ts +274 -8
- package/dist/server-data-source.js +229 -20
- package/dist/server.d.ts +13 -0
- package/dist/server.js +13 -0
- package/dist/sparkline.js +7 -5
- package/dist/svgrid-wrapper.types.d.ts +33 -0
- package/dist/validate.d.ts +4 -0
- package/dist/validate.js +29 -3
- package/package.json +11 -1
- package/src/GridMenus.svelte +34 -4
- package/src/SvGrid.controller.svelte.ts +397 -61
- package/src/SvGrid.css +200 -2
- package/src/SvGrid.svelte +350 -40
- package/src/SvGrid.types.ts +453 -7
- package/src/SvGridDropdown.svelte +20 -0
- package/src/SvModal.svelte +22 -0
- package/src/SvModal.test.ts +30 -1
- package/src/a11y/dismissable.test.ts +10 -1
- package/src/a11y/dismissable.ts +22 -2
- package/src/build-api.ts +96 -31
- package/src/cell-formatting.test.ts +17 -0
- package/src/cell-formatting.ts +18 -1
- package/src/cell-render.test.ts +24 -2
- package/src/cell-render.ts +24 -8
- package/src/clipboard.test.ts +107 -0
- package/src/clipboard.ts +62 -23
- package/src/columns.test.ts +4 -4
- package/src/columns.ts +7 -2
- package/src/conditional-formatting.test.ts +8 -0
- package/src/conditional-formatting.ts +3 -0
- package/src/core.rowmodel-cache.test.ts +51 -0
- package/src/core.tick-repair.test.ts +287 -0
- package/src/core.ts +407 -38
- package/src/editing.test.ts +52 -0
- package/src/editing.ts +33 -0
- package/src/gantt-stub.test.svelte +38 -0
- package/src/gantt-view.svelte.ts +35 -0
- package/src/grid-icons.ts +2 -2
- package/src/grid-messages.test.ts +7 -0
- package/src/grid-messages.ts +22 -0
- package/src/headless.ts +24 -0
- package/src/history.test.ts +49 -1
- package/src/history.ts +48 -2
- package/src/icon-seam.test.ts +2 -4
- package/src/index.ts +38 -10
- package/src/keyboard-handlers.coverage.test.ts +65 -0
- package/src/keyboard-handlers.ts +26 -1
- package/src/keyboard.ts +3 -0
- package/src/row-drag-touch.ts +2 -2
- package/src/row-drag.test.ts +51 -0
- package/src/row-drag.ts +35 -2
- package/src/row-model.ts +152 -0
- package/src/row-resize.ts +24 -1
- package/src/selection.test.ts +3 -0
- package/src/selection.ts +33 -3
- package/src/server-block-cache.test.ts +672 -0
- package/src/server-block-cache.ts +690 -0
- package/src/server-data-source.infinite.test.ts +405 -0
- package/src/server-data-source.test.ts +19 -0
- package/src/server-data-source.ts +496 -29
- package/src/server.ts +49 -0
- package/src/sparkline.test.ts +7 -0
- package/src/sparkline.ts +6 -4
- package/src/svgrid-wrapper.types.ts +32 -0
- package/src/svgrid.api.test.ts +21 -0
- package/src/svgrid.charting.test.ts +12 -4
- package/src/svgrid.context-menu.test.ts +12 -0
- package/src/svgrid.detail-rows.svelte.test.ts +187 -0
- package/src/svgrid.filter-menu-scroll.test.ts +9 -0
- package/src/svgrid.gantt-seam.test.ts +199 -0
- package/src/svgrid.live-update-paths.svelte.test.ts +184 -0
- package/src/svgrid.menu-scroll-close.test.ts +10 -0
- package/src/svgrid.row-model-prop.svelte.test.ts +352 -0
- package/src/svgrid.row-model-seam.svelte.test.ts +305 -0
- package/src/svgrid.row-pinning.test.ts +15 -1
- package/src/svgrid.selection-bar-seam.test.ts +1 -1
- package/src/svgrid.sticky-groups.svelte.test.ts +145 -0
- package/src/svgrid.upsell-license.test.ts +8 -5
- package/src/test-setup.ts +12 -0
- package/src/transaction.test.ts +58 -0
- package/src/validate.test.ts +29 -0
- package/src/validate.ts +34 -3
- package/dist/SvGroupCell.svelte +0 -141
- package/dist/SvGroupCell.svelte.d.ts +0 -49
- package/dist/SvRowGroupPanel.svelte +0 -186
- package/dist/SvRowGroupPanel.svelte.d.ts +0 -25
- package/dist/cdn/GridMenus-7kbpnnBW.js +0 -635
- package/dist/cdn/validate-_CDJzgIo.js +0 -75
- package/dist/server-group-model.d.ts +0 -98
- package/dist/server-group-model.js +0 -263
- package/src/SvGroupCell.svelte +0 -141
- package/src/SvRowGroupPanel.svelte +0 -186
- package/src/server-group-model.test.ts +0 -294
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
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
|
|
2506
|
-
// before the spacer whatever the window shows,
|
|
2507
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|