@opencorestack/opengridx 3.5.1 → 3.7.0
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 +53 -0
- package/README.md +2 -0
- package/dist/ai.cjs +4 -2
- package/dist/ai.cjs.map +1 -1
- package/dist/ai.d.ts +2 -2
- package/dist/ai.es.js +4 -2
- package/dist/ai.es.js.map +1 -1
- package/dist/index.d.ts +62 -0
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +9643 -9024
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +16 -16
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +17 -3
- package/docs/README.md +2 -0
- package/docs/architecture/datagrid-orchestration.md +46 -29
- package/docs/architecture/grid-row-meta.md +1 -1
- package/docs/customization/slots-api.md +1 -1
- package/docs/customization/theming.md +43 -0
- package/docs/features/ai-toolkit.md +2 -2
- package/docs/features/export-guide.md +2 -0
- package/docs/features/header-filters.md +34 -0
- package/docs/features/keyboard-navigation.md +2 -0
- package/docs/features/nextjs.md +241 -0
- package/docs/features/pdf-export.md +2 -0
- package/docs/features/pinning.md +2 -0
- package/docs/features/rtl.md +58 -0
- package/docs/features/virtualization.md +16 -2
- package/docs/performance.md +89 -119
- package/docs/roadmap.md +4 -2
- package/lib/ai/promptHandler.ts +12 -8
- package/lib/ai/validate.ts +5 -2
- package/lib/components/AiAssistant/GridAiAssistantPanel.css +4 -2
- package/lib/components/Cell/Cell.css +31 -9
- package/lib/components/Cell/Cell.tsx +2 -2
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +4 -4
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +3 -3
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +18 -2
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +3 -1
- package/lib/components/DataGrid/DataGrid.css +19 -13
- package/lib/components/DataGrid/DataGrid.tsx +163 -670
- package/lib/components/DataGrid/GridAggregationFooter.tsx +3 -3
- package/lib/components/DataGrid/GridListView.tsx +3 -1
- package/lib/components/DataGrid/GridRoot.tsx +239 -0
- package/lib/components/DataGrid/GridViewport.tsx +314 -0
- package/lib/components/FilterPanel/FilterPanel.css +9 -8
- package/lib/components/Header/ColumnMenu.css +5 -4
- package/lib/components/Header/ColumnMenu.tsx +14 -6
- package/lib/components/Header/Header.css +23 -14
- package/lib/components/Header/Header.tsx +16 -9
- package/lib/components/Header/headerColumnStyle.ts +3 -2
- package/lib/components/HeaderFilter/HeaderFilter.css +9 -3
- package/lib/components/HeaderFilter/HeaderFilterCell.tsx +21 -18
- package/lib/components/HeaderFilter/HeaderFilterOperatorMenu.tsx +5 -4
- package/lib/components/HeaderFilter/HeaderFilterRow.tsx +9 -3
- package/lib/components/ListView/ListViewRow.tsx +1 -1
- package/lib/components/Pagination/Pagination.css +5 -1
- package/lib/components/Pagination/Pagination.tsx +4 -4
- package/lib/components/Row/Row.css +2 -2
- package/lib/components/Row/Row.tsx +3 -3
- package/lib/components/SkeletonRow/SkeletonRow.tsx +2 -2
- package/lib/components/Toolbar/GridToolbar.css +8 -7
- package/lib/components/Toolbar/GridToolbar.tsx +8 -28
- package/lib/components/Toolbar/PivotPanel.css +3 -3
- package/lib/components/Toolbar/PivotPanel.tsx +4 -7
- package/lib/components/ui/ExpandIcon.css +13 -0
- package/lib/components/ui/ExpandIcon.tsx +2 -4
- package/lib/hooks/core/useGridCellSelection.ts +20 -5
- package/lib/hooks/core/useGridColumns.tsx +2 -2
- package/lib/hooks/core/useGridDevWarnings.ts +3 -1
- package/lib/hooks/core/useGridEditPipeline.ts +55 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +7 -4
- package/lib/hooks/core/useGridRangeEditing.ts +129 -0
- package/lib/hooks/core/useGridRenderWindow.ts +66 -0
- package/lib/hooks/core/useGridScrollSync.ts +28 -5
- package/lib/hooks/core/useGridScrollViewport.ts +42 -0
- package/lib/hooks/core/useGridSelectionAndStateApi.ts +61 -0
- package/lib/hooks/core/useGridToolbarStack.ts +49 -0
- package/lib/hooks/core/useGridViewApis.ts +46 -0
- package/lib/hooks/core/useLayout.ts +13 -6
- package/lib/hooks/useRowGrouping.ts +9 -9
- package/lib/styles/base/variables.css +12 -0
- package/lib/theme/DataGridThemeProvider.tsx +15 -0
- package/lib/theme/__baseline__/default-theme.darwin.chromium.json +1503 -0
- package/lib/theme/__baseline__/default-theme.darwin.firefox.json +1503 -0
- package/lib/theme/__baseline__/default-theme.darwin.webkit.json +1503 -0
- package/lib/theme/types.ts +31 -0
- package/lib/types/ai.ts +109 -0
- package/lib/types/api.ts +169 -0
- package/lib/types/columns.ts +341 -0
- package/lib/types/dataSource.ts +40 -0
- package/lib/types/editing.ts +77 -0
- package/lib/types/export.ts +164 -0
- package/lib/types/filtering.ts +52 -0
- package/lib/types/grouping.ts +27 -0
- package/lib/types/index.ts +18 -1672
- package/lib/types/locale.ts +51 -0
- package/lib/types/props.ts +405 -0
- package/lib/types/rows.ts +132 -0
- package/lib/types/selection.ts +66 -0
- package/lib/types/slots.ts +56 -0
- package/lib/types/sorting.ts +25 -0
- package/lib/types/state.ts +35 -0
- package/lib/utils/aggregation/index.ts +56 -1
- package/lib/utils/direction.ts +52 -0
- package/lib/utils/export/exportToExcelAdvanced.ts +9 -2
- package/lib/utils/export/exportToPdf.ts +2 -1
- package/lib/utils/filtering/index.ts +58 -6
- package/lib/utils/headerFilterLocale.ts +37 -0
- package/lib/utils/scroll/index.ts +5 -3
- package/lib/utils/sorting/index.ts +141 -26
- package/lib/utils/values.ts +10 -6
- package/llms.txt +4 -2
- package/package.json +4 -2
|
@@ -72,8 +72,8 @@ export const SkeletonRow: React.FC<SkeletonRowProps> = ({
|
|
|
72
72
|
width,
|
|
73
73
|
minWidth: col.minWidth,
|
|
74
74
|
maxWidth: col.maxWidth,
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
insetInlineStart: col.left,
|
|
76
|
+
insetInlineEnd: col.right,
|
|
77
77
|
position: col.isSpacer ? 'relative' : (col.pinned ? 'sticky' : 'relative'),
|
|
78
78
|
zIndex: col.zIndex
|
|
79
79
|
}}
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
z-index: 9999;
|
|
81
81
|
overflow: hidden;
|
|
82
82
|
animation: ogx-panel-in 0.15s ease-out;
|
|
83
|
+
font-family: var(--ogx-overlay-font-family, inherit);
|
|
83
84
|
}
|
|
84
85
|
@keyframes ogx-panel-in {
|
|
85
86
|
from { opacity: 0; transform: translateY(-6px) scale(0.98); }
|
|
@@ -97,7 +98,7 @@
|
|
|
97
98
|
display: flex;
|
|
98
99
|
align-items: center;
|
|
99
100
|
gap: var(--ogx-spacing-xs);
|
|
100
|
-
font-family: var(--ogx-font-family);
|
|
101
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
101
102
|
font-size: var(--ogx-font-size-sm);
|
|
102
103
|
font-weight: 600;
|
|
103
104
|
color: var(--ogx-grid-header-text);
|
|
@@ -108,7 +109,7 @@
|
|
|
108
109
|
border-radius: var(--ogx-border-radius-sm);
|
|
109
110
|
background: transparent;
|
|
110
111
|
color: var(--ogx-toolbar-btn-danger-text, var(--ogx-color-error, #ef4444));
|
|
111
|
-
font-family: var(--ogx-font-family);
|
|
112
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
112
113
|
font-size: var(--ogx-font-size-xs);
|
|
113
114
|
font-weight: 500;
|
|
114
115
|
cursor: pointer;
|
|
@@ -124,7 +125,7 @@
|
|
|
124
125
|
border-radius: var(--ogx-border-radius-sm);
|
|
125
126
|
background: transparent;
|
|
126
127
|
color: var(--ogx-grid-header-text);
|
|
127
|
-
font-family: var(--ogx-font-family);
|
|
128
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
128
129
|
font-size: var(--ogx-font-size-xs);
|
|
129
130
|
font-weight: 500;
|
|
130
131
|
cursor: pointer;
|
|
@@ -142,7 +143,7 @@
|
|
|
142
143
|
}
|
|
143
144
|
.ogx-toolbar__empty {
|
|
144
145
|
padding: var(--ogx-spacing-md) var(--ogx-spacing-md);
|
|
145
|
-
font-family: var(--ogx-font-family);
|
|
146
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
146
147
|
font-size: var(--ogx-font-size-sm);
|
|
147
148
|
color: var(--ogx-grid-header-text);
|
|
148
149
|
line-height: 1.5;
|
|
@@ -171,9 +172,9 @@
|
|
|
171
172
|
}
|
|
172
173
|
.ogx-toolbar__agg-label {
|
|
173
174
|
flex: 0 0 100px;
|
|
174
|
-
font-family: var(--ogx-font-family);
|
|
175
|
-
font-size: var(--ogx-font-size-xs);
|
|
176
|
-
font-weight: 500;
|
|
175
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
176
|
+
font-size: var(--ogx-overlay-font-size, var(--ogx-font-size-xs));
|
|
177
|
+
font-weight: var(--ogx-overlay-font-weight, 500);
|
|
177
178
|
color: var(--ogx-grid-row-text);
|
|
178
179
|
overflow: hidden;
|
|
179
180
|
text-overflow: ellipsis;
|
|
@@ -4,6 +4,7 @@ import type { GridColDef, GridAggregationModel, GridPivotModel, GridFilterModel
|
|
|
4
4
|
import { AGGREGATION_FUNCTIONS } from '../../utils/aggregation';
|
|
5
5
|
import type { BuiltInAggFn } from '../../utils/aggregation';
|
|
6
6
|
import { getViewportWidth } from '../../utils/viewport';
|
|
7
|
+
import { getPanelPosition, type GridPanelPosition } from '../../utils/direction';
|
|
7
8
|
import { GridToolbarHostContext } from '../../hooks/core/gridToolbarHostContext';
|
|
8
9
|
import { PivotPanel, PivotIcon } from './PivotPanel';
|
|
9
10
|
import { GlobalSearch } from './GlobalSearch';
|
|
@@ -149,7 +150,7 @@ function FilterIcon() {
|
|
|
149
150
|
);
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
|
|
153
|
+
type PanelPosition = GridPanelPosition;
|
|
153
154
|
|
|
154
155
|
function AggregationPanel({
|
|
155
156
|
anchorRef,
|
|
@@ -176,14 +177,7 @@ function AggregationPanel({
|
|
|
176
177
|
setPortalContainer(anchorRef.current?.closest('.ogx-theme-provider') ?? document.body);
|
|
177
178
|
}, [anchorRef]);
|
|
178
179
|
|
|
179
|
-
const computePos = useCallback((): PanelPosition =>
|
|
180
|
-
if (!anchorRef.current) return { top: 0, right: 0 };
|
|
181
|
-
const rect = anchorRef.current.getBoundingClientRect();
|
|
182
|
-
return {
|
|
183
|
-
top: rect.bottom + 6,
|
|
184
|
-
right: getViewportWidth() - rect.right,
|
|
185
|
-
};
|
|
186
|
-
}, [anchorRef]);
|
|
180
|
+
const computePos = useCallback((): PanelPosition => getPanelPosition(anchorRef.current, getViewportWidth()), [anchorRef]);
|
|
187
181
|
|
|
188
182
|
useEffect(() => {
|
|
189
183
|
setPos(computePos());
|
|
@@ -221,7 +215,7 @@ function AggregationPanel({
|
|
|
221
215
|
className="ogx-toolbar__panel"
|
|
222
216
|
role="dialog"
|
|
223
217
|
aria-label="Summaries configuration"
|
|
224
|
-
style={{ top: pos.top, right: pos.right, width: 400, maxWidth: 'calc(100vw - 24px)' }}
|
|
218
|
+
style={{ top: pos.top, right: pos.right, left: pos.left, width: 400, maxWidth: 'calc(100vw - 24px)' }}
|
|
225
219
|
>
|
|
226
220
|
<div className="ogx-toolbar__panel-header">
|
|
227
221
|
<span className="ogx-toolbar__panel-title">
|
|
@@ -309,14 +303,7 @@ function ColumnsPanelWrapper({
|
|
|
309
303
|
setPortalContainer(anchorRef.current?.closest('.ogx-theme-provider') ?? document.body);
|
|
310
304
|
}, [anchorRef]);
|
|
311
305
|
|
|
312
|
-
const computePos = useCallback((): PanelPosition =>
|
|
313
|
-
if (!anchorRef.current) return { top: 0, right: 0 };
|
|
314
|
-
const rect = anchorRef.current.getBoundingClientRect();
|
|
315
|
-
return {
|
|
316
|
-
top: rect.bottom + 6,
|
|
317
|
-
right: getViewportWidth() - rect.right,
|
|
318
|
-
};
|
|
319
|
-
}, [anchorRef]);
|
|
306
|
+
const computePos = useCallback((): PanelPosition => getPanelPosition(anchorRef.current, getViewportWidth()), [anchorRef]);
|
|
320
307
|
|
|
321
308
|
useEffect(() => {
|
|
322
309
|
setPos(computePos());
|
|
@@ -354,7 +341,7 @@ function ColumnsPanelWrapper({
|
|
|
354
341
|
className="ogx-toolbar__panel"
|
|
355
342
|
role="dialog"
|
|
356
343
|
aria-label="Column visibility"
|
|
357
|
-
style={{ top: pos.top, right: pos.right, width: 280, padding: 0 }}
|
|
344
|
+
style={{ top: pos.top, right: pos.right, left: pos.left, width: 280, padding: 0 }}
|
|
358
345
|
>
|
|
359
346
|
<ColumnVisibilityPanel
|
|
360
347
|
columns={columns}
|
|
@@ -398,14 +385,7 @@ function FilterPanelWrapper({
|
|
|
398
385
|
setPortalContainer(anchorRef.current?.closest('.ogx-theme-provider') ?? document.body);
|
|
399
386
|
}, [anchorRef]);
|
|
400
387
|
|
|
401
|
-
const computePos = useCallback((): PanelPosition =>
|
|
402
|
-
if (!anchorRef.current) return { top: 0, right: 0 };
|
|
403
|
-
const rect = anchorRef.current.getBoundingClientRect();
|
|
404
|
-
return {
|
|
405
|
-
top: rect.bottom + 6,
|
|
406
|
-
right: getViewportWidth() - rect.right,
|
|
407
|
-
};
|
|
408
|
-
}, [anchorRef]);
|
|
388
|
+
const computePos = useCallback((): PanelPosition => getPanelPosition(anchorRef.current, getViewportWidth()), [anchorRef]);
|
|
409
389
|
|
|
410
390
|
useEffect(() => {
|
|
411
391
|
setPos(computePos());
|
|
@@ -442,7 +422,7 @@ function FilterPanelWrapper({
|
|
|
442
422
|
className="ogx-toolbar__panel ogx-toolbar__panel--filter"
|
|
443
423
|
role="dialog"
|
|
444
424
|
aria-label="Advanced filters"
|
|
445
|
-
style={{ top: pos.top, right: pos.right, width: 540, maxWidth: 'calc(100vw - 24px)' }}
|
|
425
|
+
style={{ top: pos.top, right: pos.right, left: pos.left, width: 540, maxWidth: 'calc(100vw - 24px)' }}
|
|
446
426
|
>
|
|
447
427
|
<div className="ogx-toolbar__panel-header">
|
|
448
428
|
<span className="ogx-toolbar__panel-title">
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
z-index: 9999;
|
|
10
10
|
overflow: hidden;
|
|
11
11
|
animation: ogx-panel-in 0.15s ease-out;
|
|
12
|
-
font-family: var(--ogx-font-family);
|
|
12
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
13
13
|
}
|
|
14
14
|
@keyframes ogx-panel-in {
|
|
15
15
|
from { opacity: 0; transform: translateY(-6px) scale(0.98); }
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
border-radius: var(--ogx-border-radius-sm);
|
|
38
38
|
background: transparent;
|
|
39
39
|
color: var(--ogx-color-error, #ef4444);
|
|
40
|
-
font-family: var(--ogx-font-family);
|
|
40
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
41
41
|
font-size: var(--ogx-font-size-xs);
|
|
42
42
|
font-weight: 500;
|
|
43
43
|
cursor: pointer;
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
border-radius: 999px;
|
|
164
164
|
background: var(--ogx-grid-header-background);
|
|
165
165
|
color: var(--ogx-grid-row-text);
|
|
166
|
-
font-family: var(--ogx-font-family);
|
|
166
|
+
font-family: var(--ogx-overlay-font-family, var(--ogx-font-family));
|
|
167
167
|
font-size: 12px;
|
|
168
168
|
font-weight: 500;
|
|
169
169
|
cursor: pointer;
|
|
@@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
|
|
|
3
3
|
import type { GridColDef } from '../../types';
|
|
4
4
|
import type { GridPivotModel, GridPivotAggFn, GridPivotValueField } from '../../types';
|
|
5
5
|
import { getViewportWidth } from '../../utils/viewport';
|
|
6
|
+
import { getPanelPosition, type GridPanelPosition } from '../../utils/direction';
|
|
6
7
|
|
|
7
8
|
const AGG_FNS: GridPivotAggFn[] = ['sum', 'avg', 'count', 'min', 'max'];
|
|
8
9
|
|
|
@@ -31,18 +32,14 @@ export interface PivotPanelProps {
|
|
|
31
32
|
|
|
32
33
|
export function PivotPanel({ anchorRef, columns, model, onChange, onClose }: PivotPanelProps) {
|
|
33
34
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
34
|
-
const [pos, setPos] = useState({ top: 0, right: 0 });
|
|
35
|
+
const [pos, setPos] = useState<GridPanelPosition>({ top: 0, right: 0 });
|
|
35
36
|
const [portalContainer, setPortalContainer] = useState<Element | null>(null);
|
|
36
37
|
|
|
37
38
|
useLayoutEffect(() => {
|
|
38
39
|
setPortalContainer(anchorRef.current?.closest('.ogx-theme-provider') ?? document.body);
|
|
39
40
|
}, [anchorRef]);
|
|
40
41
|
|
|
41
|
-
const computePos = useCallback(() =>
|
|
42
|
-
if (!anchorRef.current) return { top: 0, right: 0 };
|
|
43
|
-
const rect = anchorRef.current.getBoundingClientRect();
|
|
44
|
-
return { top: rect.bottom + 6, right: getViewportWidth() - rect.right };
|
|
45
|
-
}, [anchorRef]);
|
|
42
|
+
const computePos = useCallback(() => getPanelPosition(anchorRef.current, getViewportWidth()), [anchorRef]);
|
|
46
43
|
|
|
47
44
|
useEffect(() => {
|
|
48
45
|
setPos(computePos());
|
|
@@ -132,7 +129,7 @@ export function PivotPanel({ anchorRef, columns, model, onChange, onClose }: Piv
|
|
|
132
129
|
className="ogx-pivot-panel"
|
|
133
130
|
role="dialog"
|
|
134
131
|
aria-label="Pivot configuration"
|
|
135
|
-
style={{ top: pos.top, right: pos.right }}
|
|
132
|
+
style={{ top: pos.top, right: pos.right, left: pos.left }}
|
|
136
133
|
>
|
|
137
134
|
{ }
|
|
138
135
|
<div className="ogx-pivot-panel__header">
|
|
@@ -27,3 +27,16 @@
|
|
|
27
27
|
display: block;
|
|
28
28
|
transition: transform 0.2s ease;
|
|
29
29
|
}
|
|
30
|
+
/* The chevron points towards the inline end (right, or left in a right-to-left grid) and down when expanded. */
|
|
31
|
+
.ogx-expand-icon__chevron {
|
|
32
|
+
transform: rotate(0deg);
|
|
33
|
+
}
|
|
34
|
+
.ogx-expand-icon--expanded .ogx-expand-icon__chevron {
|
|
35
|
+
transform: rotate(90deg);
|
|
36
|
+
}
|
|
37
|
+
.ogx-expand-icon__chevron:dir(rtl) {
|
|
38
|
+
transform: scaleX(-1) rotate(0deg);
|
|
39
|
+
}
|
|
40
|
+
.ogx-expand-icon--expanded .ogx-expand-icon__chevron:dir(rtl) {
|
|
41
|
+
transform: scaleX(-1) rotate(90deg);
|
|
42
|
+
}
|
|
@@ -59,10 +59,8 @@ export function ExpandIcon({ isExpanded, onClick, variant = 'chevron', tabIndex
|
|
|
59
59
|
viewBox="0 0 16 16"
|
|
60
60
|
fill="none"
|
|
61
61
|
xmlns="http://www.w3.org/2000/svg"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
transition: 'transform 0.2s ease'
|
|
65
|
-
}}
|
|
62
|
+
className="ogx-expand-icon__chevron"
|
|
63
|
+
aria-hidden="true"
|
|
66
64
|
>
|
|
67
65
|
<path
|
|
68
66
|
d="M6 4L10 8L6 12"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import type { RefObject } from 'react';
|
|
3
3
|
import { scrollColumnIntoView, scrollRowIntoView } from '../../utils/scroll';
|
|
4
|
+
import { isRtl } from '../../utils/direction';
|
|
4
5
|
import { isSyntheticRowId } from '../../utils/syntheticRows';
|
|
5
6
|
import { isTextEntryElement } from '../../utils/focus';
|
|
6
7
|
import type { FocusedCell } from '../../utils/focus';
|
|
@@ -132,6 +133,11 @@ interface DragState {
|
|
|
132
133
|
y: number;
|
|
133
134
|
frame: number;
|
|
134
135
|
moved: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Whether the viewport lays out right to left, read once per drag: `getComputedStyle` every frame
|
|
138
|
+
* forces a style recalculation, which slowed WebKit's auto-scroll enough to delay the release.
|
|
139
|
+
*/
|
|
140
|
+
rtl?: boolean;
|
|
135
141
|
/** Ends the drag; `cancelled` unless the button was released normally (tracked drags: Escape cancels). */
|
|
136
142
|
stop: (cancelled?: boolean, altKey?: boolean) => void;
|
|
137
143
|
/** A tracked drag (fill handle): told the cell under the pointer each frame instead of moving the range. */
|
|
@@ -448,11 +454,17 @@ export function useGridCellSelection<R extends GridRowModel>(params: UseGridCell
|
|
|
448
454
|
const bodyTop = stickyTop ? stickyTop.getBoundingClientRect().bottom : box.top;
|
|
449
455
|
const bodyBottom = Math.min(box.top + height, stickyBottom ? stickyBottom.getBoundingClientRect().top : box.top + height);
|
|
450
456
|
const headerBottom = headerWrap ? headerWrap.getBoundingClientRect().bottom : bodyTop;
|
|
451
|
-
|
|
452
|
-
|
|
457
|
+
// Left-pinned columns (and pinned system columns) sit at the inline start: on the right in a
|
|
458
|
+
// right-to-left grid, whose vertical scrollbar is on the left.
|
|
459
|
+
if (drag.rtl === undefined) drag.rtl = isRtl(viewport);
|
|
460
|
+
const rtl = drag.rtl;
|
|
461
|
+
const contentLeft = rtl ? box.right - width : box.left;
|
|
462
|
+
const startPinnedWidth = layout.pinnedSystemColumnsWidth + layout.leftWidth;
|
|
463
|
+
const bodyLeft = contentLeft + (rtl ? layout.rightWidth : startPinnedWidth);
|
|
464
|
+
const bodyRight = contentLeft + width - (rtl ? startPinnedWidth : layout.rightWidth);
|
|
453
465
|
|
|
454
466
|
// The cell under the pointer; outside the viewport (or over the header) the nearest body cell.
|
|
455
|
-
const x = clamp(drag.x,
|
|
467
|
+
const x = clamp(drag.x, contentLeft + 1, contentLeft + width - 2);
|
|
456
468
|
let y = drag.y;
|
|
457
469
|
if (y < box.top || y > box.top + height || y < headerBottom) y = clamp(y, bodyTop + 1, Math.max(bodyTop + 1, bodyBottom - 2));
|
|
458
470
|
// During fast auto-scroll the rows under the pointer may not be rendered yet (virtualization
|
|
@@ -476,7 +488,7 @@ export function useGridCellSelection<R extends GridRowModel>(params: UseGridCell
|
|
|
476
488
|
if (drag.onTrack) drag.onTrack(drag.head, drag.x, drag.y);
|
|
477
489
|
|
|
478
490
|
if (!allowScroll) return;
|
|
479
|
-
const outside = drag.y < bodyTop || drag.y > bodyBottom || drag.x <
|
|
491
|
+
const outside = drag.y < bodyTop || drag.y > bodyBottom || drag.x < contentLeft || drag.x > contentLeft + width;
|
|
480
492
|
if (!drag.moved && !outside) return;
|
|
481
493
|
let dy = 0;
|
|
482
494
|
let dx = 0;
|
|
@@ -485,7 +497,10 @@ export function useGridCellSelection<R extends GridRowModel>(params: UseGridCell
|
|
|
485
497
|
if (drag.x < bodyLeft + AUTO_SCROLL_EDGE) dx = -autoScrollStep(bodyLeft + AUTO_SCROLL_EDGE - drag.x);
|
|
486
498
|
else if (drag.x > bodyRight - AUTO_SCROLL_EDGE) dx = autoScrollStep(drag.x - (bodyRight - AUTO_SCROLL_EDGE));
|
|
487
499
|
const canScrollY = (dy < 0 && viewport.scrollTop > 0) || (dy > 0 && viewport.scrollTop + height < viewport.scrollHeight - 1);
|
|
488
|
-
|
|
500
|
+
// scrollLeft runs from 0 to the maximum, or from minus the maximum to 0 right to left.
|
|
501
|
+
const maxScroll = viewport.scrollWidth - width;
|
|
502
|
+
const minLeft = rtl ? -maxScroll : 0;
|
|
503
|
+
const canScrollX = (dx < 0 && viewport.scrollLeft > minLeft) || (dx > 0 && viewport.scrollLeft < minLeft + maxScroll - 1);
|
|
489
504
|
if (!canScrollY && !canScrollX) return;
|
|
490
505
|
if (canScrollY) viewport.scrollTop += dy;
|
|
491
506
|
if (canScrollX) viewport.scrollLeft += dx;
|
|
@@ -282,8 +282,8 @@ export function useGridColumns<R extends GridRowModel>(
|
|
|
282
282
|
const content = custom.useDefault ? defaultHierarchyContent(cellParams, isRowGrouping, isTreeData) : custom.content;
|
|
283
283
|
|
|
284
284
|
return (
|
|
285
|
-
<div style={{ display: 'flex', alignItems: 'center',
|
|
286
|
-
<div style={{
|
|
285
|
+
<div style={{ display: 'flex', alignItems: 'center', paddingInlineStart: depth * 24, width: '100%', height: '100%' }}>
|
|
286
|
+
<div style={{ marginInlineEnd: 4, width: 24, height: 24, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: hasChildren ? 'pointer' : 'default', flexShrink: 0 }}>
|
|
287
287
|
{hasChildren ? (
|
|
288
288
|
<div
|
|
289
289
|
onClick={(e) => { e.stopPropagation(); e.preventDefault(); activeHierarchyHandlers?.toggleExpansion(getRowId(cellParams.row)); }}
|
|
@@ -87,7 +87,9 @@ export function useGridDevWarnings(params: UseGridDevWarningsParams): void {
|
|
|
87
87
|
console.warn(
|
|
88
88
|
`[OpenGridX] The grid content is ${Math.round(scrollHeight)}px tall, more than this browser lays out ` +
|
|
89
89
|
'(about 17.9M px in Firefox, 33.5M px in Chrome and Safari). ' + reach +
|
|
90
|
-
'
|
|
90
|
+
'Load the rows on demand with a `dataSource` (server-side pages or infinite scroll, ' +
|
|
91
|
+
'docs/features/data-source.md), use `pagination`, or a smaller rowHeight (density="compact"). ' +
|
|
92
|
+
'See docs/features/virtualization.md#the-browser-height-limit.'
|
|
91
93
|
);
|
|
92
94
|
}, [scrollHeight, maxContentHeight, reachableRowCount, unpinnedRowCount]);
|
|
93
95
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { GridColDef, GridRowId, GridRowModel } from '../../types';
|
|
2
|
+
import { useGridEditCommitChannel } from './useGridUndoRedo';
|
|
3
|
+
import { useGridBatchEdit, type UseGridBatchEditParams } from '../features/useGridBatchEdit';
|
|
4
|
+
import { useGridEditing } from '../features/useGridEditing';
|
|
5
|
+
|
|
6
|
+
export interface UseGridEditPipelineParams<R extends GridRowModel> {
|
|
7
|
+
/** The row store's lookup (rows stored since the last render are read through `batchEdit.getRow`). */
|
|
8
|
+
rowsLookup: ReadonlyMap<GridRowId, R>;
|
|
9
|
+
/** The stored rows, in store order. */
|
|
10
|
+
rows: R[];
|
|
11
|
+
getRowId: (row: R) => GridRowId;
|
|
12
|
+
columns: GridColDef<R>[];
|
|
13
|
+
processRowUpdate: UseGridBatchEditParams<R>['processRowUpdate'];
|
|
14
|
+
onProcessRowUpdateError: UseGridBatchEditParams<R>['onProcessRowUpdateError'];
|
|
15
|
+
replaceRows: UseGridBatchEditParams<R>['replaceRows'];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Steps 12a–13 of `DataGrid` (docs/architecture/datagrid-orchestration.md), in their call order: the edit
|
|
20
|
+
* commit channel, the batch edit and single-cell editing. Single edits store through `batchEdit.storeRow`
|
|
21
|
+
* and report to the channel; the undo/redo history (`useGridRangeEditing`, later) listens on it.
|
|
22
|
+
*/
|
|
23
|
+
export function useGridEditPipeline<R extends GridRowModel>(params: UseGridEditPipelineParams<R>) {
|
|
24
|
+
const { rowsLookup, rows, getRowId, columns, processRowUpdate, onProcessRowUpdateError, replaceRows } = params;
|
|
25
|
+
|
|
26
|
+
// Commits (single edits and batch edits) reach the undo/redo history created further down.
|
|
27
|
+
const editCommitChannel = useGridEditCommitChannel();
|
|
28
|
+
// Batch edits (paste, range clear, undo, redo): one processRowUpdate per row, one store update.
|
|
29
|
+
const batchEdit = useGridBatchEdit<R>({
|
|
30
|
+
rowsLookup,
|
|
31
|
+
columns,
|
|
32
|
+
processRowUpdate,
|
|
33
|
+
onProcessRowUpdateError,
|
|
34
|
+
replaceRows,
|
|
35
|
+
onCommitted: editCommitChannel.emit,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const editingHandlers = useGridEditing({
|
|
39
|
+
rows,
|
|
40
|
+
getRowId,
|
|
41
|
+
columns,
|
|
42
|
+
processRowUpdate,
|
|
43
|
+
onProcessRowUpdateError,
|
|
44
|
+
onRowChange: (updatedRow, rowId) => {
|
|
45
|
+
// Replaces the edited row in the *current* store, under the edited row's id: this runs
|
|
46
|
+
// after an awaited processRowUpdate, by which time the rows prop (or a dataSource
|
|
47
|
+
// fetch) may have replaced the rows this render saw. The returned row is stored as is
|
|
48
|
+
// (the grid never writes an id onto it), even if it does not carry its key itself.
|
|
49
|
+
batchEdit.storeRow(rowId, updatedRow);
|
|
50
|
+
},
|
|
51
|
+
onCommitted: (changes) => editCommitChannel.emit(changes, 'edit'),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return { editCommitChannel, batchEdit, editingHandlers };
|
|
55
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useState, useCallback, useMemo, useRef, useLayoutEffect } from 'react';
|
|
2
|
+
import { getScrollStart, isRtl, logicalArrowKey, setScrollStart } from '../../utils/direction';
|
|
2
3
|
import { scrollRowIntoView } from '../../utils/scroll';
|
|
3
4
|
import { resolveCellEditable } from '../../utils/editing';
|
|
4
5
|
import { getCellValue } from '../../utils/values';
|
|
@@ -256,12 +257,13 @@ export function useGridKeyboardNavigation<R extends GridRowModel>(
|
|
|
256
257
|
const isPinned = field === REORDER_FIELD
|
|
257
258
|
|| (field === EXPAND_FIELD && pinExpandColumn)
|
|
258
259
|
|| (field === CHECKBOX_FIELD && pinCheckboxColumn);
|
|
259
|
-
if (!isPinned && el
|
|
260
|
+
if (!isPinned && getScrollStart(el) > 0) setScrollStart(el, 0);
|
|
260
261
|
return;
|
|
261
262
|
}
|
|
262
263
|
if (!columnMetrics) return;
|
|
263
264
|
|
|
264
|
-
const { clientWidth
|
|
265
|
+
const { clientWidth } = el;
|
|
266
|
+
const scrollLeft = getScrollStart(el);
|
|
265
267
|
const { leftPinnedWidth, rightPinnedWidth, unpinnedAccWidths, unpinnedCols, totalSpecialsWidth, pinnedSpecialsWidth } = columnMetrics;
|
|
266
268
|
const unpinnedIndex = unpinnedCols.findIndex(c => c.field === field);
|
|
267
269
|
if (unpinnedIndex === -1) return;
|
|
@@ -277,7 +279,7 @@ export function useGridKeyboardNavigation<R extends GridRowModel>(
|
|
|
277
279
|
} else if (colRight > visibleEnd) {
|
|
278
280
|
newScrollLeft = colRight - clientWidth + rightPinnedWidth;
|
|
279
281
|
}
|
|
280
|
-
if (newScrollLeft !== scrollLeft) el
|
|
282
|
+
if (newScrollLeft !== scrollLeft) setScrollStart(el, newScrollLeft);
|
|
281
283
|
}, [viewportRef, virtualization, pinnedTopRowCount, rowHeight, pinCheckboxColumn, pinExpandColumn]);
|
|
282
284
|
|
|
283
285
|
// Keep DOM focus on the element of the focused cell. This covers keyboard moves, a cell that
|
|
@@ -365,7 +367,8 @@ export function useGridKeyboardNavigation<R extends GridRowModel>(
|
|
|
365
367
|
// While an IME is composing, Enter / Escape / arrows confirm or navigate candidates.
|
|
366
368
|
if (event.nativeEvent?.isComposing || event.keyCode === 229) return;
|
|
367
369
|
|
|
368
|
-
|
|
370
|
+
// In a right-to-left grid ArrowLeft moves to the column on the left: the next column.
|
|
371
|
+
const key = logicalArrowKey(event.key, isRtl(viewport));
|
|
369
372
|
const isSpace = key === ' ' || key === 'Spacebar';
|
|
370
373
|
const isEditing = Boolean(editingHandlers.editingCell);
|
|
371
374
|
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { MutableRefObject, RefObject } from 'react';
|
|
2
|
+
import type { DataGridProps, GridApi, GridCellParams, GridCellSelectionModel, GridColDef, GridRowId, GridRowMeta, GridRowModel } from '../../types';
|
|
3
|
+
import type { UseGridCellSelectionReturn } from './useGridCellSelection';
|
|
4
|
+
import type { FocusedCell } from './useGridKeyboardNavigation';
|
|
5
|
+
import type { LayoutResult } from './useLayout';
|
|
6
|
+
import type { UseGridBatchEditReturn } from '../features/useGridBatchEdit';
|
|
7
|
+
import { useGridCellSelectionApi } from './useGridCellSelectionApi';
|
|
8
|
+
import { useGridClipboardPaste } from './useGridClipboardPaste';
|
|
9
|
+
import { useGridUndoRedo, UNDO_HISTORY_LIMIT, type GridEditCommitChannel } from './useGridUndoRedo';
|
|
10
|
+
import { useGridFillHandle } from './useGridFillHandle';
|
|
11
|
+
|
|
12
|
+
/** The `DataGrid` props the range editing hooks read. */
|
|
13
|
+
export type GridRangeEditingProps<R extends GridRowModel> = Pick<DataGridProps<R>,
|
|
14
|
+
'disableClipboardPaste' | 'disableRangeClear' | 'onClipboardPaste' | 'onBeforeClipboardPaste' |
|
|
15
|
+
'undoRedo' | 'onHistoryChange' | 'disableFillHandle' | 'onFill'>;
|
|
16
|
+
|
|
17
|
+
export interface UseGridRangeEditingParams<R extends GridRowModel> {
|
|
18
|
+
props: GridRangeEditingProps<R>;
|
|
19
|
+
apiRef: MutableRefObject<GridApi>;
|
|
20
|
+
containerRef: RefObject<HTMLDivElement | null>;
|
|
21
|
+
viewportRef: RefObject<HTMLDivElement | null>;
|
|
22
|
+
selection: UseGridCellSelectionReturn;
|
|
23
|
+
model: GridCellSelectionModel;
|
|
24
|
+
getPendingModel: () => GridCellSelectionModel | null;
|
|
25
|
+
focusedCell: FocusedCell | null;
|
|
26
|
+
setFocusedCell: React.Dispatch<React.SetStateAction<FocusedCell | null>>;
|
|
27
|
+
allRenderableRows: R[];
|
|
28
|
+
getRowId: (row: R) => GridRowId;
|
|
29
|
+
navigationColumns: GridColDef<R>[];
|
|
30
|
+
columnIndexMap: Map<string, number>;
|
|
31
|
+
isCellEditable?: (params: GridCellParams<R>) => boolean;
|
|
32
|
+
rowMetaMap: Map<GridRowId, GridRowMeta>;
|
|
33
|
+
getSpanOrigin?: (rowId: GridRowId, field: string) => { rowId: GridRowId; field: string } | null;
|
|
34
|
+
isEditing: boolean;
|
|
35
|
+
batchEdit: UseGridBatchEditReturn<R>;
|
|
36
|
+
channel: GridEditCommitChannel;
|
|
37
|
+
layout: LayoutResult<R>;
|
|
38
|
+
rowHeight: number;
|
|
39
|
+
pinnedTopRowCount: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Steps 36a–36d of `DataGrid` (docs/architecture/datagrid-orchestration.md), in their call order: the cell
|
|
44
|
+
* selection API (anchor and focus kept together), clipboard paste and range clear, undo/redo, and the fill
|
|
45
|
+
* handle. Returns the fill handle (its position goes to the row renderers).
|
|
46
|
+
*/
|
|
47
|
+
export function useGridRangeEditing<R extends GridRowModel>(params: UseGridRangeEditingParams<R>) {
|
|
48
|
+
const {
|
|
49
|
+
props, apiRef, containerRef, viewportRef, selection, model, getPendingModel, focusedCell, setFocusedCell,
|
|
50
|
+
allRenderableRows, getRowId, navigationColumns, columnIndexMap, isCellEditable, rowMetaMap, getSpanOrigin,
|
|
51
|
+
isEditing, batchEdit, channel, layout, rowHeight, pinnedTopRowCount,
|
|
52
|
+
} = params;
|
|
53
|
+
const {
|
|
54
|
+
disableClipboardPaste = false,
|
|
55
|
+
disableRangeClear = false,
|
|
56
|
+
onClipboardPaste,
|
|
57
|
+
onBeforeClipboardPaste,
|
|
58
|
+
undoRedo = false,
|
|
59
|
+
disableFillHandle = false,
|
|
60
|
+
onFill,
|
|
61
|
+
onHistoryChange,
|
|
62
|
+
} = props;
|
|
63
|
+
|
|
64
|
+
// Keeps the range anchor and the focused cell together; installs the cell selection API.
|
|
65
|
+
useGridCellSelectionApi({
|
|
66
|
+
apiRef,
|
|
67
|
+
selection,
|
|
68
|
+
model,
|
|
69
|
+
getPendingModel,
|
|
70
|
+
focusedCell,
|
|
71
|
+
setFocusedCell,
|
|
72
|
+
containerRef,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Ctrl/Cmd+V and Delete on a range (cellSelection); apiRef.pasteText.
|
|
76
|
+
useGridClipboardPaste<R>({
|
|
77
|
+
apiRef, containerRef, viewportRef,
|
|
78
|
+
selection,
|
|
79
|
+
disableClipboardPaste, disableRangeClear,
|
|
80
|
+
focusedCell,
|
|
81
|
+
allRenderableRows,
|
|
82
|
+
getRowId,
|
|
83
|
+
navigationColumns,
|
|
84
|
+
isCellEditable,
|
|
85
|
+
rowMetaMap,
|
|
86
|
+
getSpanOrigin,
|
|
87
|
+
isEditing,
|
|
88
|
+
batchEdit,
|
|
89
|
+
onClipboardPaste,
|
|
90
|
+
onBeforeClipboardPaste,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Undo / redo (undoRedo): history of committed edits, keys and apiRef methods.
|
|
94
|
+
useGridUndoRedo<R>({
|
|
95
|
+
apiRef,
|
|
96
|
+
enabled: Boolean(undoRedo),
|
|
97
|
+
limit: (typeof undoRedo === 'object' && undoRedo.limit) || UNDO_HISTORY_LIMIT,
|
|
98
|
+
onHistoryChange,
|
|
99
|
+
channel,
|
|
100
|
+
batchEdit,
|
|
101
|
+
isEditing,
|
|
102
|
+
containerRef, viewportRef,
|
|
103
|
+
selection,
|
|
104
|
+
setFocusedCell,
|
|
105
|
+
allRenderableRows,
|
|
106
|
+
getRowId,
|
|
107
|
+
navigationColumns,
|
|
108
|
+
layout,
|
|
109
|
+
rowHeight,
|
|
110
|
+
pinnedTopRowCount,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Fill handle (cellSelection): drag the range's corner, Ctrl/Cmd+D and Ctrl/Cmd+R.
|
|
114
|
+
return useGridFillHandle<R>({
|
|
115
|
+
containerRef, viewportRef,
|
|
116
|
+
selection,
|
|
117
|
+
disableFillHandle,
|
|
118
|
+
isEditing,
|
|
119
|
+
allRenderableRows,
|
|
120
|
+
getRowId,
|
|
121
|
+
navigationColumns,
|
|
122
|
+
columnIndexMap,
|
|
123
|
+
isCellEditable,
|
|
124
|
+
rowMetaMap,
|
|
125
|
+
getSpanOrigin,
|
|
126
|
+
batchEdit,
|
|
127
|
+
onFill,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { GridColDef, GridRowId, GridRowModel } from '../../types';
|
|
2
|
+
import type { GridAriaRowLayout } from '../../utils/aria';
|
|
3
|
+
import type { GridSpanningResult } from '../features/useGridSpanning';
|
|
4
|
+
import { useGridSpanRowWindow, useGridSpanColumnWindow } from '../features/useGridSpanRenderWindow';
|
|
5
|
+
import { useGridAriaRows, type UseGridAriaRowsParams } from './useGridAriaRows';
|
|
6
|
+
import { useGridVisibleRows, type GridVisibleRow } from './useGridVisibleRows';
|
|
7
|
+
import type { GridVirtualizationResult } from './useGridVirtualization';
|
|
8
|
+
import type { LayoutResult } from './useLayout';
|
|
9
|
+
|
|
10
|
+
export interface UseGridRenderWindowParams<R extends GridRowModel> {
|
|
11
|
+
aria: UseGridAriaRowsParams;
|
|
12
|
+
spanning: GridSpanningResult;
|
|
13
|
+
virtualization: GridVirtualizationResult<R>;
|
|
14
|
+
layout: LayoutResult<R>;
|
|
15
|
+
pinnedTopRows: R[];
|
|
16
|
+
pinnedBottomRows: R[];
|
|
17
|
+
paginatedUnpinnedRows: R[];
|
|
18
|
+
sortedUnpinnedRows: R[];
|
|
19
|
+
pagination: boolean;
|
|
20
|
+
getRowId: (row: R) => GridRowId;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface UseGridRenderWindowResult<R extends GridRowModel> {
|
|
24
|
+
ariaRows: GridAriaRowLayout;
|
|
25
|
+
spanRowWindow: ReturnType<typeof useGridSpanRowWindow>;
|
|
26
|
+
visibleRows: GridVisibleRow<R>[];
|
|
27
|
+
renderColumns: GridColDef<R>[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Steps 38–41 of `DataGrid` (docs/architecture/datagrid-orchestration.md), in their call order: the
|
|
32
|
+
* `aria-rowcount` / `aria-rowindex` bases, the render window widened to whole row spans, the rows to
|
|
33
|
+
* render (pinned + virtual centre) and the columns to render, widened to whole column spans.
|
|
34
|
+
*/
|
|
35
|
+
export function useGridRenderWindow<R extends GridRowModel>(params: UseGridRenderWindowParams<R>): UseGridRenderWindowResult<R> {
|
|
36
|
+
const {
|
|
37
|
+
aria, spanning, virtualization, layout, pinnedTopRows, pinnedBottomRows, paginatedUnpinnedRows, sortedUnpinnedRows,
|
|
38
|
+
pagination, getRowId,
|
|
39
|
+
} = params;
|
|
40
|
+
|
|
41
|
+
const ariaRows = useGridAriaRows(aria);
|
|
42
|
+
|
|
43
|
+
const spanRowWindow = useGridSpanRowWindow({
|
|
44
|
+
spanning,
|
|
45
|
+
renderContext: virtualization.renderContext,
|
|
46
|
+
offsetTop: virtualization.offsetTop,
|
|
47
|
+
cumulativeHeights: layout.cumulativeHeights,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const visibleRows = useGridVisibleRows<R>({
|
|
51
|
+
renderContext: spanRowWindow.renderContext,
|
|
52
|
+
pinnedTopRows, pinnedBottomRows, paginatedUnpinnedRows, sortedUnpinnedRows, pagination,
|
|
53
|
+
getRowId,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const renderColumns = useGridSpanColumnWindow<R>({
|
|
57
|
+
spanning,
|
|
58
|
+
firstColumnIndex: virtualization.renderContext.firstColumnIndex,
|
|
59
|
+
lastColumnIndex: virtualization.renderContext.lastColumnIndex,
|
|
60
|
+
virtualColumns: virtualization.virtualColumns,
|
|
61
|
+
layout,
|
|
62
|
+
rows: visibleRows,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return { ariaRows, spanRowWindow, visibleRows, renderColumns };
|
|
66
|
+
}
|