@equinor/eds-data-grid-react 0.7.6 → 0.8.0

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.
@@ -59,7 +59,6 @@ function DebouncedInput({
59
59
  label: props.placeholder,
60
60
  children: /*#__PURE__*/jsxRuntime.jsx(edsCoreReact.Input, {
61
61
  type: 'number',
62
- placeholder: '0',
63
62
  value: value,
64
63
  onChange: e => setValue(e.target.valueAsNumber)
65
64
  })
@@ -161,6 +160,34 @@ function Filter({
161
160
  });
162
161
  }
163
162
 
163
+ const ResizeInner = styled__default.default.div.withConfig({
164
+ displayName: "Resizer__ResizeInner",
165
+ componentId: "sc-plcbjs-0"
166
+ })(["width:2px;opacity:0;height:100%;"]);
167
+ const Resizer = styled__default.default.div.withConfig({
168
+ displayName: "Resizer",
169
+ componentId: "sc-plcbjs-1"
170
+ })(["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);
171
+
172
+ const FilterVisibility = styled__default.default.div.withConfig({
173
+ displayName: "TableCell__FilterVisibility",
174
+ componentId: "sc-1g0k23m-0"
175
+ })([""]);
176
+ const TableCell = styled__default.default(edsCoreReact.Table.Cell).withConfig({
177
+ displayName: "TableCell",
178
+ componentId: "sc-1g0k23m-1"
179
+ })(["font-weight:bold;position:", ";top:0;", " ", ";&:hover ", "{background:", ";opacity:1;}", ":not(:focus-within){opacity:", ";}&:hover ", "{opacity:1;}", ":focus-within{opacity:1;}"], p => p.$sticky || p.$pinned ? 'sticky' : 'relative', p => {
180
+ if (p.$pinned) {
181
+ return `${p.$pinned}: ${p.$offset}px;`;
182
+ }
183
+ return '';
184
+ }, p => {
185
+ if (p.$sticky && p.$pinned) return 'z-index: 13';
186
+ if (p.$sticky || p.$pinned) return 'z-index: 12';
187
+ }, ResizeInner, edsTokens.tokens.colors.interactive.primary__hover.rgba, FilterVisibility, ({
188
+ $activeFilter
189
+ }) => $activeFilter ? 1 : 0, FilterVisibility, FilterVisibility);
190
+
164
191
  /* istanbul ignore file */
165
192
 
166
193
  function FilterWrapper({
@@ -189,7 +216,8 @@ function FilterWrapper({
189
216
  return value;
190
217
  };
191
218
  const onChange = react.useCallback(value => column.setFilterValue(value), [column]);
192
- return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
219
+ return /*#__PURE__*/jsxRuntime.jsxs(FilterVisibility, {
220
+ onClick: e => e.stopPropagation(),
193
221
  children: [/*#__PURE__*/jsxRuntime.jsx(edsCoreReact.Button, {
194
222
  "aria-haspopup": true,
195
223
  "aria-expanded": open,
@@ -238,28 +266,14 @@ const SortIndicator = ({
238
266
  }[column.getIsSorted()] ?? null;
239
267
  };
240
268
 
241
- const ResizeInner = styled__default.default.div.withConfig({
242
- displayName: "Resizer__ResizeInner",
243
- componentId: "sc-plcbjs-0"
244
- })(["width:2px;opacity:0;height:100%;"]);
245
- const Resizer = styled__default.default.div.withConfig({
246
- displayName: "Resizer",
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);
249
-
250
- const TableCell = styled__default.default(edsCoreReact.Table.Cell).withConfig({
251
- displayName: "TableCell",
252
- componentId: "sc-1g0k23m-0"
253
- })(["font-weight:bold;position:", ";top:0;", " ", ";&:hover ", "{background:", ";opacity:1;}"], p => p.$sticky || p.$pinned ? 'sticky' : 'relative', p => {
254
- if (p.$pinned) {
255
- return `${p.$pinned}: ${p.$offset}px;`;
256
- }
257
- return '';
258
- }, p => {
259
- if (p.$sticky && p.$pinned) return 'z-index: 13';
260
- if (p.$sticky || p.$pinned) return 'z-index: 12';
261
- }, ResizeInner, edsTokens.tokens.colors.interactive.primary__hover.rgba);
262
-
269
+ const SortButton = styled__default.default.button.withConfig({
270
+ displayName: "TableHeaderCell__SortButton",
271
+ componentId: "sc-1n0j3v0-0"
272
+ })(["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;"]);
273
+ const TableHeaderCellLabel = styled__default.default.div.withConfig({
274
+ displayName: "TableHeaderCell__TableHeaderCellLabel",
275
+ componentId: "sc-1n0j3v0-1"
276
+ })(["display:flex;flex-direction:column;"]);
263
277
  const getSortLabel = sorted => {
264
278
  if (sorted) {
265
279
  return `${sorted}ending`;
@@ -273,12 +287,32 @@ function TableHeaderCell({
273
287
  const ctx = useTableContext();
274
288
  const table = ctx.table;
275
289
  const pinned = header.column.getIsPinned();
290
+ const isFiltered = header.column.getIsFiltered();
291
+ const filterValue = header.column.getFilterValue();
292
+ const hasActiveFilters = react.useMemo(() => {
293
+ if (!isFiltered) return false;
294
+ if (Array.isArray(filterValue)) {
295
+ return filterValue.length > 0 && filterValue.some(v => !!v || v === 0); // avoid empty strings counting
296
+ }
297
+ return !!filterValue;
298
+ }, [isFiltered, filterValue]);
299
+ const canSort = header.column.getCanSort();
300
+ const canFilter = header.column.getCanFilter();
276
301
  const offset = react.useMemo(() => {
277
302
  if (!pinned) {
278
303
  return null;
279
304
  }
280
305
  return pinned === 'left' ? header.getStart() : table.getTotalSize() - header.getStart() - header.getSize();
281
306
  }, [pinned, header, table]);
307
+ const tableCellPadding = react.useMemo(() => {
308
+ if (canSort && canFilter) {
309
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 0';
310
+ }
311
+ if (canSort) {
312
+ return '0';
313
+ }
314
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 var(--eds_table__cell__padding_x, 16px)';
315
+ }, [canSort, canFilter]);
282
316
  return header.isPlaceholder ? /*#__PURE__*/jsxRuntime.jsx(TableCell, {
283
317
  $sticky: ctx.stickyHeader,
284
318
  $offset: offset,
@@ -292,39 +326,39 @@ function TableHeaderCell({
292
326
  $sticky: ctx.stickyHeader,
293
327
  $offset: offset,
294
328
  $pinned: pinned,
329
+ $activeFilter: hasActiveFilters,
295
330
  className: ctx.headerClass ? ctx.headerClass(header.column) : '',
296
331
  "aria-sort": getSortLabel(header.column.getIsSorted()),
297
- onClick: header.column.getToggleSortingHandler(),
298
332
  colSpan: header.colSpan,
299
333
  style: {
300
334
  width: header.getSize(),
301
335
  verticalAlign: ctx.enableColumnFiltering ? 'top' : 'middle',
302
- ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {})
336
+ ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {}),
337
+ padding: tableCellPadding
303
338
  },
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
- })
339
+ children: [canSort ? /*#__PURE__*/jsxRuntime.jsxs(SortButton, {
340
+ tabIndex: -1,
341
+ onClick: header.column.getToggleSortingHandler(),
342
+ "data-testid": `sort-button-${header.id}`,
343
+ children: [/*#__PURE__*/jsxRuntime.jsx(TableHeaderCellLabel, {
344
+ className: "table-header-cell-label",
345
+ children: reactTable.flexRender(header.column.columnDef.header, header.getContext())
314
346
  }), !header.column.columnDef.meta?.customFilterInput && /*#__PURE__*/jsxRuntime.jsx(SortIndicator, {
315
347
  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, {
348
+ })]
349
+ }) : /*#__PURE__*/jsxRuntime.jsx(TableHeaderCellLabel, {
350
+ className: "table-header-cell-label",
351
+ children: reactTable.flexRender(header.column.columnDef.header, header.getContext())
352
+ }), canFilter && !header.column.columnDef.meta?.customFilterInput ?
353
+ /*#__PURE__*/
354
+ // Supressing this warning - div is not interactive, but prevents propagation of events to avoid unintended sorting
355
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
356
+ jsxRuntime.jsx(FilterVisibility, {
327
357
  onClick: e => e.stopPropagation(),
358
+ children: /*#__PURE__*/jsxRuntime.jsx(FilterWrapper, {
359
+ column: header.column
360
+ })
361
+ }) : null, columnResizeMode && /*#__PURE__*/jsxRuntime.jsx(Resizer, {
328
362
  onMouseDown: header.getResizeHandler(),
329
363
  onTouchStart: header.getResizeHandler(),
330
364
  $isResizing: header.column.getIsResizing(),
@@ -550,6 +584,8 @@ function EdsDataGridInner({
550
584
  selectedRows,
551
585
  rowSelectionState,
552
586
  enableColumnFiltering,
587
+ columnFiltersState,
588
+ onColumnFiltersChange,
553
589
  debug,
554
590
  enablePagination,
555
591
  enableSorting,
@@ -636,6 +672,9 @@ function EdsDataGridInner({
636
672
  react.useEffect(() => {
637
673
  setVisible(columnVisibility ?? {});
638
674
  }, [columnVisibility, setVisible]);
675
+ react.useEffect(() => {
676
+ setColumnFilters(columnFiltersState);
677
+ }, [columnFiltersState]);
639
678
  react.useEffect(() => {
640
679
  setColumnPin(s => columnPinState ?? s);
641
680
  }, [columnPinState]);
@@ -716,6 +755,7 @@ function EdsDataGridInner({
716
755
  },
717
756
  state: {
718
757
  sorting,
758
+ columnFilters: columnFilters,
719
759
  columnPinning: columnPin,
720
760
  rowSelection: internalRowSelectionState,
721
761
  columnOrder: columnOrderState,
@@ -772,7 +812,7 @@ function EdsDataGridInner({
772
812
  if (enableColumnFiltering) {
773
813
  options.state.columnFilters = columnFilters;
774
814
  options.state.globalFilter = globalFilter;
775
- options.onColumnFiltersChange = setColumnFilters;
815
+ options.onColumnFiltersChange = onColumnFiltersChange ?? setColumnFilters;
776
816
  options.onGlobalFilterChange = setGlobalFilter;
777
817
  options.getFacetedRowModel = reactTable.getFacetedRowModel();
778
818
  options.getFacetedUniqueValues = reactTable.getFacetedUniqueValues();
@@ -965,6 +1005,7 @@ function EdsDataGridInner({
965
1005
  }, footerGroup.id))
966
1006
  })]
967
1007
  }), externalPaginator ? externalPaginator : enablePagination && /*#__PURE__*/jsxRuntime.jsx("div", {
1008
+ className: "table-pagination",
968
1009
  style: {
969
1010
  maxWidth: `${table.getTotalSize()}px`
970
1011
  },
@@ -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({
@@ -24,6 +24,8 @@ function EdsDataGridInner({
24
24
  selectedRows,
25
25
  rowSelectionState,
26
26
  enableColumnFiltering,
27
+ columnFiltersState,
28
+ onColumnFiltersChange,
27
29
  debug,
28
30
  enablePagination,
29
31
  enableSorting,
@@ -110,6 +112,9 @@ function EdsDataGridInner({
110
112
  useEffect(() => {
111
113
  setVisible(columnVisibility ?? {});
112
114
  }, [columnVisibility, setVisible]);
115
+ useEffect(() => {
116
+ setColumnFilters(columnFiltersState);
117
+ }, [columnFiltersState]);
113
118
  useEffect(() => {
114
119
  setColumnPin(s => columnPinState ?? s);
115
120
  }, [columnPinState]);
@@ -190,6 +195,7 @@ function EdsDataGridInner({
190
195
  },
191
196
  state: {
192
197
  sorting,
198
+ columnFilters: columnFilters,
193
199
  columnPinning: columnPin,
194
200
  rowSelection: internalRowSelectionState,
195
201
  columnOrder: columnOrderState,
@@ -246,7 +252,7 @@ function EdsDataGridInner({
246
252
  if (enableColumnFiltering) {
247
253
  options.state.columnFilters = columnFilters;
248
254
  options.state.globalFilter = globalFilter;
249
- options.onColumnFiltersChange = setColumnFilters;
255
+ options.onColumnFiltersChange = onColumnFiltersChange ?? setColumnFilters;
250
256
  options.onGlobalFilterChange = setGlobalFilter;
251
257
  options.getFacetedRowModel = getFacetedRowModel();
252
258
  options.getFacetedUniqueValues = getFacetedUniqueValues();
@@ -439,6 +445,7 @@ function EdsDataGridInner({
439
445
  }, footerGroup.id))
440
446
  })]
441
447
  }), externalPaginator ? externalPaginator : enablePagination && /*#__PURE__*/jsx("div", {
448
+ className: "table-pagination",
442
449
  style: {
443
450
  maxWidth: `${table.getTotalSize()}px`
444
451
  },
@@ -28,7 +28,6 @@ function DebouncedInput({
28
28
  label: props.placeholder,
29
29
  children: /*#__PURE__*/jsx(Input, {
30
30
  type: 'number',
31
- placeholder: '0',
32
31
  value: value,
33
32
  onChange: e => setValue(e.target.valueAsNumber)
34
33
  })
@@ -4,7 +4,8 @@ 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 { FilterVisibility } from './TableCell.js';
8
+ import { jsxs, jsx } from 'react/jsx-runtime';
8
9
 
9
10
  /* istanbul ignore file */
10
11
 
@@ -34,7 +35,8 @@ function FilterWrapper({
34
35
  return value;
35
36
  };
36
37
  const onChange = useCallback(value => column.setFilterValue(value), [column]);
37
- return /*#__PURE__*/jsxs(Fragment, {
38
+ return /*#__PURE__*/jsxs(FilterVisibility, {
39
+ onClick: e => e.stopPropagation(),
38
40
  children: [/*#__PURE__*/jsx(Button, {
39
41
  "aria-haspopup": true,
40
42
  "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 = ({
@@ -3,10 +3,14 @@ import { tokens } from '@equinor/eds-tokens';
3
3
  import styled from 'styled-components';
4
4
  import { ResizeInner } from './Resizer.js';
5
5
 
6
+ const FilterVisibility = styled.div.withConfig({
7
+ displayName: "TableCell__FilterVisibility",
8
+ componentId: "sc-1g0k23m-0"
9
+ })([""]);
6
10
  const TableCell = styled(Table.Cell).withConfig({
7
11
  displayName: "TableCell",
8
- componentId: "sc-1g0k23m-0"
9
- })(["font-weight:bold;position:", ";top:0;", " ", ";&:hover ", "{background:", ";opacity:1;}"], p => p.$sticky || p.$pinned ? 'sticky' : 'relative', p => {
12
+ componentId: "sc-1g0k23m-1"
13
+ })(["font-weight:bold;position:", ";top:0;", " ", ";&:hover ", "{background:", ";opacity:1;}", ":not(:focus-within){opacity:", ";}&:hover ", "{opacity:1;}", ":focus-within{opacity:1;}"], p => p.$sticky || p.$pinned ? 'sticky' : 'relative', p => {
10
14
  if (p.$pinned) {
11
15
  return `${p.$pinned}: ${p.$offset}px;`;
12
16
  }
@@ -14,6 +18,8 @@ const TableCell = styled(Table.Cell).withConfig({
14
18
  }, p => {
15
19
  if (p.$sticky && p.$pinned) return 'z-index: 13';
16
20
  if (p.$sticky || p.$pinned) return 'z-index: 12';
17
- }, ResizeInner, tokens.colors.interactive.primary__hover.rgba);
21
+ }, ResizeInner, tokens.colors.interactive.primary__hover.rgba, FilterVisibility, ({
22
+ $activeFilter
23
+ }) => $activeFilter ? 1 : 0, FilterVisibility, FilterVisibility);
18
24
 
19
- export { TableCell };
25
+ export { FilterVisibility, TableCell };
@@ -4,9 +4,18 @@ import { useMemo } from 'react';
4
4
  import { FilterWrapper } from './FilterWrapper.js';
5
5
  import { SortIndicator } from './SortIndicator.js';
6
6
  import { Resizer, ResizeInner } from './Resizer.js';
7
- import { TableCell } from './TableCell.js';
8
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+ import { TableCell, FilterVisibility } from './TableCell.js';
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,32 @@ function TableHeaderCell({
20
29
  const ctx = useTableContext();
21
30
  const table = ctx.table;
22
31
  const pinned = header.column.getIsPinned();
32
+ const isFiltered = header.column.getIsFiltered();
33
+ const filterValue = header.column.getFilterValue();
34
+ const hasActiveFilters = useMemo(() => {
35
+ if (!isFiltered) return false;
36
+ if (Array.isArray(filterValue)) {
37
+ return filterValue.length > 0 && filterValue.some(v => !!v || v === 0); // avoid empty strings counting
38
+ }
39
+ return !!filterValue;
40
+ }, [isFiltered, filterValue]);
41
+ const canSort = header.column.getCanSort();
42
+ const canFilter = header.column.getCanFilter();
23
43
  const offset = useMemo(() => {
24
44
  if (!pinned) {
25
45
  return null;
26
46
  }
27
47
  return pinned === 'left' ? header.getStart() : table.getTotalSize() - header.getStart() - header.getSize();
28
48
  }, [pinned, header, table]);
49
+ const tableCellPadding = useMemo(() => {
50
+ if (canSort && canFilter) {
51
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 0';
52
+ }
53
+ if (canSort) {
54
+ return '0';
55
+ }
56
+ return '0 var(--eds_table__cell__padding_x, 16px) 0 var(--eds_table__cell__padding_x, 16px)';
57
+ }, [canSort, canFilter]);
29
58
  return header.isPlaceholder ? /*#__PURE__*/jsx(TableCell, {
30
59
  $sticky: ctx.stickyHeader,
31
60
  $offset: offset,
@@ -39,39 +68,39 @@ function TableHeaderCell({
39
68
  $sticky: ctx.stickyHeader,
40
69
  $offset: offset,
41
70
  $pinned: pinned,
71
+ $activeFilter: hasActiveFilters,
42
72
  className: ctx.headerClass ? ctx.headerClass(header.column) : '',
43
73
  "aria-sort": getSortLabel(header.column.getIsSorted()),
44
- onClick: header.column.getToggleSortingHandler(),
45
74
  colSpan: header.colSpan,
46
75
  style: {
47
76
  width: header.getSize(),
48
77
  verticalAlign: ctx.enableColumnFiltering ? 'top' : 'middle',
49
- ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {})
78
+ ...(ctx.headerStyle ? ctx.headerStyle(header.column) : {}),
79
+ padding: tableCellPadding
50
80
  },
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
- })
81
+ children: [canSort ? /*#__PURE__*/jsxs(SortButton, {
82
+ tabIndex: -1,
83
+ onClick: header.column.getToggleSortingHandler(),
84
+ "data-testid": `sort-button-${header.id}`,
85
+ children: [/*#__PURE__*/jsx(TableHeaderCellLabel, {
86
+ className: "table-header-cell-label",
87
+ children: flexRender(header.column.columnDef.header, header.getContext())
61
88
  }), !header.column.columnDef.meta?.customFilterInput && /*#__PURE__*/jsx(SortIndicator, {
62
89
  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, {
90
+ })]
91
+ }) : /*#__PURE__*/jsx(TableHeaderCellLabel, {
92
+ className: "table-header-cell-label",
93
+ children: flexRender(header.column.columnDef.header, header.getContext())
94
+ }), canFilter && !header.column.columnDef.meta?.customFilterInput ?
95
+ /*#__PURE__*/
96
+ // Supressing this warning - div is not interactive, but prevents propagation of events to avoid unintended sorting
97
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions
98
+ jsx(FilterVisibility, {
74
99
  onClick: e => e.stopPropagation(),
100
+ children: /*#__PURE__*/jsx(FilterWrapper, {
101
+ column: header.column
102
+ })
103
+ }) : null, columnResizeMode && /*#__PURE__*/jsx(Resizer, {
75
104
  onMouseDown: header.getResizeHandler(),
76
105
  onTouchStart: header.getResizeHandler(),
77
106
  $isResizing: header.column.getIsResizing(),
@@ -1,6 +1,6 @@
1
1
  import { HTMLAttributes, ForwardedRef } from 'react';
2
2
  import { EdsDataGridProps } from './EdsDataGridProps';
3
- declare function EdsDataGridInner<T>({ rows, columns, columnResizeMode, pageSize, rowSelection, enableRowSelection, enableMultiRowSelection, enableSubRowSelection, selectedRows, rowSelectionState, enableColumnFiltering, debug, enablePagination, enableSorting, stickyHeader, stickyFooter, onSelectRow, onRowSelectionChange, caption, enableVirtual, virtualHeight, columnVisibility, columnVisibilityChange, emptyMessage, columnOrder, cellClass, cellStyle, rowClass, rowStyle, headerClass, headerStyle, footerClass, footerStyle, externalPaginator, onSortingChange, manualSorting, sortingState, columnPinState, scrollbarHorizontal, width, minWidth, height, getRowId, rowVirtualizerInstanceRef, tableInstanceRef, columnSizing, onColumnResize, expansionState, setExpansionState, getSubRows, defaultColumn, onRowContextMenu, onRowClick, onRowDoubleClick, onCellClick, enableFooter, enableSortingRemoval, ...rest }: EdsDataGridProps<T> & HTMLAttributes<HTMLDivElement>, ref: ForwardedRef<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
3
+ declare function EdsDataGridInner<T>({ rows, columns, columnResizeMode, pageSize, rowSelection, enableRowSelection, enableMultiRowSelection, enableSubRowSelection, selectedRows, rowSelectionState, enableColumnFiltering, columnFiltersState, onColumnFiltersChange, debug, enablePagination, enableSorting, stickyHeader, stickyFooter, onSelectRow, onRowSelectionChange, caption, enableVirtual, virtualHeight, columnVisibility, columnVisibilityChange, emptyMessage, columnOrder, cellClass, cellStyle, rowClass, rowStyle, headerClass, headerStyle, footerClass, footerStyle, externalPaginator, onSortingChange, manualSorting, sortingState, columnPinState, scrollbarHorizontal, width, minWidth, height, getRowId, rowVirtualizerInstanceRef, tableInstanceRef, columnSizing, onColumnResize, expansionState, setExpansionState, getSubRows, defaultColumn, onRowContextMenu, onRowClick, onRowDoubleClick, onCellClick, enableFooter, enableSortingRemoval, ...rest }: EdsDataGridProps<T> & HTMLAttributes<HTMLDivElement>, ref: ForwardedRef<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
4
4
  export declare const EdsDataGrid: <T>(props: EdsDataGridProps<T> & HTMLAttributes<HTMLDivElement> & {
5
5
  ref?: ForwardedRef<HTMLDivElement>;
6
6
  }) => ReturnType<typeof EdsDataGridInner>;
@@ -1,4 +1,4 @@
1
- import { Cell, Column, ColumnDef, ColumnPinningState, ColumnResizeMode, ColumnSizingState, ExpandedState, OnChangeFn, Row, RowSelectionState, SortingState, Table, TableOptions } from '@tanstack/react-table';
1
+ import { Cell, Column, ColumnDef, ColumnFilter, ColumnPinningState, ColumnResizeMode, ColumnSizingState, ExpandedState, OnChangeFn, Row, RowSelectionState, SortingState, Table, TableOptions } from '@tanstack/react-table';
2
2
  import { Virtualizer } from '@tanstack/react-virtual';
3
3
  import { CSSProperties, MouseEvent, MutableRefObject, ReactElement } from 'react';
4
4
  type BaseProps<T> = {
@@ -184,6 +184,16 @@ type FilterProps = {
184
184
  * @default false
185
185
  */
186
186
  enableColumnFiltering?: boolean;
187
+ /**
188
+ * Initial filter state
189
+ * @default undefined
190
+ */
191
+ columnFiltersState?: Array<ColumnFilter>;
192
+ /**
193
+ * Callback for when the filter state changes
194
+ * @default undefined
195
+ */
196
+ onColumnFiltersChange?: OnChangeFn<Array<ColumnFilter>>;
187
197
  };
188
198
  type HandlersProps<T> = {
189
199
  /**
@@ -1,4 +1,5 @@
1
1
  import { ColumnPinningPosition } from '@tanstack/react-table';
2
+ export declare const FilterVisibility: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
2
3
  export declare const TableCell: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<(Omit<{
3
4
  variant?: import("@equinor/eds-core-react/dist/types/components/Table/Table.types").Variants;
4
5
  color?: import("@equinor/eds-core-react/dist/types/components/Table/Table.types").Colors;
@@ -15,4 +16,5 @@ export declare const TableCell: import("styled-components/dist/types").IStyledCo
15
16
  $sticky: boolean;
16
17
  $pinned: ColumnPinningPosition;
17
18
  $offset: number;
19
+ $activeFilter?: boolean;
18
20
  }>> & string & Omit<import("react").ForwardRefExoticComponent<import("@equinor/eds-core-react").CellProps & import("react").RefAttributes<HTMLTableCellElement>>, keyof import("react").Component<any, {}, any>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/eds-data-grid-react",
3
- "version": "0.7.6",
3
+ "version": "0.8.0",
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.13.2",
23
+ "@tanstack/react-table": "^8.21.3",
24
+ "@tanstack/react-virtual": "^3.13.6",
25
25
  "@equinor/eds-icons": "^0.22.0",
26
- "@equinor/eds-utils": "^0.8.7",
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
44
  "@testing-library/react": "16.3.0",
45
- "@testing-library/user-event": "^14.5.2",
45
+ "@testing-library/user-event": "^14.6.1",
46
46
  "@types/jest": "^29.5.14",
47
- "@types/node": "^22.13.14",
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",
64
+ "storybook": "^8.6.12",
65
65
  "styled-components": "6.1.17",
66
- "ts-jest": "29.2.5",
66
+ "ts-jest": "29.3.2",
67
67
  "ts-node": "10.9.2",
68
68
  "tsc-watch": "^6.2.1",
69
- "typescript": "~5.8.2"
69
+ "typescript": "~5.8.3"
70
70
  },
71
71
  "homepage": "https://eds.equinor.com",
72
72
  "repository": {