From 9c8639f8ceee4e18935508b5c834fd88b8dcacd4 Mon Sep 17 00:00:00 2001 From: robert Date: Mon, 16 Dec 2024 18:59:29 +0800 Subject: [PATCH] implement right frozen I'm not override frozen to left | right | null, I just add rightFrozen property. It will not break original version. --- src/DataGrid.tsx | 5 ++- src/hooks/useCalculatedColumns.ts | 55 +++++++++++++++++++++----- src/hooks/useViewportColumns.ts | 7 ++++ src/style/cell.ts | 16 ++++++++ src/style/core.ts | 2 + src/types.ts | 2 + src/utils/styleUtils.ts | 8 ++-- website/routes/CommonFeatures.lazy.tsx | 6 ++- 8 files changed, 85 insertions(+), 16 deletions(-) diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index dc6f6aeb58..6fabcd7e5b 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -322,7 +322,9 @@ function DataGrid( colOverscanEndIdx, templateColumns, layoutCssVars, - totalFrozenColumnWidth + totalFrozenColumnWidth, + rightFrozenColumnCount, + totalRightFrozenColumnWidth } = useCalculatedColumns({ rawColumns, defaultColumnOptions, @@ -418,6 +420,7 @@ function DataGrid( colOverscanStartIdx, colOverscanEndIdx, lastFrozenColumnIndex, + rightFrozenColumnCount, rowOverscanStartIdx, rowOverscanEndIdx, rows, diff --git a/src/hooks/useCalculatedColumns.ts b/src/hooks/useCalculatedColumns.ts index 92a3417ab9..bcb1a7a737 100644 --- a/src/hooks/useCalculatedColumns.ts +++ b/src/hooks/useCalculatedColumns.ts @@ -52,13 +52,15 @@ export function useCalculatedColumns({ const defaultResizable = defaultColumnOptions?.resizable ?? false; const defaultDraggable = defaultColumnOptions?.draggable ?? false; - const { columns, colSpanColumns, lastFrozenColumnIndex, headerRowsCount } = useMemo((): { + const { columns, colSpanColumns, lastFrozenColumnIndex, rightFrozenColumnCount, headerRowsCount } = useMemo((): { readonly columns: readonly CalculatedColumn[]; readonly colSpanColumns: readonly CalculatedColumn[]; readonly lastFrozenColumnIndex: number; + readonly rightFrozenColumnCount: number; readonly headerRowsCount: number; } => { let lastFrozenColumnIndex = -1; + let rightFrozenColumnCount = 0; let headerRowsCount = 1; const columns: MutableCalculatedColumn[] = []; @@ -85,6 +87,7 @@ export function useCalculatedColumns({ } const frozen = rawColumn.frozen ?? false; + const rightFrozen = rawColumn.rightFrozen ?? false; const column: MutableCalculatedColumn = { ...rawColumn, @@ -92,6 +95,7 @@ export function useCalculatedColumns({ idx: 0, level: 0, frozen, + rightFrozen, width: rawColumn.width ?? defaultWidth, minWidth: rawColumn.minWidth ?? defaultMinWidth, maxWidth: rawColumn.maxWidth ?? defaultMaxWidth, @@ -107,13 +111,17 @@ export function useCalculatedColumns({ lastFrozenColumnIndex++; } + if(rightFrozen) { + rightFrozenColumnCount++; + } + if (level > headerRowsCount) { headerRowsCount = level; } } } - columns.sort(({ key: aKey, frozen: frozenA }, { key: bKey, frozen: frozenB }) => { + columns.sort(({ key: aKey, frozen: frozenA, rightFrozen: rightFrozenA }, { key: bKey, frozen: frozenB, rightFrozen: rightFrozenB }) => { // Sort select column first: if (aKey === SELECT_COLUMN_KEY) return -1; if (bKey === SELECT_COLUMN_KEY) return 1; @@ -125,6 +133,13 @@ export function useCalculatedColumns({ } if (frozenB) return 1; + // Sort right frozen columns second: + if (rightFrozenA) { + if (rightFrozenB) return 0; + return 1; + } + if (rightFrozenB) return -1; + // TODO: sort columns to keep them grouped if they have a parent // Sort other columns last: @@ -145,6 +160,7 @@ export function useCalculatedColumns({ columns, colSpanColumns, lastFrozenColumnIndex, + rightFrozenColumnCount, headerRowsCount }; }, [ @@ -158,15 +174,17 @@ export function useCalculatedColumns({ defaultDraggable ]); - const { templateColumns, layoutCssVars, totalFrozenColumnWidth, columnMetrics } = useMemo((): { + const { templateColumns, layoutCssVars, totalFrozenColumnWidth, totalRightFrozenColumnWidth, columnMetrics } = useMemo((): { templateColumns: readonly string[]; layoutCssVars: Readonly>; totalFrozenColumnWidth: number; + totalRightFrozenColumnWidth: number; columnMetrics: ReadonlyMap, ColumnMetric>; } => { const columnMetrics = new Map, ColumnMetric>(); let left = 0; let totalFrozenColumnWidth = 0; + let totalRightFrozenColumnWidth = 0; const templateColumns: string[] = []; for (const column of columns) { @@ -191,13 +209,26 @@ export function useCalculatedColumns({ const layoutCssVars: Record = {}; + if(rightFrozenColumnCount !== 0) { + let rightEnd = 0; + for(let i=columns.length-1;i>=columns.length-rightFrozenColumnCount;i--) { + const column = columns[i]; + const columnMetric = columnMetrics.get(column)!; + totalRightFrozenColumnWidth+=columnMetric.width; + layoutCssVars[`--rdg-frozen-right-${column.idx}`] = `${rightEnd}px`; + rightEnd+=columnMetric.width; + } + } + + + for (let i = 0; i <= lastFrozenColumnIndex; i++) { const column = columns[i]; layoutCssVars[`--rdg-frozen-left-${column.idx}`] = `${columnMetrics.get(column)!.left}px`; } - return { templateColumns, layoutCssVars, totalFrozenColumnWidth, columnMetrics }; - }, [getColumnWidth, columns, lastFrozenColumnIndex]); + return { templateColumns, layoutCssVars, totalFrozenColumnWidth, totalRightFrozenColumnWidth, columnMetrics }; + }, [getColumnWidth, columns, lastFrozenColumnIndex, rightFrozenColumnCount]); const [colOverscanStartIdx, colOverscanEndIdx] = useMemo((): [number, number] => { if (!enableVirtualization) { @@ -205,10 +236,11 @@ export function useCalculatedColumns({ } // get the viewport's left side and right side positions for non-frozen columns const viewportLeft = scrollLeft + totalFrozenColumnWidth; - const viewportRight = scrollLeft + viewportWidth; + const viewportRight = scrollLeft + viewportWidth - totalRightFrozenColumnWidth; // get first and last non-frozen column indexes const lastColIdx = columns.length - 1; const firstUnfrozenColumnIdx = min(lastFrozenColumnIndex + 1, lastColIdx); + const lastUnfrozonColumnIdx = min(columns.length - rightFrozenColumnCount -1, lastColIdx); // skip rendering non-frozen columns if the frozen columns cover the entire viewport if (viewportLeft >= viewportRight) { @@ -217,7 +249,7 @@ export function useCalculatedColumns({ // get the first visible non-frozen column index let colVisibleStartIdx = firstUnfrozenColumnIdx; - while (colVisibleStartIdx < lastColIdx) { + while (colVisibleStartIdx < lastUnfrozonColumnIdx) { const { left, width } = columnMetrics.get(columns[colVisibleStartIdx])!; // if the right side of the columnn is beyond the left side of the available viewport, // then it is the first column that's at least partially visible @@ -229,7 +261,7 @@ export function useCalculatedColumns({ // get the last visible non-frozen column index let colVisibleEndIdx = colVisibleStartIdx; - while (colVisibleEndIdx < lastColIdx) { + while (colVisibleEndIdx < lastUnfrozonColumnIdx) { const { left, width } = columnMetrics.get(columns[colVisibleEndIdx])!; // if the right side of the column is beyond or equal to the right side of the available viewport, // then it the last column that's at least partially visible, as the previous column's right side is not beyond the viewport. @@ -240,7 +272,7 @@ export function useCalculatedColumns({ } const colOverscanStartIdx = max(firstUnfrozenColumnIdx, colVisibleStartIdx - 1); - const colOverscanEndIdx = min(lastColIdx, colVisibleEndIdx + 1); + const colOverscanEndIdx = min(lastUnfrozonColumnIdx, colVisibleEndIdx + 1); return [colOverscanStartIdx, colOverscanEndIdx]; }, [ @@ -249,6 +281,7 @@ export function useCalculatedColumns({ lastFrozenColumnIndex, scrollLeft, totalFrozenColumnWidth, + totalRightFrozenColumnWidth, viewportWidth, enableVirtualization ]); @@ -262,7 +295,9 @@ export function useCalculatedColumns({ layoutCssVars, headerRowsCount, lastFrozenColumnIndex, - totalFrozenColumnWidth + totalFrozenColumnWidth, + rightFrozenColumnCount, + totalRightFrozenColumnWidth }; } diff --git a/src/hooks/useViewportColumns.ts b/src/hooks/useViewportColumns.ts index 701b719ec6..9dff900972 100644 --- a/src/hooks/useViewportColumns.ts +++ b/src/hooks/useViewportColumns.ts @@ -12,6 +12,7 @@ interface ViewportColumnsArgs { colOverscanStartIdx: number; colOverscanEndIdx: number; lastFrozenColumnIndex: number; + rightFrozenColumnCount: number; rowOverscanStartIdx: number; rowOverscanEndIdx: number; } @@ -25,6 +26,7 @@ export function useViewportColumns({ colOverscanStartIdx, colOverscanEndIdx, lastFrozenColumnIndex, + rightFrozenColumnCount, rowOverscanStartIdx, rowOverscanEndIdx }: ViewportColumnsArgs) { @@ -110,6 +112,11 @@ export function useViewportColumns({ viewportColumns.push(column); } + for(let colIdx = columns.length-rightFrozenColumnCount; colIdx { readonly colSpan?: Maybe<(args: ColSpanArgs) => Maybe>; /** Determines whether column is frozen or not */ readonly frozen?: Maybe; + /** Determines whether column is right frozen or not */ + readonly rightFrozen?: Maybe; /** Enable resizing of a column */ readonly resizable?: Maybe; /** Enable sorting of a column */ diff --git a/src/utils/styleUtils.ts b/src/utils/styleUtils.ts index 53a3becc57..0c8b9efbf4 100644 --- a/src/utils/styleUtils.ts +++ b/src/utils/styleUtils.ts @@ -2,7 +2,7 @@ import type { CSSProperties } from 'react'; import clsx from 'clsx'; import type { CalculatedColumn, CalculatedColumnOrColumnGroup } from '../types'; -import { cellClassname, cellFrozenClassname } from '../style/cell'; +import { cellClassname, cellFrozenClassname, cellRightFrozenClassname } from '../style/cell'; export function getRowStyle(rowIdx: number): CSSProperties { return { '--rdg-grid-row-start': rowIdx } as unknown as CSSProperties; @@ -41,7 +41,8 @@ export function getCellStyle( return { gridColumnStart: index, gridColumnEnd: index + colSpan, - insetInlineStart: column.frozen ? `var(--rdg-frozen-left-${column.idx})` : undefined + insetInlineStart: column.frozen ? `var(--rdg-frozen-left-${column.idx})` : undefined, + insetInlineEnd: column.rightFrozen? `var(--rdg-frozen-right-${column.idx})` : undefined, }; } @@ -52,7 +53,8 @@ export function getCellClassname( return clsx( cellClassname, { - [cellFrozenClassname]: column.frozen + [cellFrozenClassname]: column.frozen, + [cellRightFrozenClassname]: column.rightFrozen, }, ...extraClasses ); diff --git a/website/routes/CommonFeatures.lazy.tsx b/website/routes/CommonFeatures.lazy.tsx index f7f066b2bf..1bade5a2a9 100644 --- a/website/routes/CommonFeatures.lazy.tsx +++ b/website/routes/CommonFeatures.lazy.tsx @@ -214,16 +214,18 @@ function getColumns( }, { key: 'account', - name: 'Account' + name: 'Account', + rightFrozen: true, }, { key: 'version', name: 'Version', - renderEditCell: textEditor + renderEditCell: textEditor, }, { key: 'available', name: 'Available', + rightFrozen: true, renderCell({ row, onRowChange, tabIndex }) { return (