From 5590f800cc97dcafada0a5bf77bd0db8106a5848 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 26 Apr 2024 23:25:23 +0100 Subject: [PATCH 1/9] React 19 --- package.json | 16 ++++++++++------ src/Cell.tsx | 2 +- src/DataGrid.tsx | 2 +- src/EditCell.tsx | 2 +- src/GroupCell.tsx | 2 +- src/GroupRow.tsx | 4 +++- src/GroupedColumnHeaderRow.tsx | 2 +- src/HeaderRow.tsx | 2 +- src/Row.tsx | 2 +- src/SummaryCell.tsx | 2 +- src/SummaryRow.tsx | 2 +- src/TreeDataGrid.tsx | 2 +- src/hooks/useColumnWidths.ts | 6 +++--- website/demos/CommonFeatures.tsx | 2 +- 14 files changed, 27 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index e61a283ff4..c6f62b83fe 100644 --- a/package.json +++ b/package.json @@ -73,8 +73,8 @@ "@testing-library/user-event": "^14.5.2", "@types/lodash-es": "^4.17.7", "@types/node": "^20.10.3", - "@types/react": "^18.3.0", - "@types/react-dom": "^18.3.0", + "@types/react": "npm:types-react@beta", + "@types/react-dom": "npm:types-react-dom@beta", "@typescript-eslint/eslint-plugin": "^7.0.1", "@typescript-eslint/parser": "^7.0.1", "@vitejs/plugin-react": "^4.2.1", @@ -97,10 +97,10 @@ "lodash-es": "^4.17.21", "postcss": "^8.4.25", "prettier": "3.2.5", - "react": "^18.3.1", + "react": "beta", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dom": "^18.3.1", + "react-dom": "beta", "react-router-dom": "^6.11.1", "rollup": "^4.0.2", "rollup-plugin-postcss": "^4.0.2", @@ -109,7 +109,11 @@ "vitest": "^1.2.0" }, "peerDependencies": { - "react": "^18.0", - "react-dom": "^18.0" + "react": "beta", + "react-dom": "beta" + }, + "overrides": { + "@types/react": "npm:types-react@beta", + "@types/react-dom": "npm:types-react-dom@beta" } } diff --git a/src/Cell.tsx b/src/Cell.tsx index 9f0cf75b61..e90e308617 100644 --- a/src/Cell.tsx +++ b/src/Cell.tsx @@ -116,4 +116,4 @@ function Cell({ ); } -export default memo(Cell) as (props: CellRendererProps) => JSX.Element; +export default memo(Cell) as (props: CellRendererProps) => React.JSX.Element; diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 23ad4ec84c..02c1b46395 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -1220,4 +1220,4 @@ function isSamePosition(p1: Position, p2: Position) { export default forwardRef(DataGrid) as ( props: DataGridProps & RefAttributes -) => JSX.Element; +) => React.JSX.Element; diff --git a/src/EditCell.tsx b/src/EditCell.tsx index 241a6e3ac4..2f28e8e5a5 100644 --- a/src/EditCell.tsx +++ b/src/EditCell.tsx @@ -56,7 +56,7 @@ export default function EditCell({ onKeyDown, navigate }: EditCellProps) { - const frameRequestRef = useRef(); + const frameRequestRef = useRef(undefined); const commitOnOutsideClick = column.editorOptions?.commitOnOutsideClick !== false; // We need to prevent the `useEffect` from cleaning up between re-renders, diff --git a/src/GroupCell.tsx b/src/GroupCell.tsx index ab0af22795..935501b46f 100644 --- a/src/GroupCell.tsx +++ b/src/GroupCell.tsx @@ -67,4 +67,4 @@ function GroupCell({ ); } -export default memo(GroupCell) as (props: GroupCellProps) => JSX.Element; +export default memo(GroupCell) as (props: GroupCellProps) => React.JSX.Element; diff --git a/src/GroupRow.tsx b/src/GroupRow.tsx index 1b5e79e641..7937a2e5bc 100644 --- a/src/GroupRow.tsx +++ b/src/GroupRow.tsx @@ -91,4 +91,6 @@ function GroupedRow({ ); } -export default memo(GroupedRow) as (props: GroupRowRendererProps) => JSX.Element; +export default memo(GroupedRow) as ( + props: GroupRowRendererProps +) => React.JSX.Element; diff --git a/src/GroupedColumnHeaderRow.tsx b/src/GroupedColumnHeaderRow.tsx index a40cc03195..fc0ae064b5 100644 --- a/src/GroupedColumnHeaderRow.tsx +++ b/src/GroupedColumnHeaderRow.tsx @@ -60,4 +60,4 @@ function GroupedColumnHeaderRow({ export default memo(GroupedColumnHeaderRow) as ( props: GroupedColumnHeaderRowProps -) => JSX.Element; +) => React.JSX.Element; diff --git a/src/HeaderRow.tsx b/src/HeaderRow.tsx index 09fced82e4..7a8b2b6518 100644 --- a/src/HeaderRow.tsx +++ b/src/HeaderRow.tsx @@ -103,4 +103,4 @@ function HeaderRow({ export default memo(HeaderRow) as ( props: HeaderRowProps -) => JSX.Element; +) => React.JSX.Element; diff --git a/src/Row.tsx b/src/Row.tsx index aab22bda6b..3d74b6e8c9 100644 --- a/src/Row.tsx +++ b/src/Row.tsx @@ -105,7 +105,7 @@ function Row( const RowComponent = memo(forwardRef(Row)) as ( props: RenderRowProps & RefAttributes -) => JSX.Element; +) => React.JSX.Element; export default RowComponent; diff --git a/src/SummaryCell.tsx b/src/SummaryCell.tsx index 86f6b94628..4c58097396 100644 --- a/src/SummaryCell.tsx +++ b/src/SummaryCell.tsx @@ -58,4 +58,4 @@ function SummaryCell({ ); } -export default memo(SummaryCell) as (props: SummaryCellProps) => JSX.Element; +export default memo(SummaryCell) as (props: SummaryCellProps) => React.JSX.Element; diff --git a/src/SummaryRow.tsx b/src/SummaryRow.tsx index fec815bde6..09b9ebb51b 100644 --- a/src/SummaryRow.tsx +++ b/src/SummaryRow.tsx @@ -115,4 +115,4 @@ function SummaryRow({ ); } -export default memo(SummaryRow) as (props: SummaryRowProps) => JSX.Element; +export default memo(SummaryRow) as (props: SummaryRowProps) => React.JSX.Element; diff --git a/src/TreeDataGrid.tsx b/src/TreeDataGrid.tsx index b272817229..340e5321f3 100644 --- a/src/TreeDataGrid.tsx +++ b/src/TreeDataGrid.tsx @@ -436,4 +436,4 @@ function isReadonlyArray(arr: unknown): arr is readonly unknown[] { export default forwardRef(TreeDataGrid) as ( props: TreeDataGridProps & RefAttributes -) => JSX.Element; +) => React.JSX.Element; diff --git a/src/hooks/useColumnWidths.ts b/src/hooks/useColumnWidths.ts index 5e6f7ed136..57d46f70da 100644 --- a/src/hooks/useColumnWidths.ts +++ b/src/hooks/useColumnWidths.ts @@ -9,7 +9,7 @@ export function useColumnWidths( columns: readonly CalculatedColumn[], viewportColumns: readonly CalculatedColumn[], templateColumns: readonly string[], - gridRef: React.RefObject, + gridRef: React.RefObject, gridWidth: number, resizedColumnWidths: ReadonlyMap, measuredColumnWidths: ReadonlyMap, @@ -105,8 +105,8 @@ export function useColumnWidths( } as const; } -function measureColumnWidth(gridRef: React.RefObject, key: string) { +function measureColumnWidth(gridRef: React.RefObject, key: string) { const selector = `[data-measuring-cell-key="${CSS.escape(key)}"]`; - const measuringCell = gridRef.current!.querySelector(selector); + const measuringCell = gridRef.current?.querySelector(selector); return measuringCell?.getBoundingClientRect().width; } diff --git a/website/demos/CommonFeatures.tsx b/website/demos/CommonFeatures.tsx index 0603da134e..33d1e0b709 100644 --- a/website/demos/CommonFeatures.tsx +++ b/website/demos/CommonFeatures.tsx @@ -377,7 +377,7 @@ function ExportButton({ children }: { onExport: () => Promise; - children: React.ReactChild; + children: React.ReactNode; }) { const [exporting, setExporting] = useState(false); return ( From ebc2830a89f8fee24ee31f8ac0ebc36953c541c2 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Mon, 15 Jul 2024 14:38:09 +0100 Subject: [PATCH 2/9] beta -> rc --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 427d08e117..ad0f410232 100644 --- a/package.json +++ b/package.json @@ -74,8 +74,8 @@ "@testing-library/user-event": "^14.5.2", "@types/lodash-es": "^4.17.7", "@types/node": "^20.10.3", - "@types/react": "npm:types-react@beta", - "@types/react-dom": "npm:types-react-dom@beta", + "@types/react": "npm:types-react@rc", + "@types/react-dom": "npm:types-react-dom@rc", "@typescript-eslint/eslint-plugin": "^7.0.1", "@typescript-eslint/parser": "^7.0.1", "@vitejs/plugin-react": "^4.3.1", @@ -98,10 +98,10 @@ "lodash-es": "^4.17.21", "postcss": "^8.4.25", "prettier": "3.3.3", - "react": "beta", + "react": "rc", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", - "react-dom": "beta", + "react-dom": "rc", "react-router-dom": "^6.11.1", "rollup": "^4.0.2", "rollup-plugin-postcss": "^4.0.2", @@ -110,11 +110,11 @@ "vitest": "^2.0.1" }, "peerDependencies": { - "react": "beta", - "react-dom": "beta" + "react": "rc", + "react-dom": "rc" }, "overrides": { - "@types/react": "npm:types-react@beta", - "@types/react-dom": "npm:types-react-dom@beta" + "@types/react": "npm:types-react@rc", + "@types/react-dom": "npm:types-react-dom@rc" } } From 06fb41408cce00ab68aa7784daad88f1e2058dbd Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 18 Jul 2024 16:49:07 +0100 Subject: [PATCH 3/9] remove patch script --- .github/workflows/ci.yml | 12 +----------- .github/workflows/patch-react19.js | 15 --------------- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 .github/workflows/patch-react19.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4e72cbb4e..976af6f473 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,20 +12,11 @@ on: jobs: test: runs-on: ubuntu-latest - strategy: - matrix: - react: [18, 19] - fail-fast: false steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '22.4.1' - - name: set up react 19 - if: matrix.react == 19 - run: | - node ./.github/workflows/patch-react19.js - cat package.json - name: npm install run: npm i - name: Biome @@ -48,12 +39,11 @@ jobs: run: node --run test timeout-minutes: 4 - name: Upload coverage - if: matrix.react == 18 uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} - name: Deploy gh-pages - if: matrix.react == 18 && github.event_name == 'push' && github.ref == 'refs/heads/main' + if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | git config --global user.email 'action@github.com' git config --global user.name 'GitHub Action' diff --git a/.github/workflows/patch-react19.js b/.github/workflows/patch-react19.js deleted file mode 100644 index d4d9193899..0000000000 --- a/.github/workflows/patch-react19.js +++ /dev/null @@ -1,15 +0,0 @@ -import fs from 'node:fs/promises'; - -const pkgText = await fs.readFile('./package.json', 'utf8'); -const pkg = JSON.parse(pkgText); - -pkg.devDependencies['@types/react'] = 'npm:types-react@rc'; -pkg.devDependencies['@types/react-dom'] = 'npm:types-react-dom@rc'; -pkg.devDependencies.react = 'rc'; -pkg.devDependencies['react-dom'] = 'rc'; -pkg.overrides = { - '@types/react': 'npm:types-react@rc', - '@types/react-dom': 'npm:types-react-dom@rc' -}; - -fs.writeFile('./package.json', JSON.stringify(pkg, null, 2)); From 4bfba76d473b55f996a63637ae84dcb2d46e9d18 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 19 Jul 2024 17:55:29 +0100 Subject: [PATCH 4/9] -forwardRef --- src/DataGrid.tsx | 15 +++++-------- src/Row.tsx | 52 ++++++++++++++++++++------------------------ src/TreeDataGrid.tsx | 46 ++++++++++++++++----------------------- src/index.ts | 2 +- src/types.ts | 2 +- 5 files changed, 50 insertions(+), 67 deletions(-) diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 5fd10c4e83..db83a1cb4b 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -1,5 +1,5 @@ -import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react'; -import type { Key, KeyboardEvent, RefAttributes } from 'react'; +import { useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react'; +import type { Key, KeyboardEvent } from 'react'; import { flushSync } from 'react-dom'; import clsx from 'clsx'; @@ -104,6 +104,7 @@ type SharedDivProps = Pick< >; export interface DataGridProps extends SharedDivProps { + ref?: Maybe>; /** * Grid and data Props */ @@ -207,11 +208,9 @@ export interface DataGridProps extends Sha * * */ -function DataGrid( - props: DataGridProps, - ref: React.Ref -) { +export default function DataGrid(props: DataGridProps) { const { + ref, // Grid and data Props columns: rawColumns, rows, @@ -1223,7 +1222,3 @@ function getCellToScroll(gridEl: HTMLDivElement) { function isSamePosition(p1: Position, p2: Position) { return p1.idx === p2.idx && p1.rowIdx === p2.rowIdx; } - -export default forwardRef(DataGrid) as ( - props: DataGridProps & RefAttributes -) => React.JSX.Element; diff --git a/src/Row.tsx b/src/Row.tsx index 98f0a4778f..1805911f41 100644 --- a/src/Row.tsx +++ b/src/Row.tsx @@ -1,4 +1,4 @@ -import { forwardRef, memo, type RefAttributes } from 'react'; +import { memo, type RefAttributes } from 'react'; import clsx from 'clsx'; import { RowSelectionProvider, useLatestFunc } from './hooks'; @@ -7,31 +7,28 @@ import type { CalculatedColumn, RenderRowProps } from './types'; import Cell from './Cell'; import { rowClassname, rowSelectedClassname } from './style/row'; -function Row( - { - className, - rowIdx, - gridRowStart, - selectedCellIdx, - isRowSelected, - copiedCellIdx, - draggedOverCellIdx, - lastFrozenColumnIndex, - row, - viewportColumns, - selectedCellEditor, - onCellClick, - onCellDoubleClick, - onCellContextMenu, - rowClass, - setDraggedOverRowIdx, - onMouseEnter, - onRowChange, - selectCell, - ...props - }: RenderRowProps, - ref: React.Ref -) { +function Row({ + className, + rowIdx, + gridRowStart, + selectedCellIdx, + isRowSelected, + copiedCellIdx, + draggedOverCellIdx, + lastFrozenColumnIndex, + row, + viewportColumns, + selectedCellEditor, + onCellClick, + onCellDoubleClick, + onCellContextMenu, + rowClass, + setDraggedOverRowIdx, + onMouseEnter, + onRowChange, + selectCell, + ...props +}: RenderRowProps) { const handleRowChange = useLatestFunc((column: CalculatedColumn, newRow: R) => { onRowChange(column, rowIdx, newRow); }); @@ -90,7 +87,6 @@ function Row(
( ); } -const RowComponent = memo(forwardRef(Row)) as ( +const RowComponent = memo(Row) as ( props: RenderRowProps & RefAttributes ) => React.JSX.Element; diff --git a/src/TreeDataGrid.tsx b/src/TreeDataGrid.tsx index 06a0749133..74684479cf 100644 --- a/src/TreeDataGrid.tsx +++ b/src/TreeDataGrid.tsx @@ -1,5 +1,5 @@ -import { forwardRef, useCallback, useMemo } from 'react'; -import type { Key, RefAttributes } from 'react'; +import { useCallback, useMemo } from 'react'; +import type { Key } from 'react'; import { useLatestFunc } from './hooks'; import { assertIsValidKeyGetter, isCtrlKeyHeldDown } from './utils'; @@ -17,7 +17,7 @@ import type { import { renderToggleGroup } from './cellRenderers'; import { SELECT_COLUMN_KEY } from './Columns'; import DataGrid from './DataGrid'; -import type { DataGridHandle, DataGridProps } from './DataGrid'; +import type { DataGridProps } from './DataGrid'; import { useDefaultRenderers } from './DataGridDefaultRenderersProvider'; import GroupedRow from './GroupRow'; import { defaultRenderRow } from './Row'; @@ -47,25 +47,22 @@ type GroupByDictionary = Record< } >; -function TreeDataGrid( - { - columns: rawColumns, - rows: rawRows, - rowHeight: rawRowHeight, - rowKeyGetter: rawRowKeyGetter, - onCellKeyDown: rawOnCellKeyDown, - onRowsChange, - selectedRows: rawSelectedRows, - onSelectedRowsChange: rawOnSelectedRowsChange, - renderers, - groupBy: rawGroupBy, - rowGrouper, - expandedGroupIds, - onExpandedGroupIdsChange, - ...props - }: TreeDataGridProps, - ref: React.Ref -) { +export function TreeDataGrid({ + columns: rawColumns, + rows: rawRows, + rowHeight: rawRowHeight, + rowKeyGetter: rawRowKeyGetter, + onCellKeyDown: rawOnCellKeyDown, + onRowsChange, + selectedRows: rawSelectedRows, + onSelectedRowsChange: rawOnSelectedRowsChange, + renderers, + groupBy: rawGroupBy, + rowGrouper, + expandedGroupIds, + onExpandedGroupIdsChange, + ...props +}: TreeDataGridProps) { const defaultRenderers = useDefaultRenderers(); const rawRenderRow = renderers?.renderRow ?? defaultRenderers?.renderRow ?? defaultRenderRow; const headerAndTopSummaryRowsCount = 1 + (props.topSummaryRows?.length ?? 0); @@ -416,7 +413,6 @@ function TreeDataGrid( aria-rowcount={ rowsCount + 1 + (props.topSummaryRows?.length ?? 0) + (props.bottomSummaryRows?.length ?? 0) } - ref={ref} columns={columns} rows={rows as R[]} // TODO: check types rowHeight={rowHeight} @@ -436,7 +432,3 @@ function TreeDataGrid( function isReadonlyArray(arr: unknown): arr is readonly unknown[] { return Array.isArray(arr); } - -export default forwardRef(TreeDataGrid) as ( - props: TreeDataGridProps & RefAttributes -) => React.JSX.Element; diff --git a/src/index.ts b/src/index.ts index 270d71def0..cdbffe49f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import './style/layers.css'; export { default, type DataGridProps, type DataGridHandle } from './DataGrid'; -export { default as TreeDataGrid, type TreeDataGridProps } from './TreeDataGrid'; +export { TreeDataGrid, type TreeDataGridProps } from './TreeDataGrid'; export { DataGridDefaultRenderersProvider } from './DataGridDefaultRenderersProvider'; export { default as Row } from './Row'; export * from './Columns'; diff --git a/src/types.ts b/src/types.ts index 2c8d7abc63..d3d9767b5c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -201,7 +201,7 @@ export interface CellSelectArgs { } export interface BaseRenderRowProps - extends Omit, 'style' | 'children'>, + extends Omit, 'style' | 'children'>, Pick< DataGridProps, 'onCellClick' | 'onCellDoubleClick' | 'onCellContextMenu' From 8a745585d1654dd591d62f185fcbd4e821791088 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 19 Jul 2024 17:59:19 +0100 Subject: [PATCH 5/9] use ComponentProps --- src/DataGrid.tsx | 2 +- src/HeaderCell.tsx | 2 +- src/Row.tsx | 6 ++---- src/types.ts | 4 ++-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index db83a1cb4b..0bedb91fb8 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -93,7 +93,7 @@ export interface DataGridHandle { } type SharedDivProps = Pick< - React.HTMLAttributes, + React.ComponentProps<'div'>, | 'role' | 'aria-label' | 'aria-labelledby' diff --git a/src/HeaderCell.tsx b/src/HeaderCell.tsx index 2dde6d2fe0..d022ac33e8 100644 --- a/src/HeaderCell.tsx +++ b/src/HeaderCell.tsx @@ -245,7 +245,7 @@ export default function HeaderCell({ } } - let draggableProps: React.HTMLAttributes | undefined; + let draggableProps: React.ComponentProps<'div'> | undefined; if (draggable) { draggableProps = { draggable: true, diff --git a/src/Row.tsx b/src/Row.tsx index 1805911f41..d079091078 100644 --- a/src/Row.tsx +++ b/src/Row.tsx @@ -1,4 +1,4 @@ -import { memo, type RefAttributes } from 'react'; +import { memo } from 'react'; import clsx from 'clsx'; import { RowSelectionProvider, useLatestFunc } from './hooks'; @@ -98,9 +98,7 @@ function Row({ ); } -const RowComponent = memo(Row) as ( - props: RenderRowProps & RefAttributes -) => React.JSX.Element; +const RowComponent = memo(Row) as (props: RenderRowProps) => React.JSX.Element; export default RowComponent; diff --git a/src/types.ts b/src/types.ts index d3d9767b5c..9e2256d280 100644 --- a/src/types.ts +++ b/src/types.ts @@ -144,7 +144,7 @@ export interface RenderHeaderCellProps { export interface CellRendererProps extends Pick, 'row' | 'rowIdx' | 'selectCell'>, Omit< - React.HTMLAttributes, + React.ComponentProps<'div'>, 'style' | 'children' | 'onClick' | 'onDoubleClick' | 'onContextMenu' > { column: CalculatedColumn; @@ -294,7 +294,7 @@ export interface RenderSortStatusProps extends RenderSortIconProps, RenderSortPr export interface RenderCheckboxProps extends Pick< - React.InputHTMLAttributes, + React.ComponentProps<'input'>, 'aria-label' | 'aria-labelledby' | 'checked' | 'tabIndex' | 'disabled' > { onChange: (checked: boolean, shift: boolean) => void; From 5d1c3bf5bfcec234e02982e3c8a5c00c44f2d387 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 19 Jul 2024 18:01:19 +0100 Subject: [PATCH 6/9] import useLayoutEffect directly --- .eslintrc.cjs | 5 ----- src/DataGrid.tsx | 10 ++++++++-- src/ScrollToCell.tsx | 3 +-- src/hooks/index.ts | 1 - src/hooks/useColumnWidths.ts | 3 +-- src/hooks/useGridDimensions.ts | 4 +--- src/hooks/useLayoutEffect.ts | 6 ------ 7 files changed, 11 insertions(+), 21 deletions(-) delete mode 100644 src/hooks/useLayoutEffect.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 23e1b5b864..2a2e25db13 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -667,11 +667,6 @@ const rules = { importNames: ['default'], message: 'Use named imports instead.' }, - { - name: 'react', - importNames: ['useLayoutEffect'], - message: 'Use the override from src/hooks instead.' - }, { name: 'react-dom', importNames: ['default'], diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 0bedb91fb8..58b83b32ce 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -1,4 +1,11 @@ -import { useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react'; +import { + useCallback, + useImperativeHandle, + useLayoutEffect, + useMemo, + useRef, + useState +} from 'react'; import type { Key, KeyboardEvent } from 'react'; import { flushSync } from 'react-dom'; import clsx from 'clsx'; @@ -10,7 +17,6 @@ import { useColumnWidths, useGridDimensions, useLatestFunc, - useLayoutEffect, useViewportColumns, useViewportRows } from './hooks'; diff --git a/src/ScrollToCell.tsx b/src/ScrollToCell.tsx index 7fca2ce353..b2b0c7f550 100644 --- a/src/ScrollToCell.tsx +++ b/src/ScrollToCell.tsx @@ -1,6 +1,5 @@ -import { useRef } from 'react'; +import { useLayoutEffect, useRef } from 'react'; -import { useLayoutEffect } from './hooks'; import { scrollIntoView } from './utils'; export interface PartialPosition { diff --git a/src/hooks/index.ts b/src/hooks/index.ts index c836ce472f..709f729be0 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -2,7 +2,6 @@ export * from './useCalculatedColumns'; export * from './useColumnWidths'; export * from './useGridDimensions'; export * from './useLatestFunc'; -export * from './useLayoutEffect'; export * from './useRovingTabIndex'; export * from './useRowSelection'; export * from './useViewportColumns'; diff --git a/src/hooks/useColumnWidths.ts b/src/hooks/useColumnWidths.ts index 57d46f70da..830d1623c5 100644 --- a/src/hooks/useColumnWidths.ts +++ b/src/hooks/useColumnWidths.ts @@ -1,8 +1,7 @@ -import { useRef } from 'react'; +import { useLayoutEffect, useRef } from 'react'; import { flushSync } from 'react-dom'; import type { CalculatedColumn, StateSetter } from '../types'; -import { useLayoutEffect } from './useLayoutEffect'; import type { DataGridProps } from '../DataGrid'; export function useColumnWidths( diff --git a/src/hooks/useGridDimensions.ts b/src/hooks/useGridDimensions.ts index ee7df45b4b..ddd2ac67e3 100644 --- a/src/hooks/useGridDimensions.ts +++ b/src/hooks/useGridDimensions.ts @@ -1,8 +1,6 @@ -import { useRef, useState } from 'react'; +import { useLayoutEffect, useRef, useState } from 'react'; import { flushSync } from 'react-dom'; -import { useLayoutEffect } from './useLayoutEffect'; - export function useGridDimensions() { const gridRef = useRef(null); const [inlineSize, setInlineSize] = useState(1); diff --git a/src/hooks/useLayoutEffect.ts b/src/hooks/useLayoutEffect.ts deleted file mode 100644 index 8700637319..0000000000 --- a/src/hooks/useLayoutEffect.ts +++ /dev/null @@ -1,6 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-restricted-imports -import { useEffect, useLayoutEffect as useOriginalLayoutEffect } from 'react'; - -// Silence silly warning -// https://reactjs.org/link/uselayouteffect-ssr -export const useLayoutEffect = typeof window === 'undefined' ? useEffect : useOriginalLayoutEffect; From c01a5b85e7f94cceb4e0297dabc307accbd89ac4 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 19 Jul 2024 18:08:13 +0100 Subject: [PATCH 7/9] use contexts directly --- README.md | 6 +-- src/DataGrid.tsx | 20 +++++----- ....ts => DataGridDefaultRenderersContext.ts} | 4 +- src/GroupRow.tsx | 6 +-- src/Row.tsx | 6 +-- src/TreeDataGrid.tsx | 2 +- src/cellRenderers/SelectCellFormatter.tsx | 2 +- src/hooks/useRowSelection.ts | 8 +--- src/index.ts | 2 +- src/renderHeaderCell.tsx | 2 +- test/renderers.test.tsx | 40 +++++++++---------- website/demos/HeaderFilters.tsx | 4 +- 12 files changed, 48 insertions(+), 54 deletions(-) rename src/{DataGridDefaultRenderersProvider.ts => DataGridDefaultRenderersContext.ts} (61%) diff --git a/README.md b/README.md index e131eac6cf..01b5825973 100644 --- a/README.md +++ b/README.md @@ -227,16 +227,16 @@ interface Renderers { } ``` -For example, the default `` component can be wrapped via the `renderRow` prop to add context providers or tweak props +For example, the default `` component can be wrapped via the `renderRow` prop to add contexts or tweak props ```tsx import DataGrid, { RenderRowProps, Row } from 'react-data-grid'; function myRowRenderer(key: React.Key, props: RenderRowProps) { return ( - + - + ); } diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 58b83b32ce..3a74ccea77 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -11,8 +11,8 @@ import { flushSync } from 'react-dom'; import clsx from 'clsx'; import { - RowSelectionChangeProvider, - RowSelectionProvider, + RowSelectionChangeContext, + RowSelectionContext, useCalculatedColumns, useColumnWidths, useGridDimensions, @@ -57,9 +57,9 @@ import type { } from './types'; import { renderCheckbox as defaultRenderCheckbox } from './cellRenderers'; import { - DataGridDefaultRenderersProvider, + DataGridDefaultRenderersContext, useDefaultRenderers -} from './DataGridDefaultRenderersProvider'; +} from './DataGridDefaultRenderersContext'; import DragHandle from './DragHandle'; import EditCell from './EditCell'; import GroupedColumnHeaderRow from './GroupedColumnHeaderRow'; @@ -1093,9 +1093,9 @@ export default function DataGrid(props: DataGridProps - - - + + + {Array.from({ length: groupedColumnHeaderRowsCount }, (_, index) => ( (props: DataGridProps - + {rows.length === 0 && noRowsFallback ? ( noRowsFallback ) : ( @@ -1184,8 +1184,8 @@ export default function DataGrid(props: DataGridProps )} - - + + {renderDragHandle()} diff --git a/src/DataGridDefaultRenderersProvider.ts b/src/DataGridDefaultRenderersContext.ts similarity index 61% rename from src/DataGridDefaultRenderersProvider.ts rename to src/DataGridDefaultRenderersContext.ts index 79d0df609e..5cf1bcbe10 100644 --- a/src/DataGridDefaultRenderersProvider.ts +++ b/src/DataGridDefaultRenderersContext.ts @@ -3,9 +3,7 @@ import { createContext, useContext } from 'react'; import type { Maybe, Renderers } from './types'; // eslint-disable-next-line @typescript-eslint/no-explicit-any -const DataGridDefaultRenderersContext = createContext>>(undefined); - -export const DataGridDefaultRenderersProvider = DataGridDefaultRenderersContext.Provider; +export const DataGridDefaultRenderersContext = createContext>>(undefined); export function useDefaultRenderers(): Maybe> { return useContext(DataGridDefaultRenderersContext); diff --git a/src/GroupRow.tsx b/src/GroupRow.tsx index fcf023425c..d36abc8068 100644 --- a/src/GroupRow.tsx +++ b/src/GroupRow.tsx @@ -2,7 +2,7 @@ import { memo } from 'react'; import { css } from '@linaria/core'; import clsx from 'clsx'; -import { RowSelectionProvider } from './hooks'; +import { RowSelectionContext } from './hooks'; import { getRowStyle } from './utils'; import type { BaseRenderRowProps, GroupRow } from './types'; import { SELECT_COLUMN_KEY } from './Columns'; @@ -52,7 +52,7 @@ function GroupedRow({ } return ( - +
({ /> ))}
-
+ ); } diff --git a/src/Row.tsx b/src/Row.tsx index d079091078..86709215e7 100644 --- a/src/Row.tsx +++ b/src/Row.tsx @@ -1,7 +1,7 @@ import { memo } from 'react'; import clsx from 'clsx'; -import { RowSelectionProvider, useLatestFunc } from './hooks'; +import { RowSelectionContext, useLatestFunc } from './hooks'; import { getColSpan, getRowStyle } from './utils'; import type { CalculatedColumn, RenderRowProps } from './types'; import Cell from './Cell'; @@ -84,7 +84,7 @@ function Row({ } return ( - +
({ > {cells}
-
+ ); } diff --git a/src/TreeDataGrid.tsx b/src/TreeDataGrid.tsx index 74684479cf..98345c353a 100644 --- a/src/TreeDataGrid.tsx +++ b/src/TreeDataGrid.tsx @@ -18,7 +18,7 @@ import { renderToggleGroup } from './cellRenderers'; import { SELECT_COLUMN_KEY } from './Columns'; import DataGrid from './DataGrid'; import type { DataGridProps } from './DataGrid'; -import { useDefaultRenderers } from './DataGridDefaultRenderersProvider'; +import { useDefaultRenderers } from './DataGridDefaultRenderersContext'; import GroupedRow from './GroupRow'; import { defaultRenderRow } from './Row'; diff --git a/src/cellRenderers/SelectCellFormatter.tsx b/src/cellRenderers/SelectCellFormatter.tsx index 8b8fe62f11..865e450806 100644 --- a/src/cellRenderers/SelectCellFormatter.tsx +++ b/src/cellRenderers/SelectCellFormatter.tsx @@ -1,5 +1,5 @@ import type { RenderCheckboxProps } from '../types'; -import { useDefaultRenderers } from '../DataGridDefaultRenderersProvider'; +import { useDefaultRenderers } from '../DataGridDefaultRenderersContext'; type SharedInputProps = Pick< RenderCheckboxProps, diff --git a/src/hooks/useRowSelection.ts b/src/hooks/useRowSelection.ts index c5a1635357..2be4b03fdc 100644 --- a/src/hooks/useRowSelection.ts +++ b/src/hooks/useRowSelection.ts @@ -2,17 +2,13 @@ import { createContext, useContext } from 'react'; import type { SelectRowEvent } from '../types'; -const RowSelectionContext = createContext(undefined); +export const RowSelectionContext = createContext(undefined); -export const RowSelectionProvider = RowSelectionContext.Provider; - -const RowSelectionChangeContext = createContext< +export const RowSelectionChangeContext = createContext< // eslint-disable-next-line @typescript-eslint/no-explicit-any ((selectRowEvent: SelectRowEvent) => void) | undefined >(undefined); -export const RowSelectionChangeProvider = RowSelectionChangeContext.Provider; - export function useRowSelection(): [boolean, (selectRowEvent: SelectRowEvent) => void] { const rowSelectionContext = useContext(RowSelectionContext); const rowSelectionChangeContext = useContext(RowSelectionChangeContext); diff --git a/src/index.ts b/src/index.ts index cdbffe49f6..5024902200 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import './style/layers.css'; export { default, type DataGridProps, type DataGridHandle } from './DataGrid'; export { TreeDataGrid, type TreeDataGridProps } from './TreeDataGrid'; -export { DataGridDefaultRenderersProvider } from './DataGridDefaultRenderersProvider'; +export { DataGridDefaultRenderersContext } from './DataGridDefaultRenderersContext'; export { default as Row } from './Row'; export * from './Columns'; export * from './cellRenderers'; diff --git a/src/renderHeaderCell.tsx b/src/renderHeaderCell.tsx index 1338a932d3..d7a848359d 100644 --- a/src/renderHeaderCell.tsx +++ b/src/renderHeaderCell.tsx @@ -1,7 +1,7 @@ import { css } from '@linaria/core'; import type { RenderHeaderCellProps } from './types'; -import { useDefaultRenderers } from './DataGridDefaultRenderersProvider'; +import { useDefaultRenderers } from './DataGridDefaultRenderersContext'; const headerSortCellClassname = css` @layer rdg.SortableHeaderCell { diff --git a/test/renderers.test.tsx b/test/renderers.test.tsx index 52b0b5303e..68a21a4e0f 100644 --- a/test/renderers.test.tsx +++ b/test/renderers.test.tsx @@ -2,7 +2,7 @@ import { useState } from 'react'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import DataGrid, { DataGridDefaultRenderersProvider, renderSortIcon, SelectColumn } from '../src'; +import DataGrid, { DataGridDefaultRenderersContext, renderSortIcon, SelectColumn } from '../src'; import type { Column, DataGridProps, RenderSortStatusProps, SortColumn } from '../src'; import { getHeaderCells, getRows, setup } from './utils'; @@ -66,9 +66,9 @@ function TestGrid(props: DataGridProps) { return ; } -function setupProvider(props: DataGridProps) { +function setupContext(props: DataGridProps) { return render( - , renderCheckbox: globalRenderCheckbox, @@ -76,7 +76,7 @@ function setupProvider(props: DataGridProps - + ); } @@ -87,15 +87,15 @@ test('fallback defined using renderers prop with no rows', () => { expect(screen.getByText('Local no rows fallback')).toBeInTheDocument(); }); -test('fallback defined using provider with no rows', () => { - setupProvider({ columns, rows: noRows }); +test('fallback defined using context with no rows', () => { + setupContext({ columns, rows: noRows }); expect(getRows()).toHaveLength(0); expect(screen.getByText('Global no rows fallback')).toBeInTheDocument(); }); -test('fallback defined using both provider and renderers with no rows', () => { - setupProvider({ columns, rows: noRows, renderers: { noRowsFallback: } }); +test('fallback defined using both context and renderers with no rows', () => { + setupContext({ columns, rows: noRows, renderers: { noRowsFallback: } }); expect(getRows()).toHaveLength(0); expect(screen.getByText('Local no rows fallback')).toBeInTheDocument(); @@ -108,15 +108,15 @@ test('fallback defined using renderers prop with a row', () => { expect(screen.queryByText('Local no rows fallback')).not.toBeInTheDocument(); }); -test('fallback defined using provider with a row', () => { - setupProvider({ columns, rows: [{ id: 1 }] }); +test('fallback defined using context with a row', () => { + setupContext({ columns, rows: [{ id: 1 }] }); expect(getRows()).toHaveLength(1); expect(screen.queryByText('Global no rows fallback')).not.toBeInTheDocument(); }); -test('fallback defined using both provider and renderers with a row', () => { - setupProvider({ columns, rows: [{ id: 1 }], renderers: { noRowsFallback: } }); +test('fallback defined using both context and renderers with a row', () => { + setupContext({ columns, rows: [{ id: 1 }], renderers: { noRowsFallback: } }); expect(getRows()).toHaveLength(1); expect(screen.queryByText('Global no rows fallback')).not.toBeInTheDocument(); @@ -130,23 +130,23 @@ test('checkbox defined using renderers prop', () => { expect(screen.getByText('Local checkbox')).toBeInTheDocument(); }); -test('checkbox defined using provider', () => { - setupProvider({ columns, rows: noRows }); +test('checkbox defined using context', () => { + setupContext({ columns, rows: noRows }); expect(getRows()).toHaveLength(0); expect(screen.getByText('Global checkbox')).toBeInTheDocument(); }); -test('checkbox defined using both provider and renderers', () => { - setupProvider({ columns, rows: noRows, renderers: { renderCheckbox: localRenderCheckbox } }); +test('checkbox defined using both context and renderers', () => { + setupContext({ columns, rows: noRows, renderers: { renderCheckbox: localRenderCheckbox } }); expect(getRows()).toHaveLength(0); expect(screen.getByText('Local checkbox')).toBeInTheDocument(); expect(screen.queryByText('Global checkbox')).not.toBeInTheDocument(); }); -test('sortPriority defined using both providers', async () => { - setupProvider({ columns, rows: noRows }); +test('sortPriority defined using both contexts', async () => { + setupContext({ columns, rows: noRows }); const [, headerCell2, headerCell3] = getHeaderCells(); const user = userEvent.setup(); @@ -161,8 +161,8 @@ test('sortPriority defined using both providers', async () => { expect(screen.queryByTestId('local-sort-priority')).not.toBeInTheDocument(); }); -test('sortPriority defined using both providers and renderers', async () => { - setupProvider({ columns, rows: noRows, renderers: { renderSortStatus } }); +test('sortPriority defined using both contexts and renderers', async () => { + setupContext({ columns, rows: noRows, renderers: { renderSortStatus } }); const [, headerCell2, headerCell3] = getHeaderCells(); const user = userEvent.setup(); diff --git a/website/demos/HeaderFilters.tsx b/website/demos/HeaderFilters.tsx index d9ddcb98fc..c6cb1bf799 100644 --- a/website/demos/HeaderFilters.tsx +++ b/website/demos/HeaderFilters.tsx @@ -281,7 +281,7 @@ export default function HeaderFilters({ direction }: Props) { Clear Filters
- + - + {developerOptions.map(({ label, value }) => (