Skip to content

Commit 0604403

Browse files
Update eslint deps (adazzle#3615)
* Update deps * Add new rule * Add `@tanstack/eslint-plugin-router` * Update router deps * update deps * Add `'@typescript-eslint/no-unnecessary-type-parameters': 1,` * Remove @tanstack/eslint-plugin-router * Add `eslint-plugin-react-hooks-extra` * 1 more * Add `eslint-plugin-react-compiler` * -1 array * Do we need these rules * disable 1 `skipLibCheck`, add back newline * update deps * Use state to focus cell * Remove a few refs * Disable warning --------- Co-authored-by: Nicolas Stepien <[email protected]>
1 parent ca6de76 commit 0604403

11 files changed

+150
-141
lines changed

Diff for: eslint.config.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import tsParser from '@typescript-eslint/parser';
44
import vitest from '@vitest/eslint-plugin';
55
import jestDom from 'eslint-plugin-jest-dom';
66
import react from 'eslint-plugin-react';
7+
import reactCompiler from 'eslint-plugin-react-compiler';
78
import reactHooks from 'eslint-plugin-react-hooks';
9+
import reactHooksExtra from 'eslint-plugin-react-hooks-extra';
810
import sonarjs from 'eslint-plugin-sonarjs';
911
import testingLibrary from 'eslint-plugin-testing-library';
1012

@@ -18,7 +20,9 @@ export default [
1820

1921
plugins: {
2022
react,
23+
'react-compiler': reactCompiler,
2124
'react-hooks': fixupPluginRules(reactHooks),
25+
'react-hooks-extra': reactHooksExtra,
2226
sonarjs,
2327
'@typescript-eslint': typescriptEslint
2428
},
@@ -371,11 +375,22 @@ export default [
371375
'react/style-prop-object': 0,
372376
'react/void-dom-elements-no-children': 1,
373377

378+
// React Compiler
379+
// https://react.dev/learn/react-compiler#installing-eslint-plugin-react-compiler
380+
'react-compiler/react-compiler': 1,
381+
374382
// React Hooks
375383
// https://www.npmjs.com/package/eslint-plugin-react-hooks
376384
'react-hooks/rules-of-hooks': 1,
377385
'react-hooks/exhaustive-deps': 1,
378386

387+
// React Hooks Extra
388+
// https://eslint-react.xyz/
389+
'react-hooks-extra/no-redundant-custom-hook': 1,
390+
'react-hooks-extra/no-unnecessary-use-callback': 1,
391+
'react-hooks-extra/no-unnecessary-use-memo': 1,
392+
'react-hooks-extra/prefer-use-state-lazy-initialization': 1,
393+
379394
// SonarJS rules
380395
// https://github.com/SonarSource/eslint-plugin-sonarjs#rules
381396
'sonarjs/no-all-duplicated-branches': 1,
@@ -467,13 +482,14 @@ export default [
467482
'@typescript-eslint/no-this-alias': 0,
468483
'@typescript-eslint/no-type-alias': 0,
469484
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 1,
470-
'@typescript-eslint/no-unnecessary-condition': 1,
485+
'@typescript-eslint/no-unnecessary-condition': [1, { checkTypePredicates: true }],
471486
'@typescript-eslint/no-unnecessary-parameter-property-assignment': 1,
472487
'@typescript-eslint/no-unnecessary-qualifier': 0,
473488
'@typescript-eslint/no-unnecessary-template-expression': 1,
474489
'@typescript-eslint/no-unnecessary-type-arguments': 1,
475490
'@typescript-eslint/no-unnecessary-type-assertion': 1,
476491
'@typescript-eslint/no-unnecessary-type-constraint': 1,
492+
'@typescript-eslint/no-unnecessary-type-parameters': 1,
477493
'@typescript-eslint/no-unsafe-argument': 0,
478494
'@typescript-eslint/no-unsafe-assignment': 0,
479495
'@typescript-eslint/no-unsafe-call': 0,
@@ -587,7 +603,7 @@ export default [
587603
plugins: {
588604
vitest,
589605
'jest-dom': jestDom,
590-
'testing-library': fixupPluginRules(testingLibrary)
606+
'testing-library': testingLibrary
591607
},
592608

593609
rules: {
@@ -647,6 +663,7 @@ export default [
647663
'vitest/prefer-to-contain': 1,
648664
'vitest/prefer-to-have-length': 1,
649665
'vitest/prefer-todo': 1,
666+
'vitest/prefer-vi-mocked': 1,
650667
'vitest/require-hook': 0,
651668
'vitest/require-local-test-context-for-concurrent-snapshots': 0,
652669
'vitest/require-to-throw-message': 0,

Diff for: package.json

+12-10
Original file line numberDiff line numberDiff line change
@@ -62,37 +62,39 @@
6262
"@babel/preset-typescript": "^7.18.6",
6363
"@babel/runtime": "^7.21.5",
6464
"@biomejs/biome": "1.9.4",
65-
"@eslint/compat": "^1.1.1",
65+
"@eslint/compat": "^1.2.2",
6666
"@faker-js/faker": "^9.0.0",
6767
"@ianvs/prettier-plugin-sort-imports": "^4.0.2",
6868
"@linaria/core": "^6.0.0",
6969
"@microsoft/api-extractor": "^7.23.0",
7070
"@rollup/plugin-babel": "^6.0.3",
7171
"@rollup/plugin-node-resolve": "^15.1.0",
72-
"@tanstack/react-router": "^1.57.13",
73-
"@tanstack/router-plugin": "^1.57.13",
72+
"@tanstack/react-router": "^1.70.0",
73+
"@tanstack/router-plugin": "^1.69.1",
7474
"@testing-library/dom": "^10.1.0",
7575
"@testing-library/react": "^16.0.0",
7676
"@testing-library/user-event": "^14.5.2",
7777
"@types/node": "^22.0.0",
7878
"@types/react": "^18.3.9",
7979
"@types/react-dom": "^18.3.0",
80-
"@typescript-eslint/eslint-plugin": "^8.7.0",
81-
"@typescript-eslint/parser": "^8.7.0",
80+
"@typescript-eslint/eslint-plugin": "^8.13.0",
81+
"@typescript-eslint/parser": "^8.13.0",
8282
"@vitejs/plugin-react": "^4.3.1",
8383
"@vitest/browser": "^2.1.1",
8484
"@vitest/coverage-v8": "^2.1.1",
85-
"@vitest/eslint-plugin": "^1.1.4",
85+
"@vitest/eslint-plugin": "^1.1.8",
8686
"@wyw-in-js/rollup": "^0.5.0",
8787
"@wyw-in-js/vite": "^0.5.0",
8888
"babel-plugin-optimize-clsx": "^2.6.2",
8989
"browserslist": "^4.24.0",
90-
"eslint": "^9.11.1",
90+
"eslint": "^9.14.0",
9191
"eslint-plugin-jest-dom": "^5.0.1",
92-
"eslint-plugin-react": "^7.36.1",
92+
"eslint-plugin-react": "^7.37.2",
93+
"eslint-plugin-react-compiler": "^19.0.0-beta-a7bf2bd-20241110",
9394
"eslint-plugin-react-hooks": "^5.0.0",
94-
"eslint-plugin-sonarjs": "^2.0.2",
95-
"eslint-plugin-testing-library": "^6.3.0",
95+
"eslint-plugin-react-hooks-extra": "^1.16.1",
96+
"eslint-plugin-sonarjs": "^2.0.4",
97+
"eslint-plugin-testing-library": "^6.4.0",
9698
"jspdf": "^2.5.1",
9799
"jspdf-autotable": "^3.5.23",
98100
"playwright": "^1.45.1",

Diff for: src/DataGrid.tsx

+38-36
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,8 @@ function DataGrid<R, SR, K extends Key>(
296296
const [isDragging, setDragging] = useState(false);
297297
const [draggedOverRowIdx, setOverRowIdx] = useState<number | undefined>(undefined);
298298
const [scrollToPosition, setScrollToPosition] = useState<PartialPosition | null>(null);
299+
const [shouldFocusCell, setShouldFocusCell] = useState(false);
300+
const [previousRowIdx, setPreviousRowIdx] = useState(-1);
299301

300302
const getColumnWidth = useCallback(
301303
(column: CalculatedColumn<R, SR>) => {
@@ -338,15 +340,13 @@ function DataGrid<R, SR, K extends Key>(
338340
const [selectedPosition, setSelectedPosition] = useState(
339341
(): SelectCellState | EditCellState<R> => ({ idx: -1, rowIdx: minRowIdx - 1, mode: 'SELECT' })
340342
);
343+
const [prevSelectedPosition, setPrevSelectedPosition] = useState(selectedPosition);
341344

342345
/**
343346
* refs
344347
*/
345-
const prevSelectedPosition = useRef(selectedPosition);
346348
const latestDraggedOverRowIdx = useRef(draggedOverRowIdx);
347-
const lastSelectedRowIdx = useRef(-1);
348349
const focusSinkRef = useRef<HTMLDivElement>(null);
349-
const shouldFocusCellRef = useRef(false);
350350

351351
/**
352352
* computed values
@@ -458,31 +458,50 @@ function DataGrid<R, SR, K extends Key>(
458458
selectCell({ rowIdx: minRowIdx + rowIdx - 1, idx });
459459
});
460460

461+
/**
462+
* callbacks
463+
*/
464+
const setDraggedOverRowIdx = useCallback((rowIdx?: number) => {
465+
setOverRowIdx(rowIdx);
466+
latestDraggedOverRowIdx.current = rowIdx;
467+
}, []);
468+
469+
const focusCellOrCellContent = useCallback(() => {
470+
const cell = getCellToScroll(gridRef.current!);
471+
if (cell === null) return;
472+
473+
scrollIntoView(cell);
474+
// Focus cell content when available instead of the cell itself
475+
const elementToFocus = cell.querySelector<Element & HTMLOrSVGElement>('[tabindex="0"]') ?? cell;
476+
elementToFocus.focus({ preventScroll: true });
477+
}, [gridRef]);
478+
461479
/**
462480
* effects
463481
*/
464482
useLayoutEffect(() => {
465483
if (
466484
!selectedCellIsWithinSelectionBounds ||
467-
isSamePosition(selectedPosition, prevSelectedPosition.current)
485+
isSamePosition(selectedPosition, prevSelectedPosition)
468486
) {
469-
prevSelectedPosition.current = selectedPosition;
487+
setPrevSelectedPosition(selectedPosition);
470488
return;
471489
}
472490

473-
prevSelectedPosition.current = selectedPosition;
491+
setPrevSelectedPosition(selectedPosition);
474492

475-
if (selectedPosition.idx === -1) {
476-
focusSinkRef.current!.focus({ preventScroll: true });
493+
if (focusSinkRef.current !== null && selectedPosition.idx === -1) {
494+
focusSinkRef.current.focus({ preventScroll: true });
477495
scrollIntoView(focusSinkRef.current);
478496
}
479-
});
497+
}, [selectedCellIsWithinSelectionBounds, selectedPosition, prevSelectedPosition]);
480498

481499
useLayoutEffect(() => {
482-
if (!shouldFocusCellRef.current) return;
483-
shouldFocusCellRef.current = false;
484-
focusCellOrCellContent();
485-
});
500+
if (shouldFocusCell) {
501+
setShouldFocusCell(false);
502+
focusCellOrCellContent();
503+
}
504+
}, [shouldFocusCell, focusCellOrCellContent]);
486505

487506
useImperativeHandle(ref, () => ({
488507
element: gridRef.current,
@@ -499,14 +518,6 @@ function DataGrid<R, SR, K extends Key>(
499518
selectCell
500519
}));
501520

502-
/**
503-
* callbacks
504-
*/
505-
const setDraggedOverRowIdx = useCallback((rowIdx?: number) => {
506-
setOverRowIdx(rowIdx);
507-
latestDraggedOverRowIdx.current = rowIdx;
508-
}, []);
509-
510521
/**
511522
* event handlers
512523
*/
@@ -536,9 +547,8 @@ function DataGrid<R, SR, K extends Key>(
536547
if (isRowSelectionDisabled?.(row) === true) return;
537548
const newSelectedRows = new Set(selectedRows);
538549
const rowKey = rowKeyGetter(row);
539-
const previousRowIdx = lastSelectedRowIdx.current;
540550
const rowIdx = rows.indexOf(row);
541-
lastSelectedRowIdx.current = rowIdx;
551+
setPreviousRowIdx(rowIdx);
542552

543553
if (checked) {
544554
newSelectedRows.add(rowKey);
@@ -758,7 +768,7 @@ function DataGrid<R, SR, K extends Key>(
758768
// Avoid re-renders if the selected cell state is the same
759769
scrollIntoView(getCellToScroll(gridRef.current!));
760770
} else {
761-
shouldFocusCellRef.current = true;
771+
setShouldFocusCell(true);
762772
setSelectedPosition({ ...position, mode: 'SELECT' });
763773
}
764774

@@ -870,16 +880,6 @@ function DataGrid<R, SR, K extends Key>(
870880
return isDraggedOver ? selectedPosition.idx : undefined;
871881
}
872882

873-
function focusCellOrCellContent() {
874-
const cell = getCellToScroll(gridRef.current!);
875-
if (cell === null) return;
876-
877-
scrollIntoView(cell);
878-
// Focus cell content when available instead of the cell itself
879-
const elementToFocus = cell.querySelector<Element & HTMLOrSVGElement>('[tabindex="0"]') ?? cell;
880-
elementToFocus.focus({ preventScroll: true });
881-
}
882-
883883
function renderDragHandle() {
884884
if (
885885
onFill == null ||
@@ -925,7 +925,7 @@ function DataGrid<R, SR, K extends Key>(
925925
const colSpan = getColSpan(column, lastFrozenColumnIndex, { type: 'ROW', row });
926926

927927
const closeEditor = (shouldFocusCell: boolean) => {
928-
shouldFocusCellRef.current = shouldFocusCell;
928+
setShouldFocusCell(shouldFocusCell);
929929
setSelectedPosition(({ idx, rowIdx }) => ({ idx, rowIdx, mode: 'SELECT' }));
930930
};
931931

@@ -1061,6 +1061,7 @@ function DataGrid<R, SR, K extends Key>(
10611061
// Reset the positions if the current values are no longer valid. This can happen if a column or row is removed
10621062
if (selectedPosition.idx > maxColIdx || selectedPosition.rowIdx > maxRowIdx) {
10631063
setSelectedPosition({ idx: -1, rowIdx: minRowIdx - 1, mode: 'SELECT' });
1064+
// eslint-disable-next-line react-compiler/react-compiler
10641065
setDraggedOverRowIdx(undefined);
10651066
}
10661067

@@ -1182,6 +1183,7 @@ function DataGrid<R, SR, K extends Key>(
11821183
);
11831184
})}
11841185
<RowSelectionChangeProvider value={selectRowLatest}>
1186+
{/* eslint-disable-next-line react-compiler/react-compiler */}
11851187
{getViewportRows()}
11861188
</RowSelectionChangeProvider>
11871189
{bottomSummaryRows?.map((row, rowIdx) => {
@@ -1245,7 +1247,7 @@ function DataGrid<R, SR, K extends Key>(
12451247
<ScrollToCell
12461248
scrollToPosition={scrollToPosition}
12471249
setScrollToCellPosition={setScrollToPosition}
1248-
gridElement={gridRef.current!}
1250+
gridRef={gridRef}
12491251
/>
12501252
)}
12511253
</div>

Diff for: src/ScrollToCell.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ export interface PartialPosition {
1010

1111
export default function ScrollToCell({
1212
scrollToPosition: { idx, rowIdx },
13-
gridElement,
13+
gridRef,
1414
setScrollToCellPosition
1515
}: {
1616
scrollToPosition: PartialPosition;
17-
gridElement: HTMLDivElement;
17+
gridRef: React.RefObject<HTMLDivElement | null>;
1818
setScrollToCellPosition: (cell: null) => void;
1919
}) {
2020
const ref = useRef<HTMLDivElement>(null);
@@ -31,7 +31,7 @@ export default function ScrollToCell({
3131
}
3232

3333
const observer = new IntersectionObserver(removeScrollToCell, {
34-
root: gridElement,
34+
root: gridRef.current!,
3535
threshold: 1.0
3636
});
3737

@@ -40,7 +40,7 @@ export default function ScrollToCell({
4040
return () => {
4141
observer.disconnect();
4242
};
43-
}, [gridElement, setScrollToCellPosition]);
43+
}, [gridRef, setScrollToCellPosition]);
4444

4545
return (
4646
<div

Diff for: src/hooks/useViewportColumns.ts

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export function useViewportColumns<R, SR>({
3636

3737
const updateStartIdx = (colIdx: number, colSpan: number | undefined) => {
3838
if (colSpan !== undefined && colIdx + colSpan > colOverscanStartIdx) {
39+
// eslint-disable-next-line react-compiler/react-compiler
3940
startIdx = colIdx;
4041
return true;
4142
}

Diff for: src/utils/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CalculatedColumn, CalculatedColumnOrColumnGroup } from '../types';
1+
import type { CalculatedColumn, CalculatedColumnOrColumnGroup, Maybe } from '../types';
22

33
export * from './colSpanUtils';
44
export * from './domUtils';
@@ -11,7 +11,7 @@ export * from './styleUtils';
1111
export const { min, max, floor, sign, abs } = Math;
1212

1313
export function assertIsValidKeyGetter<R, K extends React.Key>(
14-
keyGetter: unknown
14+
keyGetter: Maybe<(row: NoInfer<R>) => K>
1515
): asserts keyGetter is (row: R) => K {
1616
if (typeof keyGetter !== 'function') {
1717
throw new Error('Please specify the rowKeyGetter prop to use selection');

Diff for: tsconfig.website.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
{
22
"extends": "./tsconfig.base.json",
33
"compilerOptions": {
4-
"lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"],
5-
"skipLibCheck": true
4+
"lib": ["ESNext", "DOM", "DOM.Iterable", "DOM.AsyncIterable"]
65
},
76
"include": ["website/**/*"],
87
"references": [{ "path": "tsconfig.src.json" }]

0 commit comments

Comments
 (0)