@svgrid/grid 1.2.3 → 1.2.4
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/dist/SvGrid.controller.svelte.js +84 -18
- package/dist/a11y.d.ts +1 -1
- package/dist/a11y.js +1 -1
- package/dist/cdn/svgrid.js +538 -504
- package/dist/cdn/svgrid.svelte-external.js +1944 -1910
- package/dist/menus.js +9 -1
- package/dist/scroll-sync.js +1 -1
- package/dist/sv-grid-scrollbar.js +16 -1
- package/package.json +1 -1
- package/src/SvGrid.controller.svelte.ts +82 -17
- package/src/a11y.ts +1 -1
- package/src/menus.ts +9 -1
- package/src/scroll-sync.ts +1 -1
- package/src/sv-grid-scrollbar.ts +14 -1
|
@@ -109,6 +109,36 @@ function getMaxDomScrollHeight() {
|
|
|
109
109
|
}
|
|
110
110
|
return detectedMaxDomHeight;
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Observe an element's size, but run the callback on the next animation frame
|
|
114
|
+
* and coalesce bursts into a single call. This is what keeps the benign but
|
|
115
|
+
* noisy "ResizeObserver loop completed with undelivered notifications" warning
|
|
116
|
+
* out of the console: the browser emits it when an observer callback
|
|
117
|
+
* synchronously mutates layout in a way that would require another notification
|
|
118
|
+
* within the same delivery cycle - which our callbacks do (they bump reactive
|
|
119
|
+
* versions / remeasure, driving a re-layout of the observed element). Deferring
|
|
120
|
+
* the work to the next frame lets the current delivery finish cleanly, so the
|
|
121
|
+
* loop never spans a single cycle. This is especially visible when swapping the
|
|
122
|
+
* whole grid (e.g. switching demos), which remounts everything at once.
|
|
123
|
+
* Returns a disconnect function suitable for an $effect cleanup.
|
|
124
|
+
*/
|
|
125
|
+
function observeSizeRaf(el, cb) {
|
|
126
|
+
let frame = 0;
|
|
127
|
+
const observer = new ResizeObserver(() => {
|
|
128
|
+
if (frame)
|
|
129
|
+
return;
|
|
130
|
+
frame = requestAnimationFrame(() => {
|
|
131
|
+
frame = 0;
|
|
132
|
+
cb();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
observer.observe(el);
|
|
136
|
+
return () => {
|
|
137
|
+
if (frame)
|
|
138
|
+
cancelAnimationFrame(frame);
|
|
139
|
+
observer.disconnect();
|
|
140
|
+
};
|
|
141
|
+
}
|
|
112
142
|
export function createSvGridController(props) {
|
|
113
143
|
// Resolved capability gates. Capabilities are OFF by default - a bare
|
|
114
144
|
// grid is a plain read-only table, and each power feature is opted into
|
|
@@ -770,6 +800,17 @@ export function createSvGridController(props) {
|
|
|
770
800
|
const start = pageIndex * pageSize;
|
|
771
801
|
return rows.slice(start, start + pageSize);
|
|
772
802
|
});
|
|
803
|
+
// When a filter reduces the dataset, the stored pageIndex can point beyond
|
|
804
|
+
// the last valid page. Reset to page 0 so the grid never shows a blank body.
|
|
805
|
+
$effect(() => {
|
|
806
|
+
if (!paginationEnabled)
|
|
807
|
+
return;
|
|
808
|
+
const { pageIndex, pageSize } = paginationState;
|
|
809
|
+
const pageCount = Math.ceil(allRowsBeforePagination.length / pageSize);
|
|
810
|
+
if (pageCount > 0 && pageIndex >= pageCount) {
|
|
811
|
+
grid.setPagination({ pageIndex: 0, pageSize });
|
|
812
|
+
}
|
|
813
|
+
});
|
|
773
814
|
const rowSelectionState = $derived.by(() => {
|
|
774
815
|
gridStateVersion;
|
|
775
816
|
return grid.getState().rowSelection ?? {};
|
|
@@ -1045,15 +1086,46 @@ export function createSvGridController(props) {
|
|
|
1045
1086
|
return columnVirtualizer.getTotalSize();
|
|
1046
1087
|
});
|
|
1047
1088
|
const renderedColumnItems = $derived.by(() => {
|
|
1048
|
-
if (columnVirtualizationEnabled)
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1089
|
+
if (!columnVirtualizationEnabled) {
|
|
1090
|
+
let start = 0;
|
|
1091
|
+
return allColumns.map((column, index) => {
|
|
1092
|
+
const size = getColumnWidth(column.id);
|
|
1093
|
+
const item = { index, key: index, size, start, end: start + size };
|
|
1094
|
+
start += size;
|
|
1095
|
+
return item;
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
// Pinned columns are position:sticky, so they only stay pinned while their
|
|
1099
|
+
// cell is in the DOM. Plain column virtualization drops them once they leave
|
|
1100
|
+
// the scroll window, and the pinned column vanishes. Because allColumns is
|
|
1101
|
+
// ordered [pinnedLeft, unpinned, pinnedRight], we keep the rendered window
|
|
1102
|
+
// CONTIGUOUS from the pinned-left prefix (index 0) through the pinned-right
|
|
1103
|
+
// suffix (last index) whenever those exist. The pinned cells are then always
|
|
1104
|
+
// rendered - the existing single-spacer layout positions everything, so no
|
|
1105
|
+
// markup changes are needed. (Cost: with a pinned side, the columns between
|
|
1106
|
+
// that edge and the window are also rendered; negligible for typical grids,
|
|
1107
|
+
// and correctness beats shaving a few off-screen cells.)
|
|
1108
|
+
const window = virtualColumns;
|
|
1109
|
+
const hasLeft = columnPinning.left.length > 0;
|
|
1110
|
+
const hasRight = columnPinning.right.length > 0;
|
|
1111
|
+
if ((!hasLeft && !hasRight) || window.length === 0)
|
|
1112
|
+
return window;
|
|
1113
|
+
const firstIdx = window[0].index;
|
|
1114
|
+
const lastIdx = window[window.length - 1].index;
|
|
1115
|
+
const startIndex = hasLeft ? 0 : firstIdx;
|
|
1116
|
+
const endIndex = hasRight ? allColumns.length - 1 : lastIdx;
|
|
1117
|
+
if (startIndex === firstIdx && endIndex === lastIdx)
|
|
1118
|
+
return window;
|
|
1119
|
+
const items = [];
|
|
1120
|
+
let offset = 0;
|
|
1121
|
+
for (let i = 0; i < startIndex; i += 1)
|
|
1122
|
+
offset += getColumnWidth(allColumns[i].id);
|
|
1123
|
+
for (let i = startIndex; i <= endIndex; i += 1) {
|
|
1124
|
+
const size = getColumnWidth(allColumns[i].id);
|
|
1125
|
+
items.push({ index: i, key: i, size, start: offset, end: offset + size });
|
|
1126
|
+
offset += size;
|
|
1127
|
+
}
|
|
1128
|
+
return items;
|
|
1057
1129
|
});
|
|
1058
1130
|
const renderedColumns = $derived.by(() => renderedColumnItems
|
|
1059
1131
|
.map((item) => ({ item, column: allColumns[item.index] }))
|
|
@@ -1137,11 +1209,9 @@ export function createSvGridController(props) {
|
|
|
1137
1209
|
if (!theadEl)
|
|
1138
1210
|
return;
|
|
1139
1211
|
headerHeight = theadEl.offsetHeight;
|
|
1140
|
-
|
|
1212
|
+
return observeSizeRaf(theadEl, () => {
|
|
1141
1213
|
headerHeight = theadEl?.offsetHeight ?? 0;
|
|
1142
1214
|
});
|
|
1143
|
-
observer.observe(theadEl);
|
|
1144
|
-
return () => observer.disconnect();
|
|
1145
1215
|
});
|
|
1146
1216
|
// Bump scrollVersion when the table's layout size changes so scrollbar
|
|
1147
1217
|
// visibility (and the thumb math that depends on scroll metrics) updates
|
|
@@ -1149,11 +1219,9 @@ export function createSvGridController(props) {
|
|
|
1149
1219
|
$effect(() => {
|
|
1150
1220
|
if (!gridRootEl)
|
|
1151
1221
|
return;
|
|
1152
|
-
|
|
1222
|
+
return observeSizeRaf(gridRootEl, () => {
|
|
1153
1223
|
scrollVersion += 1;
|
|
1154
1224
|
});
|
|
1155
|
-
observer.observe(gridRootEl);
|
|
1156
|
-
return () => observer.disconnect();
|
|
1157
1225
|
});
|
|
1158
1226
|
$effect(() => {
|
|
1159
1227
|
if (!allRows.length || !allColumns.length)
|
|
@@ -1270,13 +1338,11 @@ export function createSvGridController(props) {
|
|
|
1270
1338
|
$effect(() => {
|
|
1271
1339
|
if (!scrollContainer)
|
|
1272
1340
|
return;
|
|
1273
|
-
|
|
1341
|
+
return observeSizeRaf(scrollContainer, () => {
|
|
1274
1342
|
viewportVersion += 1;
|
|
1275
1343
|
if (!hasMeasured)
|
|
1276
1344
|
hasMeasured = true;
|
|
1277
1345
|
});
|
|
1278
|
-
observer.observe(scrollContainer);
|
|
1279
|
-
return () => observer.disconnect();
|
|
1280
1346
|
});
|
|
1281
1347
|
$effect(() => {
|
|
1282
1348
|
// Reading columnWidths here registers it as a reactive dependency so
|
package/dist/a11y.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export declare function getGridRowA11yProps(rowIndex?: number): {
|
|
|
29
29
|
readonly role: "row";
|
|
30
30
|
};
|
|
31
31
|
export declare function getGridCellA11yProps(input?: GridCellA11yInput): {
|
|
32
|
-
readonly 'aria-selected'
|
|
32
|
+
readonly 'aria-selected': boolean;
|
|
33
33
|
readonly 'aria-rowindex'?: number | undefined;
|
|
34
34
|
readonly 'aria-colindex'?: number | undefined;
|
|
35
35
|
readonly id?: string | undefined;
|
package/dist/a11y.js
CHANGED
|
@@ -29,7 +29,7 @@ export function getGridCellA11yProps(input = {}) {
|
|
|
29
29
|
...(id ? { id } : {}),
|
|
30
30
|
...(colIndex !== undefined ? { 'aria-colindex': colIndex } : {}),
|
|
31
31
|
...(rowIndex !== undefined ? { 'aria-rowindex': rowIndex } : {}),
|
|
32
|
-
|
|
32
|
+
'aria-selected': selected,
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
export function getGridCellDomId(baseId, rowIndex, colIndex) {
|