@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useRef, useState, useCallback, useEffect } from 'react';
|
|
2
|
+
import { getScrollStart, setScrollStart } from '../../utils/direction';
|
|
2
3
|
import type { GridRowScrollEndParams } from '../../types';
|
|
3
4
|
import { getRowsScrollEndParams } from '../../utils/scroll/scrollEnd';
|
|
4
5
|
|
|
@@ -82,16 +83,18 @@ export function useGridScrollSync(params: UseGridScrollSyncParams): UseGridScrol
|
|
|
82
83
|
const handleScroll = useCallback((event: React.UIEvent<HTMLDivElement>) => {
|
|
83
84
|
const target = event.currentTarget;
|
|
84
85
|
const now = performance.now();
|
|
86
|
+
// Counted from the inline start, so the column window is the same in a right-to-left grid.
|
|
87
|
+
const scrollLeft = getScrollStart(target);
|
|
85
88
|
|
|
86
89
|
// Velocity: total positional delta / elapsed time (px/ms)
|
|
87
90
|
const deltaPos = Math.abs(target.scrollTop - prevRef.current.scrollTop)
|
|
88
|
-
+ Math.abs(
|
|
91
|
+
+ Math.abs(scrollLeft - prevRef.current.scrollLeft);
|
|
89
92
|
const deltaTime = now - prevRef.current.time;
|
|
90
93
|
const velocity = deltaTime > 0 ? deltaPos / deltaTime : 0;
|
|
91
94
|
const movedVertically = target.scrollTop !== prevRef.current.scrollTop;
|
|
92
95
|
|
|
93
|
-
prevRef.current = { scrollTop: target.scrollTop, scrollLeft
|
|
94
|
-
pendingRef.current = { scrollTop: target.scrollTop, scrollLeft
|
|
96
|
+
prevRef.current = { scrollTop: target.scrollTop, scrollLeft, time: now };
|
|
97
|
+
pendingRef.current = { scrollTop: target.scrollTop, scrollLeft, velocity };
|
|
95
98
|
|
|
96
99
|
if (rafRef.current !== null) cancelAnimationFrame(rafRef.current);
|
|
97
100
|
rafRef.current = requestAnimationFrame(() => {
|
|
@@ -120,16 +123,36 @@ export function useGridScrollSync(params: UseGridScrollSyncParams): UseGridScrol
|
|
|
120
123
|
checkRowsScrollEnd(el);
|
|
121
124
|
}, [rowCount, autoHeight, checkRowsScrollEnd]);
|
|
122
125
|
|
|
126
|
+
// Switching `dir` on the grid or an ancestor moves the content to the other side, and browsers
|
|
127
|
+
// reset (Firefox without a scroll event) or keep the scroll position as they please. Re-read it
|
|
128
|
+
// so the column window matches what the viewport shows.
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
const doc = elementRef.current?.ownerDocument ?? (typeof document === 'undefined' ? null : document);
|
|
131
|
+
if (!doc || typeof MutationObserver === 'undefined') return;
|
|
132
|
+
const observer = new MutationObserver(() => {
|
|
133
|
+
const target = elementRef.current;
|
|
134
|
+
if (!target) return;
|
|
135
|
+
const actual = { scrollTop: target.scrollTop, scrollLeft: getScrollStart(target) };
|
|
136
|
+
const pending = pendingRef.current;
|
|
137
|
+
if (actual.scrollTop === pending.scrollTop && actual.scrollLeft === pending.scrollLeft) return;
|
|
138
|
+
pendingRef.current = { ...pending, ...actual };
|
|
139
|
+
prevRef.current = { ...prevRef.current, ...actual };
|
|
140
|
+
setScrollState(prev => ({ ...prev, ...actual }));
|
|
141
|
+
});
|
|
142
|
+
observer.observe(doc.documentElement, { attributes: true, attributeFilter: ['dir'], subtree: true });
|
|
143
|
+
return () => observer.disconnect();
|
|
144
|
+
}, []);
|
|
145
|
+
|
|
123
146
|
const attachViewport = useCallback((element: HTMLDivElement | null) => {
|
|
124
147
|
elementRef.current = element;
|
|
125
148
|
if (!element) return;
|
|
126
149
|
const { scrollTop, scrollLeft } = pendingRef.current;
|
|
127
150
|
if (scrollTop === 0 && scrollLeft === 0) return;
|
|
128
151
|
element.scrollTop = scrollTop;
|
|
129
|
-
element
|
|
152
|
+
setScrollStart(element, scrollLeft);
|
|
130
153
|
// The browser clamps to the new content. If it did, sync the state to what the element
|
|
131
154
|
// shows (no scroll event fires when the position ends up unchanged).
|
|
132
|
-
const actual = { scrollTop: element.scrollTop, scrollLeft: element
|
|
155
|
+
const actual = { scrollTop: element.scrollTop, scrollLeft: getScrollStart(element) };
|
|
133
156
|
if (actual.scrollTop !== scrollTop || actual.scrollLeft !== scrollLeft) {
|
|
134
157
|
pendingRef.current = { ...pendingRef.current, ...actual };
|
|
135
158
|
prevRef.current = { ...prevRef.current, ...actual };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { MutableRefObject, RefObject } from 'react';
|
|
2
|
+
import type { GridRowModel } from '../../types';
|
|
3
|
+
import { useGridViewport, type UseGridViewportParams } from './useGridViewport';
|
|
4
|
+
import { useGridMaxContentHeight } from './useGridMaxContentHeight';
|
|
5
|
+
import { useGridVirtualization, type UseGridVirtualizationParams } from './useGridVirtualization';
|
|
6
|
+
import type { LayoutResult } from './useLayout';
|
|
7
|
+
|
|
8
|
+
export interface UseGridScrollViewportParams<R extends GridRowModel> {
|
|
9
|
+
viewport: Omit<UseGridViewportParams, 'viewportRef' | 'rowCount'>;
|
|
10
|
+
viewportRef: MutableRefObject<HTMLDivElement | null>;
|
|
11
|
+
containerRef: RefObject<HTMLDivElement | null>;
|
|
12
|
+
layout: LayoutResult<R>;
|
|
13
|
+
viewportWidth: number;
|
|
14
|
+
viewportHeight: number;
|
|
15
|
+
/** The virtualization inputs that do not come from the viewport. */
|
|
16
|
+
virtualization: Pick<UseGridVirtualizationParams<R>,
|
|
17
|
+
'autoHeight' | 'rowReordering' | 'hasDetailPanel' | 'checkboxSelection' | 'pinCheckboxColumn' | 'pinExpandColumn'>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Steps 32–33 of `DataGrid` (docs/architecture/datagrid-orchestration.md), in their call order: scroll sync
|
|
22
|
+
* and viewport measurement, the tallest element this browser lays out (32a), and the render window.
|
|
23
|
+
*/
|
|
24
|
+
export function useGridScrollViewport<R extends GridRowModel>(params: UseGridScrollViewportParams<R>) {
|
|
25
|
+
const { viewport, viewportRef, containerRef, layout, viewportWidth, viewportHeight, virtualization: options } = params;
|
|
26
|
+
|
|
27
|
+
const { scrollTop, scrollLeft, overscanRows, handleScroll, setViewportElement } = useGridViewport({
|
|
28
|
+
...viewport, rowCount: layout.unpinnedRowsLength, viewportRef,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const maxContentHeight = useGridMaxContentHeight(containerRef);
|
|
32
|
+
const virtualization = useGridVirtualization({
|
|
33
|
+
layout, scrollTop, scrollLeft,
|
|
34
|
+
viewportWidth,
|
|
35
|
+
viewportHeight,
|
|
36
|
+
...options,
|
|
37
|
+
overscanRows,
|
|
38
|
+
maxContentHeight: maxContentHeight ?? Infinity,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return { handleScroll, setViewportElement, maxContentHeight, virtualization };
|
|
42
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { GridRowModel } from '../../types';
|
|
2
|
+
import { useGridRowInteractions, type UseGridRowInteractionsParams, type UseGridRowInteractionsResult } from './useGridRowInteractions';
|
|
3
|
+
import { useGridApiMethods, type UseGridApiMethodsParams } from './useGridApiMethods';
|
|
4
|
+
import type { UseGridControlledStateReturn } from './useGridControlledState';
|
|
5
|
+
|
|
6
|
+
/** The state API inputs that do not come from `useGridControlledState`. */
|
|
7
|
+
export type GridStateApiParams = Pick<UseGridApiMethodsParams,
|
|
8
|
+
'apiRef' | 'multiSort' | 'selectedRowIds' | 'disableMultipleRowSelection' | 'isSyntheticRowId' | 'getVisibleRows' |
|
|
9
|
+
'getAllFilteredRows' | 'visibleColumns'>;
|
|
10
|
+
|
|
11
|
+
export interface UseGridSelectionAndStateApiParams<R extends GridRowModel> {
|
|
12
|
+
controlledState: UseGridControlledStateReturn;
|
|
13
|
+
interactions: Omit<UseGridRowInteractionsParams<R>, 'selectedRowIds' | 'onSelectionModelChange' | 'disableMultipleRowSelection'>;
|
|
14
|
+
api: GridStateApiParams;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Steps 23–24 of `DataGrid` (docs/architecture/datagrid-orchestration.md), in their call order: row
|
|
19
|
+
* selection and the row click / checkbox handlers, then the state API methods (sort, filter, pagination,
|
|
20
|
+
* selection, row grouping, aggregation, visibility and pivot setters, `getGridAiState`) installed on `apiRef`.
|
|
21
|
+
*/
|
|
22
|
+
export function useGridSelectionAndStateApi<R extends GridRowModel>(
|
|
23
|
+
params: UseGridSelectionAndStateApiParams<R>
|
|
24
|
+
): UseGridRowInteractionsResult<R> {
|
|
25
|
+
const { controlledState, interactions, api } = params;
|
|
26
|
+
const {
|
|
27
|
+
sortModel, handleSortModelChange, filterModel, handleFilterModelChange, effectivePaginationModel,
|
|
28
|
+
handlePaginationModelChange, handleRowSelectionModelChange, rowGroupingModel, handleRowGroupingModelChange,
|
|
29
|
+
aggregationModel, handleAggregationModelChange, columnVisibilityModel, handleColumnVisibilityModelChange,
|
|
30
|
+
currentPivotModel, handlePivotModelChange,
|
|
31
|
+
} = controlledState;
|
|
32
|
+
|
|
33
|
+
const result = useGridRowInteractions<R>({
|
|
34
|
+
...interactions,
|
|
35
|
+
selectedRowIds: api.selectedRowIds,
|
|
36
|
+
onSelectionModelChange: handleRowSelectionModelChange,
|
|
37
|
+
disableMultipleRowSelection: api.disableMultipleRowSelection,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
useGridApiMethods({
|
|
41
|
+
...api,
|
|
42
|
+
onSortModelChange: handleSortModelChange,
|
|
43
|
+
sortModel,
|
|
44
|
+
filterModel,
|
|
45
|
+
onFilterModelChange: handleFilterModelChange,
|
|
46
|
+
paginationModel: effectivePaginationModel,
|
|
47
|
+
onPaginationModelChange: handlePaginationModelChange,
|
|
48
|
+
getPendingRowSelectionModel: controlledState.getPendingRowSelectionModel,
|
|
49
|
+
onRowSelectionModelChange: handleRowSelectionModelChange,
|
|
50
|
+
rowGroupingModel,
|
|
51
|
+
onRowGroupingModelChange: handleRowGroupingModelChange,
|
|
52
|
+
aggregationModel,
|
|
53
|
+
onAggregationModelChange: handleAggregationModelChange,
|
|
54
|
+
columnVisibilityModel,
|
|
55
|
+
onColumnVisibilityModelChange: handleColumnVisibilityModelChange,
|
|
56
|
+
pivotModel: currentPivotModel,
|
|
57
|
+
onPivotModelChange: handlePivotModelChange,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { MutableRefObject, RefObject } from 'react';
|
|
2
|
+
import type { GridApi, GridLocaleText, GridRowModel } from '../../types';
|
|
3
|
+
import { useGridColumnsPanel } from './useGridColumnsPanel';
|
|
4
|
+
import { useGridStylesheetWarning } from './useGridDevWarnings';
|
|
5
|
+
import { useGridAiAssistant, type UseGridAiAssistantParams } from '../features/useGridAiAssistant';
|
|
6
|
+
import { useGridToolbarProps, type UseGridToolbarPropsParams } from './useGridToolbarProps';
|
|
7
|
+
|
|
8
|
+
/** What `useGridToolbarProps` needs besides the columns panel and the AI assistant built here. */
|
|
9
|
+
export type GridToolbarStackToolbarParams<R extends GridRowModel> = Omit<UseGridToolbarPropsParams<R>,
|
|
10
|
+
'forceColumnsOpen' | 'onColumnsPanelClose' | 'aiAssistantEnabled' | 'aiAssistantOpen' | 'onAiAssistantToggle' |
|
|
11
|
+
'aiAssistantLabel' | 'forceFiltersOpen' | 'onFiltersPanelClose' | 'apiRef'>;
|
|
12
|
+
|
|
13
|
+
export interface UseGridToolbarStackParams<R extends GridRowModel> {
|
|
14
|
+
apiRef: MutableRefObject<GridApi>;
|
|
15
|
+
containerRef: RefObject<HTMLDivElement | null>;
|
|
16
|
+
aiAssistant: Omit<UseGridAiAssistantParams, 'apiRef'>;
|
|
17
|
+
toolbar: GridToolbarStackToolbarParams<R>;
|
|
18
|
+
localeText: GridLocaleText | undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Steps 44–46 of `DataGrid` (docs/architecture/datagrid-orchestration.md), in their call order: the columns
|
|
23
|
+
* panel (toolbar or standalone), the missing-stylesheet warning, the `aiAssistant` panel, and the props for
|
|
24
|
+
* `slots.toolbar` (which gets its Ask AI button from the assistant).
|
|
25
|
+
*/
|
|
26
|
+
export function useGridToolbarStack<R extends GridRowModel>(params: UseGridToolbarStackParams<R>) {
|
|
27
|
+
const { apiRef, containerRef, aiAssistant, toolbar, localeText } = params;
|
|
28
|
+
|
|
29
|
+
const columnsPanel = useGridColumnsPanel();
|
|
30
|
+
useGridStylesheetWarning(containerRef);
|
|
31
|
+
|
|
32
|
+
// The aiAssistant prompt panel (v3.5): applies validated replies through apiRef; apiRef.openAiAssistant.
|
|
33
|
+
const aiAssistantPanel = useGridAiAssistant({ apiRef, ...aiAssistant });
|
|
34
|
+
|
|
35
|
+
const toolbarProps = useGridToolbarProps<R>({
|
|
36
|
+
...toolbar,
|
|
37
|
+
apiRef,
|
|
38
|
+
forceColumnsOpen: columnsPanel.toolbarPanelRequested,
|
|
39
|
+
onColumnsPanelClose: columnsPanel.closeToolbarPanel,
|
|
40
|
+
aiAssistantEnabled: aiAssistantPanel.enabled,
|
|
41
|
+
aiAssistantOpen: aiAssistantPanel.open,
|
|
42
|
+
onAiAssistantToggle: aiAssistantPanel.togglePanel,
|
|
43
|
+
aiAssistantLabel: localeText?.aiAssistantButton,
|
|
44
|
+
forceFiltersOpen: columnsPanel.toolbarFiltersRequested,
|
|
45
|
+
onFiltersPanelClose: columnsPanel.closeToolbarFiltersPanel,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return { columnsPanel, aiAssistantPanel, toolbarProps };
|
|
49
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { MutableRefObject, RefObject } from 'react';
|
|
2
|
+
import type { GridApi, GridColDef, GridRowId, GridRowModel } from '../../types';
|
|
3
|
+
import { useGridClipboardApi } from './useGridClipboardApi';
|
|
4
|
+
import { useGridScrollToIndexesApi } from './useGridScrollToIndexesApi';
|
|
5
|
+
import { useGridColumnAutosize } from './useGridColumnAutosize';
|
|
6
|
+
import type { LayoutResult } from './useLayout';
|
|
7
|
+
|
|
8
|
+
export interface UseGridViewApisParams<R extends GridRowModel> {
|
|
9
|
+
apiRef: MutableRefObject<GridApi>;
|
|
10
|
+
containerRef: RefObject<HTMLDivElement | null>;
|
|
11
|
+
viewportRef: RefObject<HTMLDivElement | null>;
|
|
12
|
+
/** Rendered data columns with their layout-resolved widths, in render order (what Ctrl/Cmd+C copies). */
|
|
13
|
+
copyColumns: GridColDef[];
|
|
14
|
+
getRowId: (row: GridRowModel) => GridRowId;
|
|
15
|
+
disableClipboardCopy: boolean;
|
|
16
|
+
/** The cell range's copy text while `cellSelection` is on. */
|
|
17
|
+
getCellRangeCopyText: (() => string | null) | undefined;
|
|
18
|
+
layout: LayoutResult<R>;
|
|
19
|
+
rowHeight: number;
|
|
20
|
+
/** Every column in display order (what auto-size measures). */
|
|
21
|
+
orderedColumns: GridColDef<R>[];
|
|
22
|
+
onColumnResize: (field: string, width: number) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Steps 30–31a of `DataGrid` (docs/architecture/datagrid-orchestration.md), in their call order: the
|
|
27
|
+
* `apiRef` installers that need the laid-out view — copy, `scrollToIndexes` and column auto-size.
|
|
28
|
+
* Returns the resize handle's auto-size handler.
|
|
29
|
+
*/
|
|
30
|
+
export function useGridViewApis<R extends GridRowModel>(params: UseGridViewApisParams<R>): (field: string) => void {
|
|
31
|
+
const {
|
|
32
|
+
apiRef, containerRef, viewportRef, copyColumns, getRowId, disableClipboardCopy, getCellRangeCopyText, layout, rowHeight,
|
|
33
|
+
orderedColumns, onColumnResize,
|
|
34
|
+
} = params;
|
|
35
|
+
|
|
36
|
+
useGridClipboardApi({
|
|
37
|
+
apiRef,
|
|
38
|
+
columns: copyColumns,
|
|
39
|
+
getRowId,
|
|
40
|
+
containerRef,
|
|
41
|
+
disableKeyboardShortcut: disableClipboardCopy,
|
|
42
|
+
getCellRangeCopyText,
|
|
43
|
+
});
|
|
44
|
+
useGridScrollToIndexesApi<R>({ apiRef, viewportRef, layout, rowHeight });
|
|
45
|
+
return useGridColumnAutosize<R>({ apiRef, containerRef, columns: orderedColumns, onColumnResize });
|
|
46
|
+
}
|
|
@@ -255,12 +255,19 @@ export function useLayout<R extends GridRowModel>(params: UseLayoutParams<R>): L
|
|
|
255
255
|
return rowHeight + getDetailPanelLayoutHeight(panelHeight, detailPanelHeights?.get(id));
|
|
256
256
|
};
|
|
257
257
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
258
|
+
// One pass with preallocated arrays: this runs for every row after each sort or filter. With
|
|
259
|
+
// no detail panel open every row has the plain height, so row ids are not looked up.
|
|
260
|
+
const rowCount = unpinnedRows.length;
|
|
261
|
+
const rowHeights = new Array<number>(rowCount);
|
|
262
|
+
const cumulativeHeights = new Array<number>(rowCount);
|
|
263
|
+
const anyPanelOpen = expandedRowIds.size > 0;
|
|
264
|
+
let runningHeight = 0;
|
|
265
|
+
for (let index = 0; index < rowCount; index++) {
|
|
266
|
+
const height = anyPanelOpen ? heightOf(unpinnedRows[index], pinnedTopRowsLength + index) : rowHeight;
|
|
267
|
+
rowHeights[index] = height;
|
|
268
|
+
runningHeight = (runningHeight || 0) + height; // as before: a NaN total restarts from 0
|
|
269
|
+
cumulativeHeights[index] = runningHeight;
|
|
270
|
+
}
|
|
264
271
|
|
|
265
272
|
const skeletonCount = (paginationMode === 'infinite' && isLoading && unpinnedRows.length > 0)
|
|
266
273
|
? Math.min(pageSize, 20)
|
|
@@ -307,13 +307,15 @@ export function useRowGrouping<R extends GridRowModel>(params: UseRowGroupingPar
|
|
|
307
307
|
), [defaultGroupingExpansionDepth]);
|
|
308
308
|
|
|
309
309
|
const expandedGroupIds = useMemo<Set<GridRowId>>(() => {
|
|
310
|
+
// Only group nodes have children, so walk the groups rather than every leaf, in tree order.
|
|
310
311
|
const ids = new Set<GridRowId>();
|
|
311
|
-
|
|
312
|
-
|
|
312
|
+
for (const id of groupIds) {
|
|
313
|
+
const node = treeNodes.get(id);
|
|
314
|
+
if (!node?.children || node.children.length === 0) continue;
|
|
313
315
|
if (overrides.get(id) ?? isDefaultExpanded(node)) ids.add(id);
|
|
314
|
-
}
|
|
316
|
+
}
|
|
315
317
|
return ids;
|
|
316
|
-
}, [treeNodes, overrides, isDefaultExpanded]);
|
|
318
|
+
}, [groupIds, treeNodes, overrides, isDefaultExpanded]);
|
|
317
319
|
|
|
318
320
|
const toggleExpansion = useCallback((id: GridRowId) => {
|
|
319
321
|
setExpansionState(prev => {
|
|
@@ -439,11 +441,9 @@ export function useRowGrouping<R extends GridRowModel>(params: UseRowGroupingPar
|
|
|
439
441
|
treeNodes.forEach((node, id) => {
|
|
440
442
|
const variants = groupRowVariants.get(id);
|
|
441
443
|
if (!variants) {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
isGroupRow: false,
|
|
446
|
-
});
|
|
444
|
+
// One object per row (not shared per depth): `params.rowMeta` is public, and a consumer that
|
|
445
|
+
// writes to it must not change other rows.
|
|
446
|
+
map.set(id, { hasChildren: false, treeDepth: node.depth, isGroupRow: false });
|
|
447
447
|
return;
|
|
448
448
|
}
|
|
449
449
|
const groupMeta: GridRowMeta = {
|
|
@@ -81,6 +81,18 @@
|
|
|
81
81
|
--ogx-grid-cell-font-size: 13px;
|
|
82
82
|
--ogx-grid-header-font-size: 13px;
|
|
83
83
|
--ogx-grid-line-height: var(--ogx-line-height-normal);
|
|
84
|
+
/* Outer border and divider widths (v3.7). 0 hides a divider. Their colours,
|
|
85
|
+
--ogx-grid-column-divider-color and --ogx-grid-row-divider-color, are unset here and fall back
|
|
86
|
+
to --ogx-grid-border-color where they are used. So do the other theme-builder variables:
|
|
87
|
+
--ogx-grid-border-radius (--ogx-border-radius-lg), --ogx-grid-header-padding-x
|
|
88
|
+
(--ogx-grid-cell-padding-x), --ogx-grid-header-font-family / -font-weight and
|
|
89
|
+
--ogx-grid-cell-font-family / -font-weight (inherited; header weight 600), and
|
|
90
|
+
--ogx-overlay-font-family / -font-weight / -font-size (the grid font, each item's own weight,
|
|
91
|
+
--ogx-font-size-xs for menu and panel items). */
|
|
92
|
+
--ogx-grid-border-width: 1px;
|
|
93
|
+
--ogx-grid-column-divider-width: 1px;
|
|
94
|
+
--ogx-grid-header-column-divider-width: 1px;
|
|
95
|
+
--ogx-grid-row-divider-width: 1px;
|
|
84
96
|
--ogx-grid-background: var(--ogx-color-white);
|
|
85
97
|
--ogx-grid-border-color: var(--ogx-color-gray-200);
|
|
86
98
|
--ogx-grid-header-background: var(--ogx-color-gray-50);
|
|
@@ -272,6 +272,18 @@ function themeToCSS(theme: GridTheme): Record<string, string> {
|
|
|
272
272
|
set('--ogx-grid-cell-padding-y', g.cellPaddingY);
|
|
273
273
|
set('--ogx-grid-cell-font-size', g.cellFontSize);
|
|
274
274
|
set('--ogx-grid-header-font-size', g.headerFontSize);
|
|
275
|
+
set('--ogx-grid-header-font-family', g.headerFontFamily);
|
|
276
|
+
set('--ogx-grid-header-font-weight', g.headerFontWeight);
|
|
277
|
+
set('--ogx-grid-cell-font-family', g.cellFontFamily);
|
|
278
|
+
set('--ogx-grid-cell-font-weight', g.cellFontWeight);
|
|
279
|
+
set('--ogx-grid-header-padding-x', g.headerPaddingX);
|
|
280
|
+
set('--ogx-grid-border-width', g.borderWidth);
|
|
281
|
+
set('--ogx-grid-border-radius', g.borderRadius);
|
|
282
|
+
set('--ogx-grid-column-divider-width', g.columnDividerWidth);
|
|
283
|
+
set('--ogx-grid-header-column-divider-width', g.headerColumnDividerWidth);
|
|
284
|
+
set('--ogx-grid-row-divider-width', g.rowDividerWidth);
|
|
285
|
+
set('--ogx-grid-column-divider-color', g.columnDividerColor);
|
|
286
|
+
set('--ogx-grid-row-divider-color', g.rowDividerColor);
|
|
275
287
|
set('--ogx-grid-background', g.background);
|
|
276
288
|
set('--ogx-grid-border-color', g.borderColor);
|
|
277
289
|
set('--ogx-grid-header-background', g.headerBackground);
|
|
@@ -338,6 +350,9 @@ function themeToCSS(theme: GridTheme): Record<string, string> {
|
|
|
338
350
|
set('--ogx-overlay-item-selected-text', o.itemSelectedText);
|
|
339
351
|
set('--ogx-overlay-item-danger-bg', o.itemDangerBackground);
|
|
340
352
|
set('--ogx-overlay-item-danger-text', o.itemDangerText);
|
|
353
|
+
set('--ogx-overlay-font-family', o.fontFamily);
|
|
354
|
+
set('--ogx-overlay-font-weight', o.fontWeight);
|
|
355
|
+
set('--ogx-overlay-font-size', o.fontSize);
|
|
341
356
|
}
|
|
342
357
|
|
|
343
358
|
if (theme.scrollbar) {
|