@svgrid/grid 2.6.21 → 2.6.22
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/CHANGELOG.md +62 -0
- package/README.md +22 -0
- package/dist/GridMenus.svelte +17 -12
- package/dist/SvGrid.controller.svelte.d.ts +13 -8
- package/dist/SvGrid.controller.svelte.js +150 -72
- package/dist/SvGrid.css +1 -1
- package/dist/SvGrid.svelte +110 -56
- package/dist/SvGrid.types.d.ts +41 -1
- package/dist/cdn/{GridMenus-BfTAKn84.js → GridMenus-BuoBPqxx.js} +137 -132
- package/dist/cdn/GridMenus-n4llxoOI.js +494 -0
- package/dist/cdn/column-resize-DsfNXMom.js +102 -0
- package/dist/cdn/row-resize-BRcimkUT.js +95 -0
- package/dist/cdn/{src-BYq-qyrp.js → src-C9Hihx1W.js} +3456 -3459
- package/dist/cdn/{src-DBel9wRZ.js → src-D1lXwq1l.js} +8283 -8286
- package/dist/cdn/svgrid.js +10 -8
- package/dist/cdn/svgrid.svelte-external.js +10 -8
- package/dist/column-groups.js +1 -1
- package/dist/column-resize.d.ts +46 -0
- package/dist/column-resize.js +205 -0
- package/dist/columns.d.ts +0 -3
- package/dist/columns.js +0 -57
- package/dist/core.d.ts +19 -4
- package/dist/core.js +460 -119
- package/dist/filtering/excel-filters.js +28 -0
- package/dist/group-display.d.ts +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +6 -0
- package/dist/menus.js +1 -1
- package/dist/row-resize.d.ts +11 -0
- package/dist/row-resize.js +7 -1
- package/dist/selection.js +9 -0
- package/dist/spreadsheet.d.ts +1 -1
- package/dist/spreadsheet.js +1 -1
- package/package.json +1 -1
- package/src/GridMenus.svelte +17 -12
- package/src/SvGrid.controller.svelte.ts +155 -74
- package/src/SvGrid.css +1 -1
- package/src/SvGrid.svelte +110 -56
- package/src/SvGrid.types.ts +41 -1
- package/src/column-groups.ts +1 -1
- package/src/column-resize.test.ts +381 -0
- package/src/column-resize.ts +227 -0
- package/src/columns.test.ts +0 -103
- package/src/columns.ts +0 -58
- package/src/core.aggregate.test.ts +134 -0
- package/src/core.filter.test.ts +156 -0
- package/src/core.grouping.test.ts +146 -0
- package/src/core.row-shape.test.ts +119 -0
- package/src/core.rowmodel-cache.test.ts +121 -0
- package/src/core.sort.test.ts +293 -0
- package/src/core.ts +516 -119
- package/src/filtering/excel-filters.ts +30 -0
- package/src/filtering/normalize-fast-path.test.ts +104 -0
- package/src/group-display.ts +1 -1
- package/src/index.ts +12 -1
- package/src/menus.ts +1 -1
- package/src/resize-props.test.ts +361 -0
- package/src/row-resize.test.ts +31 -0
- package/src/row-resize.ts +21 -3
- package/src/selection.ts +9 -0
- package/src/spreadsheet.ts +1 -1
- package/dist/cdn/GridMenus-C3bJd7w8.js +0 -489
|
@@ -456,9 +456,6 @@ export function createSvGridController<
|
|
|
456
456
|
let editorSelectAll = true;
|
|
457
457
|
/** Per-column width overrides set by the resize handles. */
|
|
458
458
|
let columnWidths = $state<Record<string, number>>({});
|
|
459
|
-
let resizingColumnId = $state<string | null>(null);
|
|
460
|
-
let resizeStartX = 0;
|
|
461
|
-
let resizeStartWidth = 0;
|
|
462
459
|
const MIN_COLUMN_WIDTH = 40;
|
|
463
460
|
/** Columns pinned to the left or right edge of the grid (sticky positioning).
|
|
464
461
|
* Seeded from `props.initialColumnPinning` so demos / tests can show the
|
|
@@ -475,7 +472,28 @@ export function createSvGridController<
|
|
|
475
472
|
let dataStateVersion = $state(0);
|
|
476
473
|
const selectionColumnWidth = 44;
|
|
477
474
|
const rowNumberColumnWidth = $derived(props.rowNumberWidth ?? 56);
|
|
478
|
-
|
|
475
|
+
// A per-row `rowHeight` function already supplies heights, so auto-measuring
|
|
476
|
+
// would fight it. Fixed numbers are fine - they become the pre-measure estimate.
|
|
477
|
+
const autoRowHeightOn = $derived(
|
|
478
|
+
props.autoRowHeight === true && typeof props.rowHeight !== "function",
|
|
479
|
+
);
|
|
480
|
+
// Auto height measures the row from its content, so a dragged height would be
|
|
481
|
+
// overwritten on the next measurement pass. Let auto height win rather than
|
|
482
|
+
// having the two fight.
|
|
483
|
+
const rowResizeOn = $derived(props.rowResize === true && !autoRowHeightOn);
|
|
484
|
+
/**
|
|
485
|
+
* The row-number gutter. Explicit `showRowNumbers` always wins; otherwise
|
|
486
|
+
* `rowResize` brings it in, because a resizable row needs a row header to
|
|
487
|
+
* grab - that is where the drag strip lives, and it is where a spreadsheet
|
|
488
|
+
* puts it. Dragging the edge of a data cell instead works but reads as an
|
|
489
|
+
* accident.
|
|
490
|
+
*
|
|
491
|
+
* Both derived above are declared here rather than beside the rest of the
|
|
492
|
+
* row-resize state further down: a `$derived` referenced before its
|
|
493
|
+
* declaration in a .svelte.ts silently compiles to an empty getter, so this
|
|
494
|
+
* gate would have read `undefined` and the gutter would never appear.
|
|
495
|
+
*/
|
|
496
|
+
const showRowNumbersEffective = $derived(props.showRowNumbers ?? rowResizeOn);
|
|
479
497
|
let columnMenuFor = $state<string | null>(null);
|
|
480
498
|
let columnMenuTab = $state<"general" | "filter" | "columns">("general");
|
|
481
499
|
let columnMenuPos = $state<MenuPosition>({ x: 0, y: 0 });
|
|
@@ -499,11 +517,11 @@ export function createSvGridController<
|
|
|
499
517
|
let commentEditFor = $state<{ rowId: string; columnId: string; x: number; y: number } | null>(null);
|
|
500
518
|
let commentDraft = $state("");
|
|
501
519
|
let valueFilters = $state<Record<string, Set<string>>>({});
|
|
502
|
-
const viewportWidth = $derived.by(()
|
|
520
|
+
const viewportWidth = $derived.by(function viewportWidth_d() {
|
|
503
521
|
viewportVersion;
|
|
504
522
|
return scrollContainer ? scrollContainer.clientWidth : 0;
|
|
505
523
|
});
|
|
506
|
-
const viewportHeight = $derived.by(()
|
|
524
|
+
const viewportHeight = $derived.by(function viewportHeight_d() {
|
|
507
525
|
viewportVersion;
|
|
508
526
|
return scrollContainer ? scrollContainer.clientHeight : 0;
|
|
509
527
|
});
|
|
@@ -529,7 +547,7 @@ export function createSvGridController<
|
|
|
529
547
|
const hb = column.columnDef?.hideBelow;
|
|
530
548
|
return hb != null && viewportWidth > 0 && viewportWidth < hb;
|
|
531
549
|
}
|
|
532
|
-
const scrollMetrics = $derived.by(()
|
|
550
|
+
const scrollMetrics = $derived.by(function scrollMetrics_d() {
|
|
533
551
|
scrollVersion;
|
|
534
552
|
viewportVersion;
|
|
535
553
|
// Track the virtualizers' versions too so when data loads or row /
|
|
@@ -563,7 +581,7 @@ export function createSvGridController<
|
|
|
563
581
|
* - virtualizer.getTotalSize(): correct at initial load (before first paint)
|
|
564
582
|
* - scrollMetrics.scrollHeight: correct after detail rows expand (DOM is live,
|
|
565
583
|
* ResizeObserver on gridRootEl already bumps scrollVersion at that point) */
|
|
566
|
-
const hasVerticalOverflow = $derived.by(()
|
|
584
|
+
const hasVerticalOverflow = $derived.by(function hasVerticalOverflow_d() {
|
|
567
585
|
virtualizer.version;
|
|
568
586
|
const virtualizerSize = virtualizer.getTotalSize();
|
|
569
587
|
// scrollMetrics.scrollHeight is 0 before initial paint; once the table
|
|
@@ -856,7 +874,7 @@ export function createSvGridController<
|
|
|
856
874
|
// Declared here rather than beside the other pagination/state derivations:
|
|
857
875
|
// the auto-group column pipeline below reads it, and a `const` used above its
|
|
858
876
|
// declaration is a type error even though `$derived` is lazy enough at runtime.
|
|
859
|
-
const groupingColumns = $derived.by(()
|
|
877
|
+
const groupingColumns = $derived.by(function groupingColumns_d() {
|
|
860
878
|
gridStateVersion;
|
|
861
879
|
return grid.getState().grouping ?? [];
|
|
862
880
|
});
|
|
@@ -881,7 +899,7 @@ export function createSvGridController<
|
|
|
881
899
|
* any other column. They carry no `field` - their cell content is resolved
|
|
882
900
|
* from the row's group state at render time.
|
|
883
901
|
*/
|
|
884
|
-
const autoGroupColumns = $derived.by(()
|
|
902
|
+
const autoGroupColumns = $derived.by(function autoGroupColumns_d() {
|
|
885
903
|
if (!groupColumnMode) return [] as Column<TData>[];
|
|
886
904
|
const sourceById = new Map(grid.getAllColumns().map((c) => [c.id, c]));
|
|
887
905
|
return autoGroupSpec.autoColumns.map((spec) => {
|
|
@@ -950,7 +968,7 @@ export function createSvGridController<
|
|
|
950
968
|
};
|
|
951
969
|
}
|
|
952
970
|
|
|
953
|
-
const allColumns = $derived.by(()
|
|
971
|
+
const allColumns = $derived.by(function allColumns_d() {
|
|
954
972
|
let raw = grid
|
|
955
973
|
.getAllColumns()
|
|
956
974
|
.filter(
|
|
@@ -996,7 +1014,7 @@ export function createSvGridController<
|
|
|
996
1014
|
});
|
|
997
1015
|
|
|
998
1016
|
/** Header groups reordered to match {@link allColumns}. */
|
|
999
|
-
const headerGroups = $derived.by(()
|
|
1017
|
+
const headerGroups = $derived.by(function headerGroups_d() {
|
|
1000
1018
|
const base = grid.getHeaderGroups();
|
|
1001
1019
|
if (!base.length) return base;
|
|
1002
1020
|
const byId = new Map(
|
|
@@ -1054,7 +1072,7 @@ export function createSvGridController<
|
|
|
1054
1072
|
collapsible: boolean;
|
|
1055
1073
|
collapsed: boolean;
|
|
1056
1074
|
};
|
|
1057
|
-
const groupHeaderRows = $derived.by(()
|
|
1075
|
+
const groupHeaderRows = $derived.by(function groupHeaderRows_d() {
|
|
1058
1076
|
const userCols: Array<ColumnDef<any, TData>> =
|
|
1059
1077
|
(props.columns as unknown as Array<ColumnDef<any, TData>>) ?? [];
|
|
1060
1078
|
|
|
@@ -1184,7 +1202,7 @@ export function createSvGridController<
|
|
|
1184
1202
|
});
|
|
1185
1203
|
|
|
1186
1204
|
/** Cumulative pixel offsets for left- and right-pinned columns. */
|
|
1187
|
-
const pinnedOffsets = $derived.by(()
|
|
1205
|
+
const pinnedOffsets = $derived.by(function pinnedOffsets_d() {
|
|
1188
1206
|
const rowNumberWidth = showRowNumbersEffective ? rowNumberColumnWidth : 0;
|
|
1189
1207
|
const selectionWidth = showRowSelectionEffective ? selectionColumnWidth : 0;
|
|
1190
1208
|
const left: Record<string, number> = {};
|
|
@@ -1241,7 +1259,7 @@ export function createSvGridController<
|
|
|
1241
1259
|
);
|
|
1242
1260
|
// Per-column numeric min/max, needed only by colorScale / dataBar formats.
|
|
1243
1261
|
// Lazy: this derived never runs unless `conditionalFormats` is set.
|
|
1244
|
-
const conditionalColumnStats = $derived.by(()
|
|
1262
|
+
const conditionalColumnStats = $derived.by(function conditionalColumnStats_d() {
|
|
1245
1263
|
const map = new Map<string, ColumnStat>();
|
|
1246
1264
|
const formats = props.conditionalFormats;
|
|
1247
1265
|
if (!formats?.length || !formatsNeedingStats(formats)) return map;
|
|
@@ -1288,7 +1306,7 @@ export function createSvGridController<
|
|
|
1288
1306
|
|
|
1289
1307
|
|
|
1290
1308
|
|
|
1291
|
-
const sortDirectionByColumn = $derived.by(()
|
|
1309
|
+
const sortDirectionByColumn = $derived.by(function sortDirectionByColumn_d() {
|
|
1292
1310
|
gridStateVersion;
|
|
1293
1311
|
const directions: Record<string, false | "asc" | "desc"> = {};
|
|
1294
1312
|
for (const column of allColumns)
|
|
@@ -1297,7 +1315,7 @@ export function createSvGridController<
|
|
|
1297
1315
|
});
|
|
1298
1316
|
|
|
1299
1317
|
|
|
1300
|
-
const paginationState = $derived.by(()
|
|
1318
|
+
const paginationState = $derived.by(function paginationState_d() {
|
|
1301
1319
|
gridStateVersion;
|
|
1302
1320
|
return grid.getState().pagination ?? { pageIndex: 0, pageSize: 10 };
|
|
1303
1321
|
});
|
|
@@ -1308,7 +1326,7 @@ export function createSvGridController<
|
|
|
1308
1326
|
* compute the correct "X to Y of Z" range and total page count when
|
|
1309
1327
|
* filters reduce the dataset.
|
|
1310
1328
|
*/
|
|
1311
|
-
const allRowsBeforePagination = $derived.by(()
|
|
1329
|
+
const allRowsBeforePagination = $derived.by(function allRowsBeforePagination_d() {
|
|
1312
1330
|
// Depend on dataStateVersion (row-model-affecting store changes) NOT
|
|
1313
1331
|
// gridStateVersion - so moving the active cell / selection does not force
|
|
1314
1332
|
// this O(rows) pipeline to re-run. Filter-input state (globalFilter etc.)
|
|
@@ -1337,6 +1355,26 @@ export function createSvGridController<
|
|
|
1337
1355
|
);
|
|
1338
1356
|
}
|
|
1339
1357
|
|
|
1358
|
+
/**
|
|
1359
|
+
* Resolve a column ONCE and return a reader for it.
|
|
1360
|
+
*
|
|
1361
|
+
* `getRowColumnValue` finds the column with a linear scan over every
|
|
1362
|
+
* column, which is fine for a one-off read and wrong inside a loop over
|
|
1363
|
+
* 100,000 rows - it made each filtered column cost O(rows x columns).
|
|
1364
|
+
* The id is fixed for the life of a filter, so the scan is hoisted here and
|
|
1365
|
+
* the row loop gets a closure that only reads.
|
|
1366
|
+
*
|
|
1367
|
+
* Falls back to the row's own accessor when the id names no column, which
|
|
1368
|
+
* is also what `getRowColumnValue` does - group rows override
|
|
1369
|
+
* `getCellValueByColumnId` to return their aggregate.
|
|
1370
|
+
*/
|
|
1371
|
+
const makeColumnReader = (columnId: string) => {
|
|
1372
|
+
const column = allColumns.find((entry: any) => entry.id === columnId);
|
|
1373
|
+
return column
|
|
1374
|
+
? (row: Row<TData>) => getColumnBaseValue(row, column)
|
|
1375
|
+
: (row: Row<TData>) => row.getCellValueByColumnId(columnId);
|
|
1376
|
+
};
|
|
1377
|
+
|
|
1340
1378
|
// A single condition is "active" if it has the value(s) it needs.
|
|
1341
1379
|
const condActive = (op: FilterOperator, value: string, valueTo?: string): boolean => {
|
|
1342
1380
|
if (op === "isBlank" || op === "isNotBlank") return true;
|
|
@@ -1368,6 +1406,11 @@ export function createSvGridController<
|
|
|
1368
1406
|
// become compiled predicates before a single row is tested.
|
|
1369
1407
|
const compiledMenuFilters = menuFilters.map(([columnId, f]) => ({
|
|
1370
1408
|
columnId,
|
|
1409
|
+
// The column, resolved once. `getRowColumnValue` looks it up with a
|
|
1410
|
+
// linear scan of every column, and the id is fixed per filter, so
|
|
1411
|
+
// leaving that inside the row loop made it O(rows x columns) per
|
|
1412
|
+
// filtered column for no reason.
|
|
1413
|
+
readValue: makeColumnReader(columnId),
|
|
1371
1414
|
join: f.join,
|
|
1372
1415
|
a: condActive(f.operator, f.value, f.valueTo)
|
|
1373
1416
|
? compileCond(columnId, f.operator, f.value, f.valueTo)
|
|
@@ -1377,8 +1420,8 @@ export function createSvGridController<
|
|
|
1377
1420
|
: null,
|
|
1378
1421
|
}));
|
|
1379
1422
|
rows = rows.filter((row) =>
|
|
1380
|
-
compiledMenuFilters.every(({
|
|
1381
|
-
const cellValue =
|
|
1423
|
+
compiledMenuFilters.every(({ readValue, join, a, b }) => {
|
|
1424
|
+
const cellValue = readValue(row);
|
|
1382
1425
|
const ra = a ? a(cellValue) : null;
|
|
1383
1426
|
const rb = b ? b(cellValue) : null;
|
|
1384
1427
|
if (ra === null) return rb ?? true;
|
|
@@ -1396,11 +1439,12 @@ export function createSvGridController<
|
|
|
1396
1439
|
const bucketEntries = valueFilterEntries.map(([columnId, allowed]) => ({
|
|
1397
1440
|
columnId,
|
|
1398
1441
|
allowed,
|
|
1442
|
+
readValue: makeColumnReader(columnId),
|
|
1399
1443
|
buckets: facetBucketsByColumn.get(columnId) ?? null,
|
|
1400
1444
|
}));
|
|
1401
1445
|
rows = rows.filter((row) =>
|
|
1402
|
-
bucketEntries.every(({
|
|
1403
|
-
const raw =
|
|
1446
|
+
bucketEntries.every(({ allowed, buckets, readValue }) => {
|
|
1447
|
+
const raw = readValue(row);
|
|
1404
1448
|
if (buckets) {
|
|
1405
1449
|
// Range-bucketed filter: find which bucket this row's value
|
|
1406
1450
|
// falls into and check whether that bucket's label is allowed.
|
|
@@ -1458,7 +1502,7 @@ export function createSvGridController<
|
|
|
1458
1502
|
* is active we page by DATA rows and reprint each page's ancestor banners.
|
|
1459
1503
|
* Null when grouping is off, so the flat path stays a cheap slice.
|
|
1460
1504
|
*/
|
|
1461
|
-
const groupedPage = $derived.by(()
|
|
1505
|
+
const groupedPage = $derived.by(function groupedPage_d() {
|
|
1462
1506
|
if (!paginationEnabled || externalPaginationEnabled) return null;
|
|
1463
1507
|
if (!groupingColumns.length) return null;
|
|
1464
1508
|
const { pageIndex, pageSize } = paginationState;
|
|
@@ -1525,7 +1569,7 @@ export function createSvGridController<
|
|
|
1525
1569
|
* the full dataset rather than the current page (see the comment above
|
|
1526
1570
|
* `_rowModels`).
|
|
1527
1571
|
*/
|
|
1528
|
-
const allRows = $derived.by(()
|
|
1572
|
+
const allRows = $derived.by(function allRows_d() {
|
|
1529
1573
|
const paged = (() => {
|
|
1530
1574
|
const rows = allRowsBeforePagination;
|
|
1531
1575
|
// External pagination: `data` already IS the current page - never slice.
|
|
@@ -1598,7 +1642,7 @@ export function createSvGridController<
|
|
|
1598
1642
|
const paginationPageSize = $derived(
|
|
1599
1643
|
externalPaginationEnabled ? (props.pageSize ?? 10) : paginationState.pageSize,
|
|
1600
1644
|
);
|
|
1601
|
-
const rowSelectionState = $derived.by(()
|
|
1645
|
+
const rowSelectionState = $derived.by(function rowSelectionState_d() {
|
|
1602
1646
|
gridStateVersion;
|
|
1603
1647
|
return grid.getState().rowSelection ?? {};
|
|
1604
1648
|
});
|
|
@@ -1654,7 +1698,7 @@ export function createSvGridController<
|
|
|
1654
1698
|
? props.statusBar.aggregates
|
|
1655
1699
|
: (["count", "sum", "avg", "min", "max"] as const),
|
|
1656
1700
|
);
|
|
1657
|
-
const statusBarStats = $derived.by(()
|
|
1701
|
+
const statusBarStats = $derived.by(function statusBarStats_d() {
|
|
1658
1702
|
if (!statusBarEnabled) return null;
|
|
1659
1703
|
const a = selectionRange.anchor;
|
|
1660
1704
|
const f = selectionRange.focus;
|
|
@@ -1706,7 +1750,7 @@ export function createSvGridController<
|
|
|
1706
1750
|
const toolPanelEnabled = $derived(props.toolPanel === true);
|
|
1707
1751
|
// Every column (including hidden ones) in the user's current order, so the
|
|
1708
1752
|
// panel can toggle/reorder anything. Group columns are flagged live.
|
|
1709
|
-
const toolPanelColumns = $derived.by(()
|
|
1753
|
+
const toolPanelColumns = $derived.by(function toolPanelColumns_d() {
|
|
1710
1754
|
gridStateVersion;
|
|
1711
1755
|
const all = grid.getAllColumns();
|
|
1712
1756
|
if (!userColumnOrder.length) return all;
|
|
@@ -1743,7 +1787,7 @@ export function createSvGridController<
|
|
|
1743
1787
|
// unsaid, and why saying it would make the grid talk over itself.
|
|
1744
1788
|
|
|
1745
1789
|
/** Data rows before any local filtering - the denominator in "12 of 250". */
|
|
1746
|
-
const unfilteredRowTotal = $derived.by(()
|
|
1790
|
+
const unfilteredRowTotal = $derived.by(function unfilteredRowTotal_d() {
|
|
1747
1791
|
dataStateVersion;
|
|
1748
1792
|
void internalData;
|
|
1749
1793
|
return grid.getRowModel().rows.length;
|
|
@@ -1840,7 +1884,7 @@ export function createSvGridController<
|
|
|
1840
1884
|
props.onPivotModeChange?.(next);
|
|
1841
1885
|
}
|
|
1842
1886
|
const pivotActive = $derived(!!pivotConfig && pivotModeOn && hasPivotEngine());
|
|
1843
|
-
const pivotResult = $derived.by(()
|
|
1887
|
+
const pivotResult = $derived.by(function pivotResult_d() {
|
|
1844
1888
|
if (!pivotActive || !pivotConfig) return null;
|
|
1845
1889
|
const engine = getPivotEngine();
|
|
1846
1890
|
if (!engine) return null;
|
|
@@ -1944,7 +1988,7 @@ export function createSvGridController<
|
|
|
1944
1988
|
const h = col.columnDef.header;
|
|
1945
1989
|
return typeof h === "string" && h ? h : (col.columnDef.field ?? col.id);
|
|
1946
1990
|
};
|
|
1947
|
-
const chartableColumns = $derived.by(()
|
|
1991
|
+
const chartableColumns = $derived.by(function chartableColumns_d() {
|
|
1948
1992
|
const dims: Array<{ id: string; field: string; label: string }> = [];
|
|
1949
1993
|
const measures: Array<{ id: string; field: string; label: string }> = [];
|
|
1950
1994
|
for (const col of allColumns) {
|
|
@@ -1956,7 +2000,7 @@ export function createSvGridController<
|
|
|
1956
2000
|
}
|
|
1957
2001
|
return { dims, measures };
|
|
1958
2002
|
});
|
|
1959
|
-
const chartColumnDefaults = $derived.by(()
|
|
2003
|
+
const chartColumnDefaults = $derived.by(function chartColumnDefaults_d() {
|
|
1960
2004
|
const { dims, measures } = chartableColumns;
|
|
1961
2005
|
let dimId = dims[0]?.id ?? null;
|
|
1962
2006
|
let seriesId: string | null = null;
|
|
@@ -2315,7 +2359,7 @@ export function createSvGridController<
|
|
|
2315
2359
|
typeof props.containerHeight === "number" ? props.containerHeight : 520,
|
|
2316
2360
|
);
|
|
2317
2361
|
|
|
2318
|
-
const virtualRows = $derived.by(()
|
|
2362
|
+
const virtualRows = $derived.by(function virtualRows_d() {
|
|
2319
2363
|
virtualizer.version;
|
|
2320
2364
|
const items = virtualizer.getVirtualItems();
|
|
2321
2365
|
if (items.length || allRows.length === 0) return items;
|
|
@@ -2330,7 +2374,7 @@ export function createSvGridController<
|
|
|
2330
2374
|
props.overscan ?? 8,
|
|
2331
2375
|
);
|
|
2332
2376
|
});
|
|
2333
|
-
const virtualRowTotalSize = $derived.by(()
|
|
2377
|
+
const virtualRowTotalSize = $derived.by(function virtualRowTotalSize_d() {
|
|
2334
2378
|
virtualizer.version;
|
|
2335
2379
|
const size = virtualizer.getTotalSize();
|
|
2336
2380
|
// Keep the scroll height honest during the pre-measurement render, so the
|
|
@@ -2389,7 +2433,7 @@ export function createSvGridController<
|
|
|
2389
2433
|
// OWN committed scroll offset - not the live DOM scrollTop - so the spacer
|
|
2390
2434
|
// shift and the rendered window are always computed from the same state and
|
|
2391
2435
|
// can never skew by a frame (which would jitter at extreme scale).
|
|
2392
|
-
const rowOffsetAdjustment = $derived.by(()
|
|
2436
|
+
const rowOffsetAdjustment = $derived.by(function rowOffsetAdjustment_d() {
|
|
2393
2437
|
if (!rowScrollScalingActive) return 0;
|
|
2394
2438
|
virtualizer.version;
|
|
2395
2439
|
const logical = virtualizer.getState().scrollOffset;
|
|
@@ -2401,11 +2445,11 @@ export function createSvGridController<
|
|
|
2401
2445
|
const rowBottomSpacer = $derived(
|
|
2402
2446
|
Math.max(rowDomTotalSize - (virtualRowEnd - rowOffsetAdjustment), 0),
|
|
2403
2447
|
);
|
|
2404
|
-
const virtualColumns = $derived.by(()
|
|
2448
|
+
const virtualColumns = $derived.by(function virtualColumns_d() {
|
|
2405
2449
|
columnVirtualizerVersion;
|
|
2406
2450
|
return columnVirtualizer.getVirtualItems();
|
|
2407
2451
|
});
|
|
2408
|
-
const virtualColumnTotalSize = $derived.by(()
|
|
2452
|
+
const virtualColumnTotalSize = $derived.by(function virtualColumnTotalSize_d() {
|
|
2409
2453
|
columnVirtualizerVersion;
|
|
2410
2454
|
return columnVirtualizer.getTotalSize();
|
|
2411
2455
|
});
|
|
@@ -2421,7 +2465,7 @@ export function createSvGridController<
|
|
|
2421
2465
|
});
|
|
2422
2466
|
};
|
|
2423
2467
|
|
|
2424
|
-
const renderedColumnItems = $derived.by(()
|
|
2468
|
+
const renderedColumnItems = $derived.by(function renderedColumnItems_d() {
|
|
2425
2469
|
if (!columnVirtualizationEnabled) return allColumnItems();
|
|
2426
2470
|
// Column virtualization is ON by default and its virtualizer, like the row
|
|
2427
2471
|
// one, only learns `count` from an effect - which never runs on a server.
|
|
@@ -2466,7 +2510,7 @@ export function createSvGridController<
|
|
|
2466
2510
|
.map((item) => ({ item, column: allColumns[item.index] }))
|
|
2467
2511
|
.filter(hasRenderedColumn),
|
|
2468
2512
|
);
|
|
2469
|
-
const totalColumnWidth = $derived.by(()
|
|
2513
|
+
const totalColumnWidth = $derived.by(function totalColumnWidth_d() {
|
|
2470
2514
|
if (columnVirtualizationEnabled) return virtualColumnTotalSize;
|
|
2471
2515
|
let total = 0;
|
|
2472
2516
|
for (const column of allColumns) total += getColumnWidth(column.id);
|
|
@@ -2481,7 +2525,7 @@ export function createSvGridController<
|
|
|
2481
2525
|
* column instead is reactive to both `columnWidths` and
|
|
2482
2526
|
* `fittedColumnWidths`, so the overflow decision settles in the same
|
|
2483
2527
|
* render where fit-scaling lands - no race, no scrollbar flash. */
|
|
2484
|
-
const hasHorizontalOverflow = $derived.by(()
|
|
2528
|
+
const hasHorizontalOverflow = $derived.by(function hasHorizontalOverflow_d() {
|
|
2485
2529
|
const fixedCols =
|
|
2486
2530
|
(showRowNumbersEffective ? rowNumberColumnWidth : 0) +
|
|
2487
2531
|
(showRowSelectionEffective ? selectionColumnWidth : 0);
|
|
@@ -2514,7 +2558,7 @@ export function createSvGridController<
|
|
|
2514
2558
|
* everything stays pixel-aligned. When virtualization is off this is a
|
|
2515
2559
|
* pass-through.
|
|
2516
2560
|
*/
|
|
2517
|
-
const groupHeaderRowsWindowed = $derived.by(()
|
|
2561
|
+
const groupHeaderRowsWindowed = $derived.by(function groupHeaderRowsWindowed_d() {
|
|
2518
2562
|
const base = groupHeaderRows;
|
|
2519
2563
|
if (!columnVirtualizationEnabled || base.length === 0) return base;
|
|
2520
2564
|
const items = renderedColumnItems;
|
|
@@ -2537,14 +2581,14 @@ export function createSvGridController<
|
|
|
2537
2581
|
});
|
|
2538
2582
|
});
|
|
2539
2583
|
|
|
2540
|
-
const activeCell = $derived.by(()
|
|
2584
|
+
const activeCell = $derived.by(function activeCell_d() {
|
|
2541
2585
|
gridStateVersion;
|
|
2542
2586
|
return (
|
|
2543
2587
|
grid.getState().activeCell ?? { rowIndex: 0, colIndex: 0, cellId: null }
|
|
2544
2588
|
);
|
|
2545
2589
|
});
|
|
2546
2590
|
|
|
2547
|
-
const activeDescendantId = $derived.by(()
|
|
2591
|
+
const activeDescendantId = $derived.by(function activeDescendantId_d() {
|
|
2548
2592
|
const active = activeCell;
|
|
2549
2593
|
const inRows = active.rowIndex >= 0 && active.rowIndex < allRows.length;
|
|
2550
2594
|
const inCols = active.colIndex >= 0 && active.colIndex < allColumns.length;
|
|
@@ -2594,7 +2638,7 @@ export function createSvGridController<
|
|
|
2594
2638
|
* `null` above the cell limit - that case stays on the rAF-deferred effect,
|
|
2595
2639
|
* which keeps a huge grid painting before it totals.
|
|
2596
2640
|
*/
|
|
2597
|
-
const eagerSummaries = $derived.by(()
|
|
2641
|
+
const eagerSummaries = $derived.by(function eagerSummaries_d() {
|
|
2598
2642
|
if (!summarize) return null;
|
|
2599
2643
|
if (!rowSummariesEnabled) return null;
|
|
2600
2644
|
const rows = allRows;
|
|
@@ -2746,15 +2790,41 @@ export function createSvGridController<
|
|
|
2746
2790
|
// is the reactive signal instead, bumped only when a height actually changes.
|
|
2747
2791
|
const measuredRowHeights = new Map<number, number>();
|
|
2748
2792
|
let autoRowHeightVersion = $state(0);
|
|
2749
|
-
// A per-row `rowHeight` function already supplies heights, so auto-measuring
|
|
2750
|
-
// would fight it. Fixed numbers are fine - they become the pre-measure estimate.
|
|
2751
|
-
const autoRowHeightOn = $derived(
|
|
2752
|
-
props.autoRowHeight === true && typeof props.rowHeight !== "function",
|
|
2753
|
-
);
|
|
2754
2793
|
const autoRowHeightFallback = $derived(
|
|
2755
2794
|
typeof props.rowHeight === "number" ? props.rowHeight : 30,
|
|
2756
2795
|
);
|
|
2757
2796
|
|
|
2797
|
+
// ----- Interactive row resize (`rowResize` prop) -----
|
|
2798
|
+
// Heights the user has dragged, by row index. A plain Map plus a version
|
|
2799
|
+
// counter, exactly like `measuredRowHeights` above and for the same reason:
|
|
2800
|
+
// the reset effect below has to read this collection to know whether there is
|
|
2801
|
+
// anything to clear, and if the collection were reactive that read would make
|
|
2802
|
+
// every resize re-trigger the reset and wipe the height it just stored.
|
|
2803
|
+
const rowResizeHeights = new Map<number, number>();
|
|
2804
|
+
let rowResizeVersion = $state(0);
|
|
2805
|
+
|
|
2806
|
+
function setRowResizeHeight(index: number, height: number): void {
|
|
2807
|
+
if (!rowResizeOn || !Number.isFinite(index) || height <= 0) return;
|
|
2808
|
+
rowResizeHeights.set(index, Math.round(height));
|
|
2809
|
+
rowResizeVersion += 1;
|
|
2810
|
+
}
|
|
2811
|
+
/** A user-dragged height for this row, or undefined when it has not been
|
|
2812
|
+
* resized. Read by the view AND by the virtualizer's `estimateSize`. */
|
|
2813
|
+
function rowResizeHeightPx(index: number): number | undefined {
|
|
2814
|
+
return rowResizeOn ? rowResizeHeights.get(index) : undefined;
|
|
2815
|
+
}
|
|
2816
|
+
|
|
2817
|
+
// A row index means a different row once the data changes, so keeping the
|
|
2818
|
+
// heights would size new rows by the old ones - the same reasoning as the
|
|
2819
|
+
// measured-height reset below.
|
|
2820
|
+
$effect(() => {
|
|
2821
|
+
void allRows.length;
|
|
2822
|
+
void internalData;
|
|
2823
|
+
if (rowResizeHeights.size === 0) return;
|
|
2824
|
+
rowResizeHeights.clear();
|
|
2825
|
+
rowResizeVersion += 1;
|
|
2826
|
+
});
|
|
2827
|
+
|
|
2758
2828
|
/** Report a row's measured height. Called by the view's measuring action.
|
|
2759
2829
|
* Sub-pixel churn is ignored so a fractional layout can't loop. */
|
|
2760
2830
|
function reportRowHeight(index: number, height: number): void {
|
|
@@ -2825,11 +2895,20 @@ export function createSvGridController<
|
|
|
2825
2895
|
// the estimate for rows that have not rendered yet. Touch the version so a
|
|
2826
2896
|
// new measurement re-runs this effect (the Map itself is not reactive).
|
|
2827
2897
|
autoRowHeightVersion;
|
|
2828
|
-
|
|
2898
|
+
// Touch the version so a resize re-runs this effect: the virtualizer has to
|
|
2899
|
+
// know the new size or every row below the resized one is positioned
|
|
2900
|
+
// against a stale offset.
|
|
2901
|
+
rowResizeVersion;
|
|
2902
|
+
const base = autoRowHeightOn
|
|
2829
2903
|
? (index: number) => measuredRowHeights.get(index) ?? autoRowHeightFallback
|
|
2830
2904
|
: typeof rh === "function"
|
|
2831
2905
|
? rh
|
|
2832
2906
|
: (rh ?? 30);
|
|
2907
|
+
const estimateSize = rowResizeOn
|
|
2908
|
+
? (index: number) =>
|
|
2909
|
+
rowResizeHeights.get(index) ??
|
|
2910
|
+
(typeof base === "function" ? base(index) : base)
|
|
2911
|
+
: base;
|
|
2833
2912
|
virtualizer.setOptions({
|
|
2834
2913
|
count: allRows.length,
|
|
2835
2914
|
estimateSize,
|
|
@@ -2956,7 +3035,7 @@ export function createSvGridController<
|
|
|
2956
3035
|
|
|
2957
3036
|
|
|
2958
3037
|
|
|
2959
|
-
const headerSelectionState = $derived.by(()
|
|
3038
|
+
const headerSelectionState = $derived.by(function headerSelectionState_d() {
|
|
2960
3039
|
gridStateVersion;
|
|
2961
3040
|
const selectable = allRows.filter((row) => !isGroupRow(row));
|
|
2962
3041
|
if (!selectable.length) return "none";
|
|
@@ -2991,7 +3070,7 @@ export function createSvGridController<
|
|
|
2991
3070
|
* Returns `null` when fit scaling is not in effect (off, no room, total
|
|
2992
3071
|
* already >= target). Callers then fall back to the base width.
|
|
2993
3072
|
*/
|
|
2994
|
-
const fittedColumnWidths = $derived.by(()
|
|
3073
|
+
const fittedColumnWidths = $derived.by(function fittedColumnWidths_d() {
|
|
2995
3074
|
// Track viewport size (not scrollVersion) so we don't recompute on
|
|
2996
3075
|
// every scroll - only when the container actually resizes.
|
|
2997
3076
|
viewportVersion;
|
|
@@ -3057,8 +3136,6 @@ export function createSvGridController<
|
|
|
3057
3136
|
});
|
|
3058
3137
|
|
|
3059
3138
|
|
|
3060
|
-
let resizePendingWidth = 0;
|
|
3061
|
-
let resizeRaf: number | null = null;
|
|
3062
3139
|
|
|
3063
3140
|
|
|
3064
3141
|
|
|
@@ -3070,7 +3147,7 @@ export function createSvGridController<
|
|
|
3070
3147
|
/** Where the fill handle should render: the bottom-right cell of the
|
|
3071
3148
|
* selection range (or the active cell if there's no range). Returns
|
|
3072
3149
|
* null when cell selection is off or there is no anchored selection. */
|
|
3073
|
-
const fillHandleCell = $derived.by(()
|
|
3150
|
+
const fillHandleCell = $derived.by(function fillHandleCell_d() {
|
|
3074
3151
|
if (!(props.enableCellSelection ?? false)) return null;
|
|
3075
3152
|
const anchor = selectionRange.anchor;
|
|
3076
3153
|
const focus = selectionRange.focus;
|
|
@@ -3175,7 +3252,7 @@ export function createSvGridController<
|
|
|
3175
3252
|
* reused by both the facet UI and the row filter. Computing them lazily
|
|
3176
3253
|
* in a $derived means columns with no filter menu open and no active
|
|
3177
3254
|
* filter never pay the iteration cost. */
|
|
3178
|
-
const facetBucketsByColumn = $derived.by(()
|
|
3255
|
+
const facetBucketsByColumn = $derived.by(function facetBucketsByColumn_d() {
|
|
3179
3256
|
const map = new Map<string, Array<FacetBucket>>();
|
|
3180
3257
|
for (const column of allColumns) {
|
|
3181
3258
|
const meta = isBucketableColumn(column);
|
|
@@ -3262,7 +3339,7 @@ export function createSvGridController<
|
|
|
3262
3339
|
source: Array<string> | null;
|
|
3263
3340
|
values: Array<string>;
|
|
3264
3341
|
} | null = null;
|
|
3265
|
-
const columnMenuFacetValues = $derived.by(()
|
|
3342
|
+
const columnMenuFacetValues = $derived.by(function columnMenuFacetValues_d() {
|
|
3266
3343
|
// The funnel popover drives via `filterMenuFor`; the column menu's Filter
|
|
3267
3344
|
// tab drives via `columnMenuFor`. Support whichever is open.
|
|
3268
3345
|
const columnId = filterMenuFor ?? columnMenuFor;
|
|
@@ -3292,7 +3369,7 @@ export function createSvGridController<
|
|
|
3292
3369
|
if (!(filterMenuFor ?? columnMenuFor)) facetCache = null;
|
|
3293
3370
|
});
|
|
3294
3371
|
|
|
3295
|
-
const columnMenuVisibleFacets = $derived.by(()
|
|
3372
|
+
const columnMenuVisibleFacets = $derived.by(function columnMenuVisibleFacets_d() {
|
|
3296
3373
|
const query = columnMenuSearch.trim().toLowerCase();
|
|
3297
3374
|
if (!query) return columnMenuFacetValues;
|
|
3298
3375
|
return columnMenuFacetValues.filter((value) =>
|
|
@@ -3313,7 +3390,7 @@ export function createSvGridController<
|
|
|
3313
3390
|
* "everything checked", so that case materializes the set once here rather
|
|
3314
3391
|
* than every consumer re-deriving it.
|
|
3315
3392
|
*/
|
|
3316
|
-
const columnMenuSelectedFacets = $derived.by(()
|
|
3393
|
+
const columnMenuSelectedFacets = $derived.by(function columnMenuSelectedFacets_d() {
|
|
3317
3394
|
const columnId = filterMenuFor ?? columnMenuFor;
|
|
3318
3395
|
if (!columnId) return EMPTY_FACET_SET;
|
|
3319
3396
|
return valueFilters[columnId] ?? new Set(columnMenuFacetValues);
|
|
@@ -3323,7 +3400,7 @@ export function createSvGridController<
|
|
|
3323
3400
|
// active chip input, narrowed by whatever the user has typed. Uncapped - the
|
|
3324
3401
|
// dropdown windows its rows, so a high-cardinality column costs a list of
|
|
3325
3402
|
// strings, not thousands of nodes.
|
|
3326
|
-
const inSuggestValues = $derived.by(()
|
|
3403
|
+
const inSuggestValues = $derived.by(function inSuggestValues_d() {
|
|
3327
3404
|
if (!inSuggestFor) return EMPTY_FACETS;
|
|
3328
3405
|
const query = inSuggestQuery.trim().toLowerCase();
|
|
3329
3406
|
const all = facetValuesForColumn(inSuggestFor);
|
|
@@ -3441,12 +3518,6 @@ export function createSvGridController<
|
|
|
3441
3518
|
set editorSelectAll(v) { editorSelectAll = v as never; },
|
|
3442
3519
|
get columnWidths() { return columnWidths; },
|
|
3443
3520
|
set columnWidths(v) { columnWidths = v as never; },
|
|
3444
|
-
get resizingColumnId() { return resizingColumnId; },
|
|
3445
|
-
set resizingColumnId(v) { resizingColumnId = v as never; },
|
|
3446
|
-
get resizeStartX() { return resizeStartX; },
|
|
3447
|
-
set resizeStartX(v) { resizeStartX = v as never; },
|
|
3448
|
-
get resizeStartWidth() { return resizeStartWidth; },
|
|
3449
|
-
set resizeStartWidth(v) { resizeStartWidth = v as never; },
|
|
3450
3521
|
get MIN_COLUMN_WIDTH() { return MIN_COLUMN_WIDTH; },
|
|
3451
3522
|
get columnPinning() { return columnPinning; },
|
|
3452
3523
|
set columnPinning(v) { columnPinning = v as never; },
|
|
@@ -3765,6 +3836,15 @@ export function createSvGridController<
|
|
|
3765
3836
|
autoRowHeightVersion;
|
|
3766
3837
|
return (index: number): number | undefined => measuredRowHeights.get(index);
|
|
3767
3838
|
},
|
|
3839
|
+
/** True when the `rowResize` prop is on and nothing overrides it. */
|
|
3840
|
+
get rowResizeOn() { return rowResizeOn; },
|
|
3841
|
+
/** Record the height the user dragged a row to. */
|
|
3842
|
+
get setRowResizeHeight() { return setRowResizeHeight; },
|
|
3843
|
+
/** A row's dragged height, or undefined when it has not been resized. */
|
|
3844
|
+
get rowResizeHeightPx() {
|
|
3845
|
+
rowResizeVersion;
|
|
3846
|
+
return rowResizeHeightPx;
|
|
3847
|
+
},
|
|
3768
3848
|
get virtualRowTotalSize() { return virtualRowTotalSize; },
|
|
3769
3849
|
get virtualRowStart() { return virtualRowStart; },
|
|
3770
3850
|
get virtualRowEnd() { return virtualRowEnd; },
|
|
@@ -3827,13 +3907,6 @@ export function createSvGridController<
|
|
|
3827
3907
|
get getColumnBaseWidth() { return getColumnBaseWidth; },
|
|
3828
3908
|
get fittedColumnWidths() { return fittedColumnWidths; },
|
|
3829
3909
|
get getColumnWidth() { return getColumnWidth; },
|
|
3830
|
-
get resizePendingWidth() { return resizePendingWidth; },
|
|
3831
|
-
set resizePendingWidth(v) { resizePendingWidth = v as never; },
|
|
3832
|
-
get resizeRaf() { return resizeRaf; },
|
|
3833
|
-
set resizeRaf(v) { resizeRaf = v as never; },
|
|
3834
|
-
get startColumnResize() { return startColumnResize; },
|
|
3835
|
-
get onColumnResizeMove() { return onColumnResizeMove; },
|
|
3836
|
-
get endColumnResize() { return endColumnResize; },
|
|
3837
3910
|
get setSelection() { return setSelection; },
|
|
3838
3911
|
get extendSelection() { return extendSelection; },
|
|
3839
3912
|
get isCellInSelectedRange() { return isCellInSelectedRange; },
|
|
@@ -3843,6 +3916,15 @@ export function createSvGridController<
|
|
|
3843
3916
|
get isInFillPreview() { return isInFillPreview; },
|
|
3844
3917
|
get fillMarqueeEdges() { return fillMarqueeEdges; },
|
|
3845
3918
|
get findColumnById() { return findColumnById; },
|
|
3919
|
+
/**
|
|
3920
|
+
* Whether this column may be resized by the user, from its
|
|
3921
|
+
* `ColumnDef.resizable`. Defaults to true, so a column only opts out by
|
|
3922
|
+
* saying so; the grid-wide `columnResize` prop gates all of them above
|
|
3923
|
+
* this. Used by the resize action and by the column menu's Autosize item.
|
|
3924
|
+
*/
|
|
3925
|
+
columnResizable(columnId: string): boolean {
|
|
3926
|
+
return findColumnById(columnId)?.columnDef?.resizable !== false;
|
|
3927
|
+
},
|
|
3846
3928
|
get readCellRaw() { return readCellRaw; },
|
|
3847
3929
|
get writeCellRaw() { return writeCellRaw; },
|
|
3848
3930
|
get applyFillPattern() { return applyFillPattern; },
|
|
@@ -3953,7 +4035,7 @@ export function createSvGridController<
|
|
|
3953
4035
|
const { cellConditionalFormat, computeRowClass, computeCellClass, computeCellTooltip, computeCellValidity, computeCellNote, getColumnEditorOptions, areEditorOptionsLoading, formatListCellValue, formatCellValue, formatPinnedValue, computePinnedCellClass } = createCellRender<TFeatures, TData>(ctx);
|
|
3954
4036
|
const { isCellEditable, isCellEditableAt, getRowColumnValue, getCellDisplayValue, startEditingWithChar, startEditing, stopEditing, startFullRowEdit, setFullRowDraft, commitFullRowEdit, cancelFullRowEdit, saveEditingCell, applyHistoryStep, updateEditingCellValue, onEditorKeyDown, commitAndMoveByTab, focusOnMount, onCellDoubleClick, pasteFromClipboard, onGridPaste } = createEditing<TFeatures, TData>(ctx);
|
|
3955
4037
|
const { isRowSelected, toggleRowSelectionById, toggleSelectAllRows, setActiveCell, scrollActiveCellIntoView, setSelection, extendSelection, isCellInSelectedRange, getCellRangeEdges, getSelectionRects, isInFillPreview, fillMarqueeEdges, findColumnById, onCellPointerDown, onCellPointerEnter, endDragSelection, onWindowPointerMove, onCellClick, emitCellDoubleClick } = createSelection<TFeatures, TData>(ctx);
|
|
3956
|
-
const { cellPinStyle, isColumnPinned, getCurrentColumnOrder, emitColumnOrder, setColumnOrderInternal, applyColumnDrop, onColumnHeaderDragStart, onColumnHeaderDragOver, onColumnHeaderDragLeave, onColumnHeaderDrop, onColumnHeaderDragEnd, pinColumnLeft, pinColumnRight, unpinColumn, toggleColumnVisibleInPanel, moveColumnInPanel, toggleGroupInPanel, getColumnBaseWidth, getColumnWidth,
|
|
4038
|
+
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<TFeatures, TData>(ctx);
|
|
3957
4039
|
const { onRowDragStart, onRowDragOver, onRowDragLeave, onRowDrop, onRowsContainerDragOver, onRowsContainerDrop, onRowDragEnd, onRowPointerDown, destroyRowDrag } = createRowDrag<TFeatures, TData>(ctx);
|
|
3958
4040
|
const { register: registerAlignedGrid, broadcastScroll: broadcastAlignedScroll, broadcastWidths: broadcastAlignedWidths } = createAlignedGrids<TFeatures, TData>(ctx);
|
|
3959
4041
|
const { buildApi } = createGridApi<TFeatures, TData>(ctx);
|
|
@@ -4030,7 +4112,6 @@ export function createSvGridController<
|
|
|
4030
4112
|
// this grid still owns (#68). Each of these is a no-op when idle.
|
|
4031
4113
|
$effect(() => {
|
|
4032
4114
|
return () => {
|
|
4033
|
-
endColumnResize();
|
|
4034
4115
|
hideTooltip();
|
|
4035
4116
|
destroyRowDrag();
|
|
4036
4117
|
};
|
package/src/SvGrid.css
CHANGED
|
@@ -1573,7 +1573,7 @@ select.sv-grid-fr-editor {
|
|
|
1573
1573
|
position: relative;
|
|
1574
1574
|
}
|
|
1575
1575
|
/* Declarative cell validation (column `validate` hook). Invalid cells get a
|
|
1576
|
-
* soft red wash and a red inset ring -
|
|
1576
|
+
* soft red wash and a red inset ring - the conventional spreadsheet invalid-cell look. The
|
|
1577
1577
|
* value keeps rendering as-is; the message (if any) shows as the tooltip. */
|
|
1578
1578
|
.sv-grid-cell-invalid {
|
|
1579
1579
|
background-color: var(--sg-invalid-bg, rgba(239, 68, 68, 0.14)) !important;
|