@equinor/eds-data-grid-react 0.7.5 → 0.7.7

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.
@@ -189,7 +189,7 @@ function FilterWrapper({
189
189
  return value;
190
190
  };
191
191
  const onChange = react.useCallback(value => column.setFilterValue(value), [column]);
192
- return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
192
+ return /*#__PURE__*/jsxRuntime.jsxs("span", {
193
193
  children: [/*#__PURE__*/jsxRuntime.jsx(edsCoreReact.Button, {
194
194
  "aria-haspopup": true,
195
195
  "aria-expanded": open,
@@ -245,7 +245,7 @@ const ResizeInner = styled__default.default.div.withConfig({
245
245
  const Resizer = styled__default.default.div.withConfig({
246
246
  displayName: "Resizer",
247
247
  componentId: "sc-plcbjs-1"
248
- })(["transform:", ";", "{opacity:", ";}position:absolute;right:0;top:0;height:100%;width:5px;cursor:col-resize;user-select:none;touch-action:none;display:flex;justify-content:flex-end;"], props => props.$columnResizeMode === 'onEnd' ? 'translateX(0px)' : 'none', ResizeInner, props => props.$isResizing ? 1 : 0);
248
+ })(["transform:", ";", "{opacity:", ";}position:absolute;right:0;top:0;height:100%;width:5px;cursor:col-resize;user-select:none;touch-action:none;display:flex;justify-content:flex-end;z-index:1;"], props => props.$columnResizeMode === 'onEnd' ? 'translateX(0px)' : 'none', ResizeInner, props => props.$isResizing ? 1 : 0);
249
249
 
250
250
  const TableCell = styled__default.default(edsCoreReact.Table.Cell).withConfig({
251
251
  displayName: "TableCell",
@@ -260,6 +260,14 @@ const TableCell = styled__default.default(edsCoreReact.Table.Cell).withConfig({
260
260
  if (p.$sticky || p.$pinned) return 'z-index: 12';
261
261
  }, ResizeInner, edsTokens.tokens.colors.interactive.primary__hover.rgba);
262
262
 
263
+ const SortButton = styled__default.default.button.withConfig({
264
+ displayName: "TableHeaderCell__SortButton",
265
+ componentId: "sc-1n0j3v0-0"
266
+ })(["cursor:pointer;height:100%;width:calc(100% - 5px);display:flex;flex-direction:row;align-items:center;background:transparent;border:none;padding-left:var(--eds_table__cell__padding_x,16px);padding-right:var(--eds_table__cell__padding_x,16px);margin:0;outline:none;color:inherit;text-align:left;font:inherit;"]);
267
+ const TableHeaderCellLabel = styled__default.default.div.withConfig({
268
+ displayName: "TableHeaderCell__TableHeaderCellLabel",
269
+ componentId: "sc-1n0j3v0-1"
270
+ })(["display:flex;flex-direction:column;"]);
263
271
  const getSortLabel = sorted => {
264
272
  if (sorted) {
265
273
  return `${sorted}ending`;
@@ -273,12 +281,23 @@ function TableHeaderCell({
273
281
  const ctx = useTableContext();
274
282
  const table = ctx.table;
275
283
  const pinned = header.column.getIsPinned();
284
+ const canSort = header.column.getCanSort();
285
+ const canFilter = header.column.getCanFilter();
276
286
  const offset = react.useMemo(() => {
277
287
  if (!pinned) {
278
288
  return null;
279
289
  }
280
290
  return pinned === 'left' ? header.getStart() : table.getTotalSize() - header.getStart() - header.getSize();
281
291
  }, [pinned, header, table]);
292
+ const tableCellPadding = react.useMemo(() => {
293
+ if (canSort && canFilter) {
294
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 0';
295
+ }
296
+ if (canSort) {
297
+ return '0';
298
+ }
299
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 var(--eds_table__cell__padding_x, 16px)';
300
+ }, [canSort, canFilter]);
282
301
  return header.isPlaceholder ? /*#__PURE__*/jsxRuntime.jsx(TableCell, {
283
302
  $sticky: ctx.stickyHeader,
284
303
  $offset: offset,
@@ -294,37 +313,29 @@ function TableHeaderCell({
294
313
  $pinned: pinned,
295
314
  className: ctx.headerClass ? ctx.headerClass(header.column) : '',
296
315
  "aria-sort": getSortLabel(header.column.getIsSorted()),
297
- onClick: header.column.getToggleSortingHandler(),
298
316
  colSpan: header.colSpan,
299
317
  style: {
300
318
  width: header.getSize(),
301
319
  verticalAlign: ctx.enableColumnFiltering ? 'top' : 'middle',
302
- ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {})
320
+ ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {}),
321
+ padding: tableCellPadding
303
322
  },
304
- children: [/*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
305
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
306
- style: {
307
- display: 'flex',
308
- flexDirection: 'column'
309
- },
310
- children: /*#__PURE__*/jsxRuntime.jsx("span", {
311
- className: "table-header-cell-label",
312
- children: reactTable.flexRender(header.column.columnDef.header, header.getContext())
313
- })
323
+ children: [canSort ? /*#__PURE__*/jsxRuntime.jsxs(SortButton, {
324
+ tabIndex: -1,
325
+ onClick: header.column.getToggleSortingHandler(),
326
+ "data-testid": `sort-button-${header.id}`,
327
+ children: [/*#__PURE__*/jsxRuntime.jsx(TableHeaderCellLabel, {
328
+ className: "table-header-cell-label",
329
+ children: reactTable.flexRender(header.column.columnDef.header, header.getContext())
314
330
  }), !header.column.columnDef.meta?.customFilterInput && /*#__PURE__*/jsxRuntime.jsx(SortIndicator, {
315
331
  column: header.column
316
- }), header.column.getCanFilter() && !header.column.columnDef.meta?.customFilterInput ?
317
- /*#__PURE__*/
318
- // Supressing this warning - div is not interactive, but prevents propagation of events to avoid unintended sorting
319
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
320
- jsxRuntime.jsx("div", {
321
- onClick: e => e.stopPropagation(),
322
- children: /*#__PURE__*/jsxRuntime.jsx(FilterWrapper, {
323
- column: header.column
324
- })
325
- }) : null]
326
- }), columnResizeMode && /*#__PURE__*/jsxRuntime.jsx(Resizer, {
327
- onClick: e => e.stopPropagation(),
332
+ })]
333
+ }) : /*#__PURE__*/jsxRuntime.jsx(TableHeaderCellLabel, {
334
+ className: "table-header-cell-label",
335
+ children: reactTable.flexRender(header.column.columnDef.header, header.getContext())
336
+ }), canFilter && !header.column.columnDef.meta?.customFilterInput ? /*#__PURE__*/jsxRuntime.jsx(FilterWrapper, {
337
+ column: header.column
338
+ }) : null, columnResizeMode && /*#__PURE__*/jsxRuntime.jsx(Resizer, {
328
339
  onMouseDown: header.getResizeHandler(),
329
340
  onTouchStart: header.getResizeHandler(),
330
341
  $isResizing: header.column.getIsResizing(),
@@ -845,6 +856,14 @@ function EdsDataGridInner({
845
856
  estimateSize
846
857
  });
847
858
  if (rowVirtualizerInstanceRef) rowVirtualizerInstanceRef.current = virtualizer;
859
+
860
+ // Add effect to recalculate virtualization when density changes
861
+ react.useEffect(() => {
862
+ if (enableVirtual && virtualizer) {
863
+ // Force the virtualizer to recalculate when density changes
864
+ virtualizer.measure();
865
+ }
866
+ }, [density, enableVirtual, virtualizer]);
848
867
  const virtualRows = virtualizer.getVirtualItems();
849
868
  const paddingTop = virtualRows.length ? virtualRows[0].start : 0;
850
869
  const paddingBottom = virtualRows.length ? virtualizer.getTotalSize() - virtualRows[virtualRows.length - 1].end : 0;
@@ -957,6 +976,7 @@ function EdsDataGridInner({
957
976
  }, footerGroup.id))
958
977
  })]
959
978
  }), externalPaginator ? externalPaginator : enablePagination && /*#__PURE__*/jsxRuntime.jsx("div", {
979
+ className: "table-pagination",
960
980
  style: {
961
981
  maxWidth: `${table.getTotalSize()}px`
962
982
  },
@@ -1,5 +1,5 @@
1
- import { Typography, useEds, Table, Pagination } from '@equinor/eds-core-react';
2
- import { getExpandedRowModel, getCoreRowModel, getSortedRowModel, getFacetedRowModel, getFacetedUniqueValues, getFacetedMinMaxValues, getFilteredRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
1
+ import { useEds, Table, Pagination, Typography } from '@equinor/eds-core-react';
2
+ import { getSortedRowModel, getCoreRowModel, getExpandedRowModel, getFacetedRowModel, getFacetedUniqueValues, getFacetedMinMaxValues, getFilteredRowModel, getPaginationRowModel, useReactTable } from '@tanstack/react-table';
3
3
  import { useVirtualizer } from '@tanstack/react-virtual';
4
4
  import { forwardRef, useState, useEffect, useMemo, useRef, useCallback } from 'react';
5
5
  import styled from 'styled-components';
@@ -9,7 +9,7 @@ import { TableFooterRow } from './components/TableFooterRow.js';
9
9
  import { TableRow } from './components/TableRow.js';
10
10
  import { addPxSuffixIfInputHasNoPrefix, logDevelopmentWarningOfPropUse } from './utils.js';
11
11
  import { mergeRefs } from '@equinor/eds-utils';
12
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
12
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
13
 
14
14
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
15
15
  function EdsDataGridInner({
@@ -319,6 +319,14 @@ function EdsDataGridInner({
319
319
  estimateSize
320
320
  });
321
321
  if (rowVirtualizerInstanceRef) rowVirtualizerInstanceRef.current = virtualizer;
322
+
323
+ // Add effect to recalculate virtualization when density changes
324
+ useEffect(() => {
325
+ if (enableVirtual && virtualizer) {
326
+ // Force the virtualizer to recalculate when density changes
327
+ virtualizer.measure();
328
+ }
329
+ }, [density, enableVirtual, virtualizer]);
322
330
  const virtualRows = virtualizer.getVirtualItems();
323
331
  const paddingTop = virtualRows.length ? virtualRows[0].start : 0;
324
332
  const paddingBottom = virtualRows.length ? virtualizer.getTotalSize() - virtualRows[virtualRows.length - 1].end : 0;
@@ -431,6 +439,7 @@ function EdsDataGridInner({
431
439
  }, footerGroup.id))
432
440
  })]
433
441
  }), externalPaginator ? externalPaginator : enablePagination && /*#__PURE__*/jsx("div", {
442
+ className: "table-pagination",
434
443
  style: {
435
444
  maxWidth: `${table.getTotalSize()}px`
436
445
  },
@@ -4,7 +4,7 @@ import { filter_alt_active, filter_alt } from '@equinor/eds-icons';
4
4
  import { tokens } from '@equinor/eds-tokens';
5
5
  import { Filter } from './Filter.js';
6
6
  import { useTableContext } from '../EdsDataGridContext.js';
7
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
7
+ import { jsxs, jsx } from 'react/jsx-runtime';
8
8
 
9
9
  /* istanbul ignore file */
10
10
 
@@ -34,7 +34,7 @@ function FilterWrapper({
34
34
  return value;
35
35
  };
36
36
  const onChange = useCallback(value => column.setFilterValue(value), [column]);
37
- return /*#__PURE__*/jsxs(Fragment, {
37
+ return /*#__PURE__*/jsxs("span", {
38
38
  children: [/*#__PURE__*/jsx(Button, {
39
39
  "aria-haspopup": true,
40
40
  "aria-expanded": open,
@@ -7,6 +7,6 @@ const ResizeInner = styled.div.withConfig({
7
7
  const Resizer = styled.div.withConfig({
8
8
  displayName: "Resizer",
9
9
  componentId: "sc-plcbjs-1"
10
- })(["transform:", ";", "{opacity:", ";}position:absolute;right:0;top:0;height:100%;width:5px;cursor:col-resize;user-select:none;touch-action:none;display:flex;justify-content:flex-end;"], props => props.$columnResizeMode === 'onEnd' ? 'translateX(0px)' : 'none', ResizeInner, props => props.$isResizing ? 1 : 0);
10
+ })(["transform:", ";", "{opacity:", ";}position:absolute;right:0;top:0;height:100%;width:5px;cursor:col-resize;user-select:none;touch-action:none;display:flex;justify-content:flex-end;z-index:1;"], props => props.$columnResizeMode === 'onEnd' ? 'translateX(0px)' : 'none', ResizeInner, props => props.$isResizing ? 1 : 0);
11
11
 
12
12
  export { ResizeInner, Resizer };
@@ -1,5 +1,5 @@
1
1
  import { Icon } from '@equinor/eds-core-react';
2
- import { arrow_up, arrow_down } from '@equinor/eds-icons';
2
+ import { arrow_down, arrow_up } from '@equinor/eds-icons';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4
 
5
5
  const SortIndicator = ({
@@ -5,8 +5,17 @@ import { FilterWrapper } from './FilterWrapper.js';
5
5
  import { SortIndicator } from './SortIndicator.js';
6
6
  import { Resizer, ResizeInner } from './Resizer.js';
7
7
  import { TableCell } from './TableCell.js';
8
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import styled from 'styled-components';
9
+ import { jsx, jsxs } from 'react/jsx-runtime';
9
10
 
11
+ const SortButton = styled.button.withConfig({
12
+ displayName: "TableHeaderCell__SortButton",
13
+ componentId: "sc-1n0j3v0-0"
14
+ })(["cursor:pointer;height:100%;width:calc(100% - 5px);display:flex;flex-direction:row;align-items:center;background:transparent;border:none;padding-left:var(--eds_table__cell__padding_x,16px);padding-right:var(--eds_table__cell__padding_x,16px);margin:0;outline:none;color:inherit;text-align:left;font:inherit;"]);
15
+ const TableHeaderCellLabel = styled.div.withConfig({
16
+ displayName: "TableHeaderCell__TableHeaderCellLabel",
17
+ componentId: "sc-1n0j3v0-1"
18
+ })(["display:flex;flex-direction:column;"]);
10
19
  const getSortLabel = sorted => {
11
20
  if (sorted) {
12
21
  return `${sorted}ending`;
@@ -20,12 +29,23 @@ function TableHeaderCell({
20
29
  const ctx = useTableContext();
21
30
  const table = ctx.table;
22
31
  const pinned = header.column.getIsPinned();
32
+ const canSort = header.column.getCanSort();
33
+ const canFilter = header.column.getCanFilter();
23
34
  const offset = useMemo(() => {
24
35
  if (!pinned) {
25
36
  return null;
26
37
  }
27
38
  return pinned === 'left' ? header.getStart() : table.getTotalSize() - header.getStart() - header.getSize();
28
39
  }, [pinned, header, table]);
40
+ const tableCellPadding = useMemo(() => {
41
+ if (canSort && canFilter) {
42
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 0';
43
+ }
44
+ if (canSort) {
45
+ return '0';
46
+ }
47
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 var(--eds_table__cell__padding_x, 16px)';
48
+ }, [canSort, canFilter]);
29
49
  return header.isPlaceholder ? /*#__PURE__*/jsx(TableCell, {
30
50
  $sticky: ctx.stickyHeader,
31
51
  $offset: offset,
@@ -41,37 +61,29 @@ function TableHeaderCell({
41
61
  $pinned: pinned,
42
62
  className: ctx.headerClass ? ctx.headerClass(header.column) : '',
43
63
  "aria-sort": getSortLabel(header.column.getIsSorted()),
44
- onClick: header.column.getToggleSortingHandler(),
45
64
  colSpan: header.colSpan,
46
65
  style: {
47
66
  width: header.getSize(),
48
67
  verticalAlign: ctx.enableColumnFiltering ? 'top' : 'middle',
49
- ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {})
68
+ ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {}),
69
+ padding: tableCellPadding
50
70
  },
51
- children: [/*#__PURE__*/jsxs(Fragment, {
52
- children: [/*#__PURE__*/jsx("div", {
53
- style: {
54
- display: 'flex',
55
- flexDirection: 'column'
56
- },
57
- children: /*#__PURE__*/jsx("span", {
58
- className: "table-header-cell-label",
59
- children: flexRender(header.column.columnDef.header, header.getContext())
60
- })
71
+ children: [canSort ? /*#__PURE__*/jsxs(SortButton, {
72
+ tabIndex: -1,
73
+ onClick: header.column.getToggleSortingHandler(),
74
+ "data-testid": `sort-button-${header.id}`,
75
+ children: [/*#__PURE__*/jsx(TableHeaderCellLabel, {
76
+ className: "table-header-cell-label",
77
+ children: flexRender(header.column.columnDef.header, header.getContext())
61
78
  }), !header.column.columnDef.meta?.customFilterInput && /*#__PURE__*/jsx(SortIndicator, {
62
79
  column: header.column
63
- }), header.column.getCanFilter() && !header.column.columnDef.meta?.customFilterInput ?
64
- /*#__PURE__*/
65
- // Supressing this warning - div is not interactive, but prevents propagation of events to avoid unintended sorting
66
- // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
67
- jsx("div", {
68
- onClick: e => e.stopPropagation(),
69
- children: /*#__PURE__*/jsx(FilterWrapper, {
70
- column: header.column
71
- })
72
- }) : null]
73
- }), columnResizeMode && /*#__PURE__*/jsx(Resizer, {
74
- onClick: e => e.stopPropagation(),
80
+ })]
81
+ }) : /*#__PURE__*/jsx(TableHeaderCellLabel, {
82
+ className: "table-header-cell-label",
83
+ children: flexRender(header.column.columnDef.header, header.getContext())
84
+ }), canFilter && !header.column.columnDef.meta?.customFilterInput ? /*#__PURE__*/jsx(FilterWrapper, {
85
+ column: header.column
86
+ }) : null, columnResizeMode && /*#__PURE__*/jsx(Resizer, {
75
87
  onMouseDown: header.getResizeHandler(),
76
88
  onTouchStart: header.getResizeHandler(),
77
89
  $isResizing: header.column.getIsResizing(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/eds-data-grid-react",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
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",
@@ -20,53 +20,53 @@
20
20
  "styled-components": ">=5.1"
21
21
  },
22
22
  "dependencies": {
23
- "@tanstack/react-table": "^8.20.6",
24
- "@tanstack/react-virtual": "^3.11.2",
25
- "@equinor/eds-utils": "^0.8.6",
23
+ "@tanstack/react-table": "^8.21.3",
24
+ "@tanstack/react-virtual": "^3.13.6",
26
25
  "@equinor/eds-icons": "^0.22.0",
27
- "@equinor/eds-tokens": "0.9.2"
26
+ "@equinor/eds-tokens": "0.9.2",
27
+ "@equinor/eds-utils": "^0.8.7"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@rollup/plugin-babel": "^6.0.4",
31
- "@rollup/plugin-commonjs": "^28.0.2",
32
- "@rollup/plugin-node-resolve": "^16.0.0",
33
- "@storybook/addon-a11y": "^8.4.7",
34
- "@storybook/addon-actions": "^8.4.7",
35
- "@storybook/addon-docs": "^8.4.7",
36
- "@storybook/addon-essentials": "^8.4.7",
37
- "@storybook/addon-links": "^8.4.7",
38
- "@storybook/blocks": "^8.4.7",
39
- "@storybook/preview-api": "^8.4.7",
40
- "@storybook/react": "^8.4.7",
41
- "@storybook/react-vite": "^8.4.7",
31
+ "@rollup/plugin-commonjs": "^28.0.3",
32
+ "@rollup/plugin-node-resolve": "^16.0.1",
33
+ "@storybook/addon-a11y": "^8.6.12",
34
+ "@storybook/addon-actions": "^8.6.12",
35
+ "@storybook/addon-docs": "^8.6.12",
36
+ "@storybook/addon-essentials": "^8.6.12",
37
+ "@storybook/addon-links": "^8.6.12",
38
+ "@storybook/blocks": "^8.6.12",
39
+ "@storybook/preview-api": "^8.6.12",
40
+ "@storybook/react": "^8.6.12",
41
+ "@storybook/react-vite": "^8.6.12",
42
42
  "@testing-library/dom": "^10.4.0",
43
43
  "@testing-library/jest-dom": "^6.6.3",
44
- "@testing-library/react": "16.1.0",
45
- "@testing-library/user-event": "^14.5.2",
44
+ "@testing-library/react": "16.3.0",
45
+ "@testing-library/user-event": "^14.6.1",
46
46
  "@types/jest": "^29.5.14",
47
- "@types/node": "22.10.5",
47
+ "@types/node": "^22.15.3",
48
48
  "@types/ramda": "^0.30.2",
49
- "@types/react": "^18.3.3",
50
- "@types/react-dom": "^18.3.0",
49
+ "@types/react": "^18.3.20",
50
+ "@types/react-dom": "^18.3.6",
51
51
  "babel-plugin-styled-components": "^2.1.4",
52
52
  "jest": "29.7.0",
53
53
  "jest-environment-jsdom": "29.7.0",
54
54
  "jest-styled-components": "^7.2.0",
55
55
  "js-file-download": "^0.4.12",
56
- "postcss": "^8.4.49",
56
+ "postcss": "^8.5.3",
57
57
  "ramda": "^0.30.1",
58
58
  "react": "^18.3.1",
59
59
  "react-dom": "^18.3.1",
60
- "react-hook-form": "^7.54.2",
61
- "rollup": "^4.29.1",
62
- "rollup-plugin-delete": "^2.1.0",
60
+ "react-hook-form": "^7.56.1",
61
+ "rollup": "^4.40.1",
62
+ "rollup-plugin-delete": "^2.2.0",
63
63
  "rollup-plugin-postcss": "^4.0.2",
64
- "storybook": "^8.4.7",
65
- "styled-components": "6.1.13",
66
- "ts-jest": "29.2.5",
64
+ "storybook": "^8.6.12",
65
+ "styled-components": "6.1.17",
66
+ "ts-jest": "29.3.1",
67
67
  "ts-node": "10.9.2",
68
68
  "tsc-watch": "^6.2.1",
69
- "typescript": "~5.7.2"
69
+ "typescript": "~5.8.3"
70
70
  },
71
71
  "homepage": "https://eds.equinor.com",
72
72
  "repository": {