@navikt/ds-react 8.10.3 → 8.10.4
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/cjs/action-menu/ActionMenu.js +1 -1
- package/cjs/action-menu/ActionMenu.js.map +1 -1
- package/cjs/data/stories/Data.test-data.d.ts +24 -0
- package/cjs/data/stories/Data.test-data.js +1616 -0
- package/cjs/data/stories/Data.test-data.js.map +1 -0
- package/cjs/data/table/column-header/DataTableColumnHeader.d.ts +4 -1
- package/cjs/data/table/column-header/DataTableColumnHeader.js +2 -2
- package/cjs/data/table/column-header/DataTableColumnHeader.js.map +1 -1
- package/cjs/data/table/column-header/useTableColumnResize.d.ts +21 -18
- package/cjs/data/table/column-header/useTableColumnResize.js +7 -25
- package/cjs/data/table/column-header/useTableColumnResize.js.map +1 -1
- package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +6 -0
- package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js +32 -0
- package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -0
- package/cjs/data/table/helpers/collectTableRowEntries.d.ts +4 -4
- package/cjs/data/table/helpers/collectTableRowEntries.js +6 -7
- package/cjs/data/table/helpers/collectTableRowEntries.js.map +1 -1
- package/cjs/data/table/hooks/useColumnOptions.js +18 -5
- package/cjs/data/table/hooks/useColumnOptions.js.map +1 -1
- package/cjs/data/table/hooks/useTableDetailsPanel.d.ts +62 -0
- package/cjs/data/table/hooks/{useTableExpansion.js → useTableDetailsPanel.js} +20 -19
- package/cjs/data/table/hooks/useTableDetailsPanel.js.map +1 -0
- package/cjs/data/table/hooks/useTableItems.d.ts +13 -16
- package/cjs/data/table/hooks/useTableItems.js +9 -8
- package/cjs/data/table/hooks/useTableItems.js.map +1 -1
- package/cjs/data/table/hooks/useTableSelection.d.ts +4 -2
- package/cjs/data/table/hooks/useTableSelection.js +6 -1
- package/cjs/data/table/hooks/useTableSelection.js.map +1 -1
- package/cjs/data/table/index.d.ts +1 -2
- package/cjs/data/table/index.js +22 -12
- package/cjs/data/table/index.js.map +1 -1
- package/cjs/data/table/root/DataTable.types.d.ts +7 -6
- package/cjs/data/table/root/DataTableRoot.context.d.ts +5 -1
- package/cjs/data/table/root/DataTableRoot.context.js.map +1 -1
- package/cjs/data/table/root/DataTableRoot.d.ts +79 -115
- package/cjs/data/table/root/DataTableRoot.js +167 -38
- package/cjs/data/table/root/DataTableRoot.js.map +1 -1
- package/cjs/data/table/root/DataTableRoot.legacy.d.ts +177 -0
- package/cjs/data/table/root/DataTableRoot.legacy.js +104 -0
- package/cjs/data/table/root/DataTableRoot.legacy.js.map +1 -0
- package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.d.ts +6 -0
- package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js +21 -0
- package/cjs/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -0
- package/cjs/data/table/tr/DataTableTr.js +11 -11
- package/cjs/data/table/tr/DataTableTr.js.map +1 -1
- package/cjs/utils/components/dismissablelayer/DismissableLayer.js +1 -1
- package/cjs/utils/components/dismissablelayer/DismissableLayer.js.map +1 -1
- package/cjs/utils/components/floating/Floating.d.ts +16 -1
- package/cjs/utils/components/floating/Floating.js +50 -13
- package/cjs/utils/components/floating/Floating.js.map +1 -1
- package/cjs/utils/components/floating-menu/Menu.js +1 -1
- package/cjs/utils/components/floating-menu/Menu.js.map +1 -1
- package/cjs/utils/helpers/create-strict-context.js +1 -1
- package/cjs/utils/helpers/create-strict-context.js.map +1 -1
- package/cjs/utils/hooks/useControllableState.d.ts +5 -5
- package/cjs/utils/hooks/useControllableState.js.map +1 -1
- package/cjs/utils/hooks/useValueAsRef.js +1 -1
- package/cjs/utils/hooks/useValueAsRef.js.map +1 -1
- package/cjs/utils-external/hooks/useId.js +1 -1
- package/cjs/utils-external/hooks/useId.js.map +1 -1
- package/esm/action-menu/ActionMenu.js +1 -1
- package/esm/action-menu/ActionMenu.js.map +1 -1
- package/esm/data/stories/Data.test-data.d.ts +24 -0
- package/esm/data/stories/Data.test-data.js +1607 -0
- package/esm/data/stories/Data.test-data.js.map +1 -0
- package/esm/data/table/column-header/DataTableColumnHeader.d.ts +4 -1
- package/esm/data/table/column-header/DataTableColumnHeader.js +2 -2
- package/esm/data/table/column-header/DataTableColumnHeader.js.map +1 -1
- package/esm/data/table/column-header/useTableColumnResize.d.ts +21 -18
- package/esm/data/table/column-header/useTableColumnResize.js +7 -25
- package/esm/data/table/column-header/useTableColumnResize.js.map +1 -1
- package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.d.ts +6 -0
- package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js +27 -0
- package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -0
- package/esm/data/table/helpers/collectTableRowEntries.d.ts +4 -4
- package/esm/data/table/helpers/collectTableRowEntries.js +6 -7
- package/esm/data/table/helpers/collectTableRowEntries.js.map +1 -1
- package/esm/data/table/hooks/useColumnOptions.js +18 -5
- package/esm/data/table/hooks/useColumnOptions.js.map +1 -1
- package/esm/data/table/hooks/useTableDetailsPanel.d.ts +62 -0
- package/esm/data/table/hooks/{useTableExpansion.js → useTableDetailsPanel.js} +17 -16
- package/esm/data/table/hooks/useTableDetailsPanel.js.map +1 -0
- package/esm/data/table/hooks/useTableItems.d.ts +13 -16
- package/esm/data/table/hooks/useTableItems.js +9 -8
- package/esm/data/table/hooks/useTableItems.js.map +1 -1
- package/esm/data/table/hooks/useTableSelection.d.ts +4 -2
- package/esm/data/table/hooks/useTableSelection.js +6 -1
- package/esm/data/table/hooks/useTableSelection.js.map +1 -1
- package/esm/data/table/index.d.ts +1 -2
- package/esm/data/table/index.js +21 -1
- package/esm/data/table/index.js.map +1 -1
- package/esm/data/table/root/DataTable.types.d.ts +7 -6
- package/esm/data/table/root/DataTableRoot.context.d.ts +5 -1
- package/esm/data/table/root/DataTableRoot.context.js.map +1 -1
- package/esm/data/table/root/DataTableRoot.d.ts +79 -115
- package/esm/data/table/root/DataTableRoot.js +174 -36
- package/esm/data/table/root/DataTableRoot.js.map +1 -1
- package/esm/data/table/root/DataTableRoot.legacy.d.ts +177 -0
- package/esm/data/table/root/DataTableRoot.legacy.js +59 -0
- package/esm/data/table/root/DataTableRoot.legacy.js.map +1 -0
- package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.d.ts +6 -0
- package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js +16 -0
- package/esm/data/table/sub-row-toggle/DataTableSubRowToggle.js.map +1 -0
- package/esm/data/table/tr/DataTableTr.js +11 -11
- package/esm/data/table/tr/DataTableTr.js.map +1 -1
- package/esm/utils/components/dismissablelayer/DismissableLayer.js +1 -1
- package/esm/utils/components/dismissablelayer/DismissableLayer.js.map +1 -1
- package/esm/utils/components/floating/Floating.d.ts +16 -1
- package/esm/utils/components/floating/Floating.js +48 -13
- package/esm/utils/components/floating/Floating.js.map +1 -1
- package/esm/utils/components/floating-menu/Menu.js +2 -2
- package/esm/utils/components/floating-menu/Menu.js.map +1 -1
- package/esm/utils/helpers/create-strict-context.js +1 -1
- package/esm/utils/helpers/create-strict-context.js.map +1 -1
- package/esm/utils/hooks/useControllableState.d.ts +5 -5
- package/esm/utils/hooks/useControllableState.js.map +1 -1
- package/esm/utils/hooks/useValueAsRef.js +1 -1
- package/esm/utils/hooks/useValueAsRef.js.map +1 -1
- package/esm/utils-external/hooks/useId.js +1 -1
- package/esm/utils-external/hooks/useId.js.map +1 -1
- package/package.json +3 -3
- package/src/action-menu/ActionMenu.tsx +1 -1
- package/src/data/stories/Data.test-data.tsx +1703 -0
- package/src/data/table/column-header/DataTableColumnHeader.tsx +6 -6
- package/src/data/table/column-header/useTableColumnResize.ts +29 -44
- package/src/data/table/details-panel-row/DataTableDetailsPanelRow.tsx +53 -0
- package/src/data/table/helpers/collectTableRowEntries.ts +10 -18
- package/src/data/table/hooks/__tests__/useTableItems.test.ts +14 -7
- package/src/data/table/hooks/__tests__/useTableSelection.test.ts +57 -44
- package/src/data/table/hooks/useColumnOptions.ts +19 -5
- package/src/data/table/hooks/{useTableExpansion.tsx → useTableDetailsPanel.tsx} +81 -45
- package/src/data/table/hooks/useTableItems.ts +27 -36
- package/src/data/table/hooks/useTableSelection.ts +17 -6
- package/src/data/table/index.tsx +5 -3
- package/src/data/table/root/DataTable.types.ts +20 -6
- package/src/data/table/root/DataTableRoot.context.ts +5 -1
- package/src/data/table/root/DataTableRoot.legacy.tsx +297 -0
- package/src/data/table/root/DataTableRoot.tsx +482 -217
- package/src/data/table/sub-row-toggle/DataTableSubRowToggle.tsx +39 -0
- package/src/data/table/tr/DataTableTr.tsx +14 -13
- package/src/utils/components/dismissablelayer/DismissableLayer.tsx +1 -1
- package/src/utils/components/floating/Floating.tsx +56 -13
- package/src/utils/components/floating-menu/Menu.tsx +4 -1
- package/src/utils/helpers/create-strict-context.tsx +1 -1
- package/src/utils/hooks/useControllableState.ts +11 -8
- package/src/utils/hooks/useValueAsRef.ts +1 -1
- package/src/utils-external/hooks/useId.ts +1 -1
- package/cjs/data/table/hooks/useTableExpansion.d.ts +0 -27
- package/cjs/data/table/hooks/useTableExpansion.js.map +0 -1
- package/cjs/data/table/root/DataTableAuto.d.ts +0 -182
- package/cjs/data/table/root/DataTableAuto.js +0 -206
- package/cjs/data/table/root/DataTableAuto.js.map +0 -1
- package/esm/data/table/hooks/useTableExpansion.d.ts +0 -27
- package/esm/data/table/hooks/useTableExpansion.js.map +0 -1
- package/esm/data/table/root/DataTableAuto.d.ts +0 -182
- package/esm/data/table/root/DataTableAuto.js +0 -170
- package/esm/data/table/root/DataTableAuto.js.map +0 -1
- package/src/data/table/root/DataTableAuto.test.tsx +0 -244
- package/src/data/table/root/DataTableAuto.tsx +0 -612
|
@@ -1,45 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
/** biome-ignore-all lint/correctness/useHookAtTopLevel: False positive because of the way forwardRef() is added */
|
|
2
|
+
import React, {
|
|
3
|
+
forwardRef,
|
|
4
|
+
useCallback,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from "react";
|
|
10
|
+
import { Skeleton } from "../../../skeleton";
|
|
2
11
|
import { useId } from "../../../utils-external";
|
|
12
|
+
import { Slot } from "../../../utils/components/slot/Slot";
|
|
3
13
|
import { cl } from "../../../utils/helpers";
|
|
4
14
|
import { useMergeRefs } from "../../../utils/hooks";
|
|
15
|
+
import { DataTableBaseCell } from "../base-cell/DataTableBaseCell";
|
|
16
|
+
import { DataTableColumnHeader } from "../column-header/DataTableColumnHeader";
|
|
17
|
+
import { DataTableDetailsPanelRow } from "../details-panel-row/DataTableDetailsPanelRow";
|
|
18
|
+
import { DataTableEmptyState } from "../empty-state/DataTableEmptyState";
|
|
19
|
+
import { useColumnOptions } from "../hooks/useColumnOptions";
|
|
5
20
|
import {
|
|
6
|
-
|
|
7
|
-
type
|
|
8
|
-
} from "../
|
|
21
|
+
DataTableDetailsPanelProvider,
|
|
22
|
+
type DetailsPanelProps,
|
|
23
|
+
} from "../hooks/useTableDetailsPanel";
|
|
9
24
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
type SubRowsProps,
|
|
26
|
+
TableItemsProvider,
|
|
27
|
+
useTableItems,
|
|
28
|
+
useTableItemsContext,
|
|
29
|
+
} from "../hooks/useTableItems";
|
|
14
30
|
import { useTableKeyboardNav } from "../hooks/useTableKeyboardNav";
|
|
15
31
|
import {
|
|
16
32
|
type SelectionProps,
|
|
17
|
-
|
|
33
|
+
useTableSelection,
|
|
18
34
|
} from "../hooks/useTableSelection";
|
|
35
|
+
import { type TableSortOptions, useTableSort } from "../hooks/useTableSort";
|
|
36
|
+
import { DataTableLoadingState } from "../loading-state/DataTableLoadingState";
|
|
37
|
+
import { DataTableSubRowToggle } from "../sub-row-toggle/DataTableSubRowToggle";
|
|
38
|
+
import { DataTableTbody } from "../tbody/DataTableTbody";
|
|
39
|
+
import { DataTableThead } from "../thead/DataTableThead";
|
|
40
|
+
import { DataTableTr } from "../tr/DataTableTr";
|
|
41
|
+
import type { ColumnDefinitions } from "./DataTable.types";
|
|
19
42
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} from "
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import { DataTableTd, type DataTableTdProps } from "../td/DataTableTd";
|
|
28
|
-
import {
|
|
29
|
-
DataTableTfoot,
|
|
30
|
-
type DataTableTfootProps,
|
|
31
|
-
} from "../tfoot/DataTableTfoot";
|
|
32
|
-
import { DataTableTh, type DataTableThProps } from "../th/DataTableTh";
|
|
33
|
-
import {
|
|
34
|
-
DataTableThead,
|
|
35
|
-
type DataTableTheadProps,
|
|
36
|
-
} from "../thead/DataTableThead";
|
|
37
|
-
import { DataTableTr, type DataTableTrProps } from "../tr/DataTableTr";
|
|
38
|
-
import { DataTableContextProvider } from "./DataTableRoot.context";
|
|
39
|
-
|
|
40
|
-
interface DataTableProps
|
|
41
|
-
extends React.HTMLAttributes<HTMLTableElement>, SelectionProps {
|
|
42
|
-
children: React.ReactNode;
|
|
43
|
+
DataTableContextProvider,
|
|
44
|
+
useDataTableContext,
|
|
45
|
+
} from "./DataTableRoot.context";
|
|
46
|
+
|
|
47
|
+
interface DataTableProps<T>
|
|
48
|
+
extends React.HTMLAttributes<HTMLTableElement>, TableSortOptions {
|
|
49
|
+
children?: never;
|
|
43
50
|
/**
|
|
44
51
|
* Controls vertical cell padding.
|
|
45
52
|
* @default "normal"
|
|
@@ -59,7 +66,7 @@ interface DataTableProps
|
|
|
59
66
|
truncateContent?: boolean; // TODO: Consider making this default false when layout=auto, and maybe disallow it but add a wrap prop on the td-comp.
|
|
60
67
|
/**
|
|
61
68
|
* Enables keyboard navigation for table rows and cells.
|
|
62
|
-
* @default
|
|
69
|
+
* @default true
|
|
63
70
|
*/
|
|
64
71
|
withKeyboardNav?: boolean;
|
|
65
72
|
/**
|
|
@@ -83,215 +90,473 @@ interface DataTableProps
|
|
|
83
90
|
* @default "fixed"
|
|
84
91
|
*/
|
|
85
92
|
layout?: "fixed" | "auto";
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
interface DataTableRootComponent extends React.ForwardRefExoticComponent<
|
|
89
|
-
DataTableProps & React.RefAttributes<HTMLTableElement>
|
|
90
|
-
> {
|
|
91
93
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* <DataTable.Caption>
|
|
97
|
-
* Lorem ipsum
|
|
98
|
-
* </DataTable.Caption
|
|
99
|
-
* </DataTable>
|
|
100
|
-
* ```
|
|
94
|
+
* Defines the columns of the table and how to render them.
|
|
95
|
+
*
|
|
96
|
+
*
|
|
97
|
+
* Each column definition should have a unique `id` (or use the column index as fallback) and a `cell`-renderer function that takes the row data as argument and returns a React node.
|
|
101
98
|
*/
|
|
102
|
-
|
|
99
|
+
columnDefinitions: ColumnDefinitions<T>;
|
|
103
100
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* <DataTable.Thead>
|
|
109
|
-
* ... TODO
|
|
110
|
-
* </DataTable.Thead>
|
|
111
|
-
* </DataTable>
|
|
112
|
-
* ```
|
|
101
|
+
* The data to display in the table.
|
|
102
|
+
*
|
|
103
|
+
*
|
|
104
|
+
* Each object in the array represents a row, and the properties of the object are used to render the cells based on the `columnDefinitions`.
|
|
113
105
|
*/
|
|
114
|
-
|
|
106
|
+
data: T[];
|
|
115
107
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* <DataTable.Tbody>
|
|
121
|
-
* ... TODO
|
|
122
|
-
* </DataTable.Tbody>
|
|
123
|
-
* </DataTable>
|
|
124
|
-
* ```
|
|
108
|
+
* Function to get unique row id from row data.
|
|
109
|
+
*
|
|
110
|
+
*
|
|
111
|
+
* If not provided, the row index will be used as id. This can cause issues if your data changes dynamically, so it's recommended to provide a stable id if possible.
|
|
125
112
|
*/
|
|
126
|
-
|
|
113
|
+
getRowId?: (rowData: T, index: number) => string | number;
|
|
127
114
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* <DataTable>
|
|
132
|
-
* <DataTable.Tr>
|
|
133
|
-
* ... TODO
|
|
134
|
-
* </DataTable.Tr
|
|
135
|
-
* </DataTable>
|
|
136
|
-
* ```
|
|
115
|
+
* Sticky columns that remain visible when horizontally scrolling the table.
|
|
116
|
+
*
|
|
117
|
+
* You can specify 1 sticky column on the left and 1 on the right.
|
|
137
118
|
*/
|
|
138
|
-
|
|
119
|
+
stickyColumns?: {
|
|
120
|
+
first?: "1";
|
|
121
|
+
last?: "1";
|
|
122
|
+
};
|
|
139
123
|
/**
|
|
140
|
-
* @
|
|
141
|
-
* @example
|
|
142
|
-
* ```jsx
|
|
143
|
-
* ```
|
|
124
|
+
* @default true
|
|
144
125
|
*/
|
|
145
|
-
|
|
126
|
+
stickyHeader?: boolean;
|
|
146
127
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* ```jsx
|
|
150
|
-
* <DataTable>
|
|
151
|
-
* <DataTable.Tbody>
|
|
152
|
-
* <DataTable.Td>
|
|
153
|
-
* Lorem ipsum
|
|
154
|
-
* </DataTable.Td>
|
|
155
|
-
* <DataTable.Td>
|
|
156
|
-
* Dolor sit amet
|
|
157
|
-
* </DataTable.Td>
|
|
158
|
-
* </DataTable.Tbody>
|
|
159
|
-
* </DataTable>
|
|
160
|
-
* ```
|
|
128
|
+
* Callback invoked when a data row is clicked.
|
|
129
|
+
* Not called when clicking header, loading, or empty-state rows.
|
|
161
130
|
*/
|
|
162
|
-
|
|
131
|
+
onRowClick?: (
|
|
132
|
+
rowId: string | number,
|
|
133
|
+
event: React.MouseEvent<HTMLTableRowElement>,
|
|
134
|
+
) => void;
|
|
163
135
|
/**
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* ```jsx
|
|
167
|
-
* <DataTable>
|
|
168
|
-
* <DataTable.Tfoot>
|
|
169
|
-
* ...
|
|
170
|
-
* </DataTable.Tfoot>
|
|
171
|
-
* </DataTable>
|
|
172
|
-
* ```
|
|
136
|
+
* Content to render when `data` is empty.
|
|
137
|
+
* Rendered inside a `DataTable.EmptyState` row spanning all columns.
|
|
173
138
|
*/
|
|
174
|
-
|
|
139
|
+
emptyState?: React.ReactNode;
|
|
140
|
+
loading?: {
|
|
141
|
+
/**
|
|
142
|
+
* Shows the table in a loading state.
|
|
143
|
+
*
|
|
144
|
+
* - When `loadingState` is provided, it is rendered inside a `DataTable.LoadingState` row.
|
|
145
|
+
* - When `loadingState` is **not** provided, skeleton placeholder rows are rendered instead.
|
|
146
|
+
* @default false
|
|
147
|
+
*/
|
|
148
|
+
isLoading?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Custom content to render when `isLoading` is `true`.
|
|
151
|
+
* Rendered inside a `DataTable.LoadingState` row spanning all columns.
|
|
152
|
+
* When omitted, skeleton rows are rendered based on `loadingRows`.
|
|
153
|
+
*/
|
|
154
|
+
loadingState?: React.ReactNode;
|
|
155
|
+
/**
|
|
156
|
+
* Number of skeleton rows to render when `isLoading` is `true` and no `loadingState` is provided.
|
|
157
|
+
*
|
|
158
|
+
*
|
|
159
|
+
* If not provided, the rendered content will get a temporarily overlay while loading
|
|
160
|
+
*/
|
|
161
|
+
loadingRows?: number;
|
|
162
|
+
/**
|
|
163
|
+
* Visually hidden label announced to screen readers when skeleton rows are shown.
|
|
164
|
+
* Only used when `isLoading` is `true` and no `loadingState` is provided.
|
|
165
|
+
* @default "Laster innhold"
|
|
166
|
+
*/
|
|
167
|
+
loadingLabel?: string;
|
|
168
|
+
};
|
|
169
|
+
|
|
175
170
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* </DataTable.TBody>
|
|
183
|
-
* </DataTable>
|
|
184
|
-
* ```
|
|
171
|
+
* Function to get sub-rows for a given row, used for nested rows.
|
|
172
|
+
* When provided, an expand toggle column is added automatically.
|
|
173
|
+
*
|
|
174
|
+
*
|
|
175
|
+
* TODO:
|
|
176
|
+
* - Table might need to be implemented with role="treegrid" for a11y when having nested rows.
|
|
185
177
|
*/
|
|
186
|
-
|
|
178
|
+
selection?: SelectionProps;
|
|
179
|
+
subRows?: SubRowsProps<T>;
|
|
180
|
+
detailsPanel?: DetailsPanelProps<T>;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function DataTableInner<T>(
|
|
184
|
+
{
|
|
185
|
+
className,
|
|
186
|
+
id,
|
|
187
|
+
rowDensity = "normal",
|
|
188
|
+
withKeyboardNav = true,
|
|
189
|
+
zebraStripes = false,
|
|
190
|
+
truncateContent = true,
|
|
191
|
+
shouldBlockNavigation,
|
|
192
|
+
layout = "fixed",
|
|
193
|
+
selection,
|
|
194
|
+
data,
|
|
195
|
+
columnDefinitions,
|
|
196
|
+
getRowId,
|
|
197
|
+
stickyColumns,
|
|
198
|
+
stickyHeader = true,
|
|
199
|
+
sort: sortProp,
|
|
200
|
+
defaultSort = [],
|
|
201
|
+
onSortChange,
|
|
202
|
+
onRowClick,
|
|
203
|
+
emptyState,
|
|
204
|
+
loading,
|
|
205
|
+
detailsPanel,
|
|
206
|
+
subRows,
|
|
207
|
+
...rest
|
|
208
|
+
}: DataTableProps<T>,
|
|
209
|
+
forwardedRef: React.ForwardedRef<HTMLTableElement>,
|
|
210
|
+
) {
|
|
211
|
+
const { sortState, onSortClick } = useTableSort({
|
|
212
|
+
defaultSort,
|
|
213
|
+
onSortChange,
|
|
214
|
+
sort: sortProp,
|
|
215
|
+
});
|
|
216
|
+
|
|
187
217
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
* <DataTable>
|
|
192
|
-
* <DataTable.TBody>
|
|
193
|
-
* <DataTable.LoadingState />
|
|
194
|
-
* </DataTable.TBody>
|
|
195
|
-
* </DataTable>
|
|
196
|
-
* ```
|
|
218
|
+
* TODO:
|
|
219
|
+
* - If user currently does not give a getRowsId function, and data is nested (getSubRows)
|
|
220
|
+
* we end up in an infinite loop since the index based ids repeat for children and causes chaos.
|
|
197
221
|
*/
|
|
198
|
-
|
|
222
|
+
const tableItems = useTableItems({
|
|
223
|
+
items: data,
|
|
224
|
+
getRowId: getRowId ?? ((_, index) => index),
|
|
225
|
+
subRows,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const tableSelectionState = useTableSelection({
|
|
229
|
+
selection,
|
|
230
|
+
visibleRowIds: tableItems.visibleRowIds,
|
|
231
|
+
childRowIdsById: tableItems.childRowIdsById,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const { columns, stickySelection } = useColumnOptions<T>(columnDefinitions, {
|
|
235
|
+
stickyColumns,
|
|
236
|
+
selectionMode: tableSelectionState.selection.selectionMode,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const {
|
|
240
|
+
isLoading = false,
|
|
241
|
+
loadingState,
|
|
242
|
+
loadingRows,
|
|
243
|
+
loadingLabel = "Laster innhold",
|
|
244
|
+
} = loading || {};
|
|
245
|
+
|
|
246
|
+
const fullWidthColSpan = useMemo(() => {
|
|
247
|
+
return (
|
|
248
|
+
columns.length +
|
|
249
|
+
(layout === "fixed" ? 1 : 0) +
|
|
250
|
+
(tableSelectionState.selection.selectionMode !== "none" ? 1 : 0) +
|
|
251
|
+
(detailsPanel?.getContent ? 1 : 0)
|
|
252
|
+
);
|
|
253
|
+
}, [
|
|
254
|
+
columns,
|
|
255
|
+
layout,
|
|
256
|
+
tableSelectionState.selection.selectionMode,
|
|
257
|
+
detailsPanel,
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
const tableId = useId(id);
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<DataTableContextProvider
|
|
264
|
+
layout={layout}
|
|
265
|
+
withKeyboardNav={withKeyboardNav}
|
|
266
|
+
selectionState={tableSelectionState}
|
|
267
|
+
stickySelection={stickySelection}
|
|
268
|
+
stickyHeader={stickyHeader}
|
|
269
|
+
tableId={tableId}
|
|
270
|
+
showLoadingSkeletons={isLoading && loadingState == null}
|
|
271
|
+
onRowClick={onRowClick}
|
|
272
|
+
isLoading={isLoading}
|
|
273
|
+
showLoadingOverlay={isLoading && !loadingState && !loadingRows}
|
|
274
|
+
columns={columns}
|
|
275
|
+
fullWidthColSpan={fullWidthColSpan}
|
|
276
|
+
>
|
|
277
|
+
<TableItemsProvider
|
|
278
|
+
itemDetails={tableItems.itemDetails}
|
|
279
|
+
items={tableItems.items}
|
|
280
|
+
onExpandedRowIdsChange={tableItems.onExpandedRowIdsChange}
|
|
281
|
+
isSubRowExpanded={tableItems.isSubRowExpanded}
|
|
282
|
+
>
|
|
283
|
+
<DataTableDetailsPanelProvider detailsPanel={detailsPanel}>
|
|
284
|
+
<TableElementWrapper
|
|
285
|
+
shouldBlockNavigation={shouldBlockNavigation}
|
|
286
|
+
enabled={withKeyboardNav}
|
|
287
|
+
>
|
|
288
|
+
<table
|
|
289
|
+
{...rest}
|
|
290
|
+
ref={forwardedRef}
|
|
291
|
+
className={cl("aksel-data-table", className)}
|
|
292
|
+
data-zebra-stripes={zebraStripes}
|
|
293
|
+
data-truncate-content={truncateContent}
|
|
294
|
+
data-density={rowDensity}
|
|
295
|
+
data-layout={layout}
|
|
296
|
+
data-loading={isLoading || undefined}
|
|
297
|
+
aria-busy={isLoading || undefined}
|
|
298
|
+
>
|
|
299
|
+
<DataTableThead>
|
|
300
|
+
<DataTableTr>
|
|
301
|
+
{columns.map(({ isSticky, colDef }) => {
|
|
302
|
+
const sortEntry = sortState.find(
|
|
303
|
+
(s) => s.columnId === colDef.id,
|
|
304
|
+
);
|
|
305
|
+
const sortDirection = sortEntry?.direction ?? "none";
|
|
306
|
+
return (
|
|
307
|
+
<DataTableColumnHeader
|
|
308
|
+
resizable={colDef.resizable}
|
|
309
|
+
width={colDef.width}
|
|
310
|
+
defaultWidth={colDef.defaultWidth}
|
|
311
|
+
autoWidth={colDef.autoWidth}
|
|
312
|
+
minWidth={colDef.minWidth}
|
|
313
|
+
maxWidth={colDef.maxWidth}
|
|
314
|
+
onWidthChange={colDef.onWidthChange}
|
|
315
|
+
textAlign={colDef.align ?? "left"}
|
|
316
|
+
key={colDef.id}
|
|
317
|
+
isSticky={isSticky}
|
|
318
|
+
sortable={colDef.sortable}
|
|
319
|
+
sortDirection={sortDirection}
|
|
320
|
+
onSortClick={(event) => onSortClick(colDef.id, event)}
|
|
321
|
+
label={colDef.label}
|
|
322
|
+
>
|
|
323
|
+
{colDef.header ?? colDef.label}
|
|
324
|
+
</DataTableColumnHeader>
|
|
325
|
+
);
|
|
326
|
+
})}
|
|
327
|
+
</DataTableTr>
|
|
328
|
+
</DataTableThead>
|
|
329
|
+
|
|
330
|
+
<DataTableTbody>
|
|
331
|
+
<DataTableTBodyContent
|
|
332
|
+
loadingState={loadingState}
|
|
333
|
+
loadingRows={loadingRows}
|
|
334
|
+
loadingLabel={loadingLabel}
|
|
335
|
+
emptyState={emptyState}
|
|
336
|
+
/>
|
|
337
|
+
</DataTableTbody>
|
|
338
|
+
</table>
|
|
339
|
+
</TableElementWrapper>
|
|
340
|
+
</DataTableDetailsPanelProvider>
|
|
341
|
+
</TableItemsProvider>
|
|
342
|
+
</DataTableContextProvider>
|
|
343
|
+
);
|
|
199
344
|
}
|
|
200
345
|
|
|
201
346
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
-
* **NB:** To get sticky headers, you have to set a height restriction on the table container. You can use VStack for this:
|
|
205
|
-
* TODO example
|
|
347
|
+
* Temp optimization to avoid re-renders on every keyboard-move, selection change etc
|
|
206
348
|
*/
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
349
|
+
function TableElementWrapper({
|
|
350
|
+
children,
|
|
351
|
+
enabled,
|
|
352
|
+
shouldBlockNavigation,
|
|
353
|
+
}: {
|
|
354
|
+
children: React.ReactNode;
|
|
355
|
+
shouldBlockNavigation?: (event: KeyboardEvent) => boolean;
|
|
356
|
+
enabled: boolean;
|
|
357
|
+
}) {
|
|
358
|
+
const [applyStickyStyles, setApplyStickyStyles] = useState<boolean>(false);
|
|
359
|
+
|
|
360
|
+
const tableWrapperRef = useRef<HTMLDivElement>(null);
|
|
361
|
+
const tableRef = useRef<HTMLTableElement>(null);
|
|
362
|
+
const rafRef = useRef<number | null>(null);
|
|
363
|
+
const { tabIndex, setTableRef } = useTableKeyboardNav({
|
|
364
|
+
enabled,
|
|
365
|
+
shouldBlockNavigation,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
const mergedTableRefs = useMergeRefs(tableRef, setTableRef);
|
|
369
|
+
|
|
370
|
+
const updateStickyStyles = useCallback(() => {
|
|
371
|
+
if (!tableWrapperRef.current) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const doesWrapperHasScroll =
|
|
376
|
+
tableWrapperRef.current.scrollWidth > tableWrapperRef.current.clientWidth;
|
|
377
|
+
|
|
378
|
+
setApplyStickyStyles(doesWrapperHasScroll);
|
|
379
|
+
}, []);
|
|
380
|
+
|
|
381
|
+
const scheduleStickyStylesUpdate = useCallback(() => {
|
|
382
|
+
if (rafRef.current !== null) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
rafRef.current = requestAnimationFrame(() => {
|
|
387
|
+
rafRef.current = null;
|
|
388
|
+
updateStickyStyles();
|
|
224
389
|
});
|
|
390
|
+
}, [updateStickyStyles]);
|
|
391
|
+
|
|
392
|
+
useEffect(() => {
|
|
393
|
+
const tableWrapperElement = tableWrapperRef.current;
|
|
394
|
+
|
|
395
|
+
if (!tableWrapperElement) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const handleResize = () => scheduleStickyStylesUpdate();
|
|
400
|
+
|
|
401
|
+
window.addEventListener("resize", handleResize);
|
|
402
|
+
|
|
403
|
+
let resizeObserver: ResizeObserver | undefined;
|
|
404
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
405
|
+
resizeObserver = new ResizeObserver(handleResize);
|
|
406
|
+
resizeObserver.observe(tableWrapperElement);
|
|
407
|
+
if (tableRef.current) {
|
|
408
|
+
resizeObserver.observe(tableRef.current);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
scheduleStickyStylesUpdate();
|
|
413
|
+
|
|
414
|
+
return () => {
|
|
415
|
+
window.removeEventListener("resize", handleResize);
|
|
416
|
+
resizeObserver?.disconnect();
|
|
417
|
+
if (rafRef.current !== null) {
|
|
418
|
+
cancelAnimationFrame(rafRef.current);
|
|
419
|
+
rafRef.current = null;
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
}, [scheduleStickyStylesUpdate]);
|
|
423
|
+
|
|
424
|
+
return (
|
|
425
|
+
<div className="aksel-data-table__border-wrapper">
|
|
426
|
+
<div ref={tableWrapperRef} className="aksel-data-table__scroll-wrapper">
|
|
427
|
+
<Slot
|
|
428
|
+
tabIndex={tabIndex}
|
|
429
|
+
/* @ts-expect-error Ref is not typed correctly to handle this case */
|
|
430
|
+
ref={mergedTableRefs}
|
|
431
|
+
data-scroll={applyStickyStyles ? "true" : undefined}
|
|
432
|
+
>
|
|
433
|
+
{children}
|
|
434
|
+
</Slot>
|
|
435
|
+
</div>
|
|
436
|
+
</div>
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
interface DataTableTBodyContentProps {
|
|
441
|
+
loadingState: React.ReactNode;
|
|
442
|
+
loadingLabel: string;
|
|
443
|
+
loadingRows?: number;
|
|
444
|
+
emptyState: React.ReactNode;
|
|
445
|
+
}
|
|
225
446
|
|
|
226
|
-
|
|
447
|
+
function DataTableTBodyContent({
|
|
448
|
+
loadingState,
|
|
449
|
+
loadingRows,
|
|
450
|
+
loadingLabel,
|
|
451
|
+
emptyState,
|
|
452
|
+
}: DataTableTBodyContentProps) {
|
|
453
|
+
const { items, itemDetails } = useTableItemsContext();
|
|
454
|
+
const { columns, isLoading, fullWidthColSpan } = useDataTableContext();
|
|
227
455
|
|
|
456
|
+
if (isLoading && loadingState != null) {
|
|
228
457
|
return (
|
|
229
|
-
<
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
selectionState={noSelectionState}
|
|
233
|
-
stickySelection={false}
|
|
234
|
-
stickyHeader={true}
|
|
235
|
-
tableId={useId()}
|
|
236
|
-
showLoadingSkeletons={false}
|
|
237
|
-
onRowClick={undefined}
|
|
238
|
-
disableRowSelectionOnClick={false}
|
|
239
|
-
showLoadingOverlay={false}
|
|
240
|
-
columns={[]}
|
|
241
|
-
>
|
|
242
|
-
<DataTableExpansionProvider>
|
|
243
|
-
<div className="aksel-data-table__border-wrapper">
|
|
244
|
-
<div className="aksel-data-table__scroll-wrapper">
|
|
245
|
-
<table
|
|
246
|
-
{...rest}
|
|
247
|
-
ref={mergedRef}
|
|
248
|
-
className={cl("aksel-data-table", className)}
|
|
249
|
-
data-zebra-stripes={zebraStripes}
|
|
250
|
-
data-truncate-content={truncateContent}
|
|
251
|
-
data-density={rowDensity}
|
|
252
|
-
data-layout={layout}
|
|
253
|
-
tabIndex={tabIndex}
|
|
254
|
-
/>
|
|
255
|
-
</div>
|
|
256
|
-
</div>
|
|
257
|
-
</DataTableExpansionProvider>
|
|
258
|
-
</DataTableContextProvider>
|
|
458
|
+
<DataTableLoadingState colSpan={fullWidthColSpan}>
|
|
459
|
+
{loadingState}
|
|
460
|
+
</DataTableLoadingState>
|
|
259
461
|
);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (isLoading && loadingRows) {
|
|
465
|
+
return (
|
|
466
|
+
<>
|
|
467
|
+
<tr>
|
|
468
|
+
<td colSpan={fullWidthColSpan} className="aksel-sr-only">
|
|
469
|
+
{loadingLabel}
|
|
470
|
+
</td>
|
|
471
|
+
</tr>
|
|
472
|
+
{Array.from({ length: loadingRows }, (_, rowIndex) => (
|
|
473
|
+
<DataTableTr key={`skeleton-row-${rowIndex}`} aria-hidden>
|
|
474
|
+
{columns.map(({ isSticky, colDef }, colDefIndex) => (
|
|
475
|
+
<DataTableBaseCell
|
|
476
|
+
textAlign={colDef.align ?? "left"}
|
|
477
|
+
key={colDef.id || colDefIndex}
|
|
478
|
+
as={colDef.isRowHeader ? "th" : "td"}
|
|
479
|
+
isSticky={isSticky}
|
|
480
|
+
>
|
|
481
|
+
<Skeleton variant="text" />
|
|
482
|
+
</DataTableBaseCell>
|
|
483
|
+
))}
|
|
484
|
+
</DataTableTr>
|
|
485
|
+
))}
|
|
486
|
+
</>
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (items.length === 0 && emptyState !== undefined) {
|
|
491
|
+
return (
|
|
492
|
+
<DataTableEmptyState colSpan={fullWidthColSpan}>
|
|
493
|
+
{emptyState}
|
|
494
|
+
</DataTableEmptyState>
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const renderLoadingAnnouncement = isLoading && !loadingState && !loadingRows;
|
|
499
|
+
|
|
500
|
+
return (
|
|
501
|
+
<>
|
|
502
|
+
{renderLoadingAnnouncement && (
|
|
503
|
+
<tr>
|
|
504
|
+
<td colSpan={fullWidthColSpan} className="aksel-sr-only">
|
|
505
|
+
{loadingLabel}
|
|
506
|
+
</td>
|
|
507
|
+
</tr>
|
|
508
|
+
)}
|
|
509
|
+
{items.map((rowData) => {
|
|
510
|
+
const details = itemDetails.get(rowData);
|
|
511
|
+
|
|
512
|
+
/* Should in theory be impossible. Look about typing this? */
|
|
513
|
+
if (!details) {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const hasSubRows = details.children.length > 0;
|
|
518
|
+
|
|
519
|
+
return (
|
|
520
|
+
<React.Fragment key={details.id}>
|
|
521
|
+
<DataTableTr rowId={details.id}>
|
|
522
|
+
{columns.map(({ isSticky, colDef }, colDefIndex) => {
|
|
523
|
+
const renderNestedToggle = colDefIndex === 0 && hasSubRows;
|
|
524
|
+
const renderNestedIndent =
|
|
525
|
+
colDefIndex === 0 && (details.level > 0 || hasSubRows);
|
|
526
|
+
|
|
527
|
+
const style: React.CSSProperties = {
|
|
528
|
+
"--__axc-data-table-nested-depth": details.level,
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
return (
|
|
532
|
+
<DataTableBaseCell
|
|
533
|
+
textAlign={colDef.align ?? "left"}
|
|
534
|
+
key={colDef.id || colDefIndex}
|
|
535
|
+
as={colDef.isRowHeader ? "th" : "td"}
|
|
536
|
+
isSticky={isSticky}
|
|
537
|
+
data-nested={renderNestedIndent || undefined}
|
|
538
|
+
style={style}
|
|
539
|
+
>
|
|
540
|
+
{renderNestedToggle && (
|
|
541
|
+
<DataTableSubRowToggle details={details} />
|
|
542
|
+
)}
|
|
543
|
+
{colDef.cell(rowData)}
|
|
544
|
+
</DataTableBaseCell>
|
|
545
|
+
);
|
|
546
|
+
})}
|
|
547
|
+
</DataTableTr>
|
|
548
|
+
<DataTableDetailsPanelRow rowId={details.id} rowData={rowData} />
|
|
549
|
+
</React.Fragment>
|
|
550
|
+
);
|
|
551
|
+
})}
|
|
552
|
+
</>
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const DataTable = forwardRef(DataTableInner) as <T>(
|
|
557
|
+
props: DataTableProps<T> & React.RefAttributes<HTMLTableElement>,
|
|
558
|
+
) => React.ReactElement | null;
|
|
559
|
+
|
|
560
|
+
export { DataTable };
|
|
561
|
+
export type { DataTableProps };
|
|
285
562
|
export default DataTable;
|
|
286
|
-
export type {
|
|
287
|
-
DataTableCaptionProps,
|
|
288
|
-
DataTableEmptyStateProps,
|
|
289
|
-
DataTableLoadingStateProps,
|
|
290
|
-
DataTableProps,
|
|
291
|
-
DataTableTbodyProps,
|
|
292
|
-
DataTableTdProps,
|
|
293
|
-
DataTableTfootProps,
|
|
294
|
-
DataTableTheadProps,
|
|
295
|
-
DataTableThProps,
|
|
296
|
-
DataTableTrProps,
|
|
297
|
-
};
|