@equinor/eds-data-grid-react 0.8.1 → 0.9.1
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/dist/eds-data-grid-react.cjs +41 -2
- package/dist/esm/EdsDataGrid.js +6 -2
- package/dist/esm/components/TableRow.js +31 -1
- package/dist/esm/utils.js +7 -1
- package/dist/types/components/ClickableCell/ClickableCell.d.ts +12 -0
- package/dist/types/components/ClickableCell/ClickableCell.tokens.d.ts +3 -0
- package/dist/types/components/ClickableCell/index.d.ts +1 -0
- package/dist/types/components/TableRow.d.ts +4 -1
- package/dist/types/utils.d.ts +2 -0
- package/package.json +25 -29
|
@@ -513,13 +513,42 @@ function TableRow({
|
|
|
513
513
|
onCellClick,
|
|
514
514
|
onClick,
|
|
515
515
|
onDoubleClick,
|
|
516
|
-
onContextMenu
|
|
516
|
+
onContextMenu,
|
|
517
|
+
rowVirtualizer,
|
|
518
|
+
virtualItem
|
|
517
519
|
}) {
|
|
518
520
|
const {
|
|
519
521
|
rowClass,
|
|
520
522
|
rowStyle
|
|
521
523
|
} = useTableContext();
|
|
524
|
+
const isMountedRef = react.useRef(true);
|
|
525
|
+
|
|
526
|
+
// Set mounted flag to false on unmount to prevent measurements during cleanup
|
|
527
|
+
react.useEffect(() => {
|
|
528
|
+
return () => {
|
|
529
|
+
isMountedRef.current = false;
|
|
530
|
+
};
|
|
531
|
+
}, []);
|
|
532
|
+
|
|
533
|
+
// Create a stable ref callback that guards against calls during unmount
|
|
534
|
+
const measureRef = react.useCallback(node => {
|
|
535
|
+
// Only measure if we have a node, the component is still mounted, and we have a virtualizer
|
|
536
|
+
if (node && isMountedRef.current && rowVirtualizer) {
|
|
537
|
+
try {
|
|
538
|
+
rowVirtualizer.measureElement(node);
|
|
539
|
+
} catch (error) {
|
|
540
|
+
// Silently catch any errors during measurement to prevent crashes
|
|
541
|
+
// This can happen if the virtualizer is in an inconsistent state during unmount
|
|
542
|
+
if (process.env.NODE_ENV === 'development') {
|
|
543
|
+
console.warn('Failed to measure element during virtualization:', error);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}, [rowVirtualizer]);
|
|
522
548
|
return /*#__PURE__*/jsxRuntime.jsx(StyledTableRow, {
|
|
549
|
+
"data-index": virtualItem?.index,
|
|
550
|
+
ref: measureRef //measure dynamic row height safely
|
|
551
|
+
,
|
|
523
552
|
style: {
|
|
524
553
|
...(rowStyle?.(row) ?? {})
|
|
525
554
|
},
|
|
@@ -578,6 +607,12 @@ function logDevelopmentWarningOfPropUse(deprecatedProps) {
|
|
|
578
607
|
}
|
|
579
608
|
}
|
|
580
609
|
}
|
|
610
|
+
const isFirefox = () => {
|
|
611
|
+
return typeof window !== 'undefined' && navigator.userAgent.indexOf('Firefox') !== -1;
|
|
612
|
+
};
|
|
613
|
+
const getMeasureElementHandler = () => {
|
|
614
|
+
return isFirefox() ? undefined : element => element?.getBoundingClientRect().height;
|
|
615
|
+
};
|
|
581
616
|
|
|
582
617
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
583
618
|
function EdsDataGridInner({
|
|
@@ -890,7 +925,9 @@ function EdsDataGridInner({
|
|
|
890
925
|
const virtualizer = reactVirtual.useVirtualizer({
|
|
891
926
|
count: table.getRowModel().rows.length,
|
|
892
927
|
getScrollElement: () => parentRef.current,
|
|
893
|
-
estimateSize
|
|
928
|
+
estimateSize,
|
|
929
|
+
//measure dynamic row height, except in firefox because it measures table border height incorrectly
|
|
930
|
+
measureElement: getMeasureElementHandler()
|
|
894
931
|
});
|
|
895
932
|
if (rowVirtualizerInstanceRef) rowVirtualizerInstanceRef.current = virtualizer;
|
|
896
933
|
|
|
@@ -977,6 +1014,8 @@ function EdsDataGridInner({
|
|
|
977
1014
|
}), virtualRows.map(virtualItem => {
|
|
978
1015
|
const row = table.getRowModel().rows[virtualItem.index];
|
|
979
1016
|
return /*#__PURE__*/jsxRuntime.jsx(TableRow, {
|
|
1017
|
+
virtualItem: virtualItem,
|
|
1018
|
+
rowVirtualizer: virtualizer,
|
|
980
1019
|
row: row,
|
|
981
1020
|
onContextMenu: onRowContextMenu ? event => onRowContextMenu(row, event) : undefined,
|
|
982
1021
|
onClick: onRowClick ? event => onRowClick(row, event) : undefined,
|
package/dist/esm/EdsDataGrid.js
CHANGED
|
@@ -7,7 +7,7 @@ import { TableProvider } from './EdsDataGridContext.js';
|
|
|
7
7
|
import { TableHeaderRow } from './components/TableHeaderRow.js';
|
|
8
8
|
import { TableFooterRow } from './components/TableFooterRow.js';
|
|
9
9
|
import { TableRow } from './components/TableRow.js';
|
|
10
|
-
import { addPxSuffixIfInputHasNoPrefix, logDevelopmentWarningOfPropUse } from './utils.js';
|
|
10
|
+
import { addPxSuffixIfInputHasNoPrefix, logDevelopmentWarningOfPropUse, getMeasureElementHandler } from './utils.js';
|
|
11
11
|
import { mergeRefs } from '@equinor/eds-utils';
|
|
12
12
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
13
13
|
|
|
@@ -322,7 +322,9 @@ function EdsDataGridInner({
|
|
|
322
322
|
const virtualizer = useVirtualizer({
|
|
323
323
|
count: table.getRowModel().rows.length,
|
|
324
324
|
getScrollElement: () => parentRef.current,
|
|
325
|
-
estimateSize
|
|
325
|
+
estimateSize,
|
|
326
|
+
//measure dynamic row height, except in firefox because it measures table border height incorrectly
|
|
327
|
+
measureElement: getMeasureElementHandler()
|
|
326
328
|
});
|
|
327
329
|
if (rowVirtualizerInstanceRef) rowVirtualizerInstanceRef.current = virtualizer;
|
|
328
330
|
|
|
@@ -409,6 +411,8 @@ function EdsDataGridInner({
|
|
|
409
411
|
}), virtualRows.map(virtualItem => {
|
|
410
412
|
const row = table.getRowModel().rows[virtualItem.index];
|
|
411
413
|
return /*#__PURE__*/jsx(TableRow, {
|
|
414
|
+
virtualItem: virtualItem,
|
|
415
|
+
rowVirtualizer: virtualizer,
|
|
412
416
|
row: row,
|
|
413
417
|
onContextMenu: onRowContextMenu ? event => onRowContextMenu(row, event) : undefined,
|
|
414
418
|
onClick: onRowClick ? event => onRowClick(row, event) : undefined,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Table } from '@equinor/eds-core-react';
|
|
2
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
2
3
|
import styled from 'styled-components';
|
|
3
4
|
import { useTableContext } from '../EdsDataGridContext.js';
|
|
4
5
|
import { TableBodyCell } from './TableBodyCell.js';
|
|
@@ -9,13 +10,42 @@ function TableRow({
|
|
|
9
10
|
onCellClick,
|
|
10
11
|
onClick,
|
|
11
12
|
onDoubleClick,
|
|
12
|
-
onContextMenu
|
|
13
|
+
onContextMenu,
|
|
14
|
+
rowVirtualizer,
|
|
15
|
+
virtualItem
|
|
13
16
|
}) {
|
|
14
17
|
const {
|
|
15
18
|
rowClass,
|
|
16
19
|
rowStyle
|
|
17
20
|
} = useTableContext();
|
|
21
|
+
const isMountedRef = useRef(true);
|
|
22
|
+
|
|
23
|
+
// Set mounted flag to false on unmount to prevent measurements during cleanup
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
return () => {
|
|
26
|
+
isMountedRef.current = false;
|
|
27
|
+
};
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
// Create a stable ref callback that guards against calls during unmount
|
|
31
|
+
const measureRef = useCallback(node => {
|
|
32
|
+
// Only measure if we have a node, the component is still mounted, and we have a virtualizer
|
|
33
|
+
if (node && isMountedRef.current && rowVirtualizer) {
|
|
34
|
+
try {
|
|
35
|
+
rowVirtualizer.measureElement(node);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
// Silently catch any errors during measurement to prevent crashes
|
|
38
|
+
// This can happen if the virtualizer is in an inconsistent state during unmount
|
|
39
|
+
if (process.env.NODE_ENV === 'development') {
|
|
40
|
+
console.warn('Failed to measure element during virtualization:', error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}, [rowVirtualizer]);
|
|
18
45
|
return /*#__PURE__*/jsx(StyledTableRow, {
|
|
46
|
+
"data-index": virtualItem?.index,
|
|
47
|
+
ref: measureRef //measure dynamic row height safely
|
|
48
|
+
,
|
|
19
49
|
style: {
|
|
20
50
|
...(rowStyle?.(row) ?? {})
|
|
21
51
|
},
|
package/dist/esm/utils.js
CHANGED
|
@@ -36,5 +36,11 @@ function logDevelopmentWarningOfPropUse(deprecatedProps) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
+
const isFirefox = () => {
|
|
40
|
+
return typeof window !== 'undefined' && navigator.userAgent.indexOf('Firefox') !== -1;
|
|
41
|
+
};
|
|
42
|
+
const getMeasureElementHandler = () => {
|
|
43
|
+
return isFirefox() ? undefined : element => element?.getBoundingClientRect().height;
|
|
44
|
+
};
|
|
39
45
|
|
|
40
|
-
export { addPxSuffixIfInputHasNoPrefix, isNumberOnlyString, logDevelopmentWarningOfPropUse };
|
|
46
|
+
export { addPxSuffixIfInputHasNoPrefix, getMeasureElementHandler, isFirefox, isNumberOnlyString, logDevelopmentWarningOfPropUse };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React, { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
export type ClickableCellProps = {
|
|
3
|
+
/** Cell content */
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
/** Click handler */
|
|
6
|
+
onClick: () => void;
|
|
7
|
+
/** Accessible label for screen readers */
|
|
8
|
+
ariaLabel: string;
|
|
9
|
+
/** Indicates if the cell is selected */
|
|
10
|
+
isSelected?: boolean;
|
|
11
|
+
} & Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'onClick' | 'children'>;
|
|
12
|
+
export declare function ClickableCell({ children, onClick, ariaLabel, isSelected, ...rest }: ClickableCellProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ClickableCell, type ClickableCellProps } from './ClickableCell';
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { Row } from '@tanstack/react-table';
|
|
2
2
|
import { HTMLAttributes } from 'react';
|
|
3
3
|
import { EdsDataGridProps } from '../EdsDataGridProps';
|
|
4
|
+
import { VirtualItem, Virtualizer } from '@tanstack/react-virtual';
|
|
4
5
|
type Props<T> = {
|
|
5
6
|
row: Row<T>;
|
|
6
7
|
onCellClick?: EdsDataGridProps<T>['onCellClick'];
|
|
8
|
+
rowVirtualizer?: Virtualizer<HTMLDivElement, HTMLTableRowElement>;
|
|
9
|
+
virtualItem?: VirtualItem;
|
|
7
10
|
} & HTMLAttributes<HTMLTableRowElement>;
|
|
8
|
-
export declare function TableRow<T>({ row, onCellClick, onClick, onDoubleClick, onContextMenu, }: Props<T>): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function TableRow<T>({ row, onCellClick, onClick, onDoubleClick, onContextMenu, rowVirtualizer, virtualItem, }: Props<T>): import("react/jsx-runtime").JSX.Element;
|
|
9
12
|
export {};
|
package/dist/types/utils.d.ts
CHANGED
|
@@ -20,3 +20,5 @@ export declare function logDevelopmentWarningOfPropUse(deprecatedProps: Record<s
|
|
|
20
20
|
value: unknown;
|
|
21
21
|
mitigationInfo?: string;
|
|
22
22
|
}>): void;
|
|
23
|
+
export declare const isFirefox: () => boolean;
|
|
24
|
+
export declare const getMeasureElementHandler: () => (element: HTMLTableRowElement) => number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@equinor/eds-data-grid-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "A feature-rich data-grid written in React, implementing the Equinor Design System",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -21,52 +21,48 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@tanstack/react-table": "^8.21.3",
|
|
24
|
-
"@tanstack/react-virtual": "^3.13.
|
|
24
|
+
"@tanstack/react-virtual": "^3.13.12",
|
|
25
25
|
"@equinor/eds-icons": "^0.22.0",
|
|
26
|
-
"@equinor/eds-
|
|
27
|
-
"@equinor/eds-
|
|
26
|
+
"@equinor/eds-utils": "^0.9.0",
|
|
27
|
+
"@equinor/eds-tokens": "0.10.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@rollup/plugin-babel": "^6.0.4",
|
|
31
|
-
"@rollup/plugin-commonjs": "^28.0.
|
|
31
|
+
"@rollup/plugin-commonjs": "^28.0.6",
|
|
32
32
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
33
|
-
"@storybook/addon-a11y": "^
|
|
34
|
-
"@storybook/addon-
|
|
35
|
-
"@storybook/addon-
|
|
36
|
-
"@storybook/
|
|
37
|
-
"@
|
|
38
|
-
"@
|
|
39
|
-
"@storybook/preview-api": "^8.6.12",
|
|
40
|
-
"@storybook/react": "^8.6.12",
|
|
41
|
-
"@storybook/react-vite": "^8.6.12",
|
|
42
|
-
"@testing-library/dom": "^10.4.0",
|
|
43
|
-
"@testing-library/jest-dom": "^6.6.3",
|
|
33
|
+
"@storybook/addon-a11y": "^9.1.5",
|
|
34
|
+
"@storybook/addon-docs": "^9.1.5",
|
|
35
|
+
"@storybook/addon-links": "^9.1.5",
|
|
36
|
+
"@storybook/react-vite": "^9.1.5",
|
|
37
|
+
"@testing-library/dom": "^10.4.1",
|
|
38
|
+
"@testing-library/jest-dom": "^6.8.0",
|
|
44
39
|
"@testing-library/react": "16.3.0",
|
|
45
40
|
"@testing-library/user-event": "^14.6.1",
|
|
46
41
|
"@types/jest": "^29.5.14",
|
|
47
|
-
"@types/node": "^22.
|
|
42
|
+
"@types/node": "^22.18.0",
|
|
48
43
|
"@types/ramda": "^0.30.2",
|
|
49
|
-
"@types/react": "^18.3.
|
|
50
|
-
"@types/react-dom": "^18.3.
|
|
44
|
+
"@types/react": "^18.3.24",
|
|
45
|
+
"@types/react-dom": "^18.3.7",
|
|
51
46
|
"babel-plugin-styled-components": "^2.1.4",
|
|
52
47
|
"jest": "29.7.0",
|
|
53
48
|
"jest-environment-jsdom": "29.7.0",
|
|
54
49
|
"jest-styled-components": "^7.2.0",
|
|
55
50
|
"js-file-download": "^0.4.12",
|
|
56
|
-
"postcss": "^8.5.
|
|
57
|
-
"ramda": "^0.
|
|
51
|
+
"postcss": "^8.5.6",
|
|
52
|
+
"ramda": "^0.31.3",
|
|
58
53
|
"react": "^18.3.1",
|
|
59
54
|
"react-dom": "^18.3.1",
|
|
60
|
-
"react-hook-form": "^7.
|
|
61
|
-
"rollup": "^4.
|
|
55
|
+
"react-hook-form": "^7.62.0",
|
|
56
|
+
"rollup": "^4.50.0",
|
|
62
57
|
"rollup-plugin-delete": "^2.2.0",
|
|
63
58
|
"rollup-plugin-postcss": "^4.0.2",
|
|
64
|
-
"storybook": "^
|
|
65
|
-
"styled-components": "6.1.
|
|
66
|
-
"ts-jest": "29.
|
|
59
|
+
"storybook": "^9.1.5",
|
|
60
|
+
"styled-components": "6.1.19",
|
|
61
|
+
"ts-jest": "29.4.0",
|
|
67
62
|
"ts-node": "10.9.2",
|
|
68
|
-
"tsc-watch": "^6.
|
|
69
|
-
"typescript": "~5.8.3"
|
|
63
|
+
"tsc-watch": "^6.3.1",
|
|
64
|
+
"typescript": "~5.8.3",
|
|
65
|
+
"eslint-plugin-storybook": "9.1.5"
|
|
70
66
|
},
|
|
71
67
|
"homepage": "https://eds.equinor.com",
|
|
72
68
|
"repository": {
|
|
@@ -86,7 +82,7 @@
|
|
|
86
82
|
],
|
|
87
83
|
"scripts": {
|
|
88
84
|
"build": "rollup -c --bundleConfigAsCjs && tsc -p tsconfig.build.json",
|
|
89
|
-
"test": "tsc -p tsconfig.
|
|
85
|
+
"test": "tsc -p tsconfig.test.json && jest",
|
|
90
86
|
"test:watch": "tsc-watch -p tsconfig.test.json --onFirstSuccess \"jest --watch\"",
|
|
91
87
|
"test:update-snapshots": "jest --updateSnapshot",
|
|
92
88
|
"storybook": "storybook dev -p 9000 --ci",
|