@navikt/ds-react 8.10.2 → 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 +4 -2
- package/cjs/data/table/column-header/DataTableColumnHeader.js.map +1 -1
- package/cjs/data/table/column-header/useTableColumnResize.d.ts +39 -14
- package/cjs/data/table/column-header/useTableColumnResize.js +37 -39
- 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 +13 -5
- package/cjs/data/table/helpers/collectTableRowEntries.js +26 -19
- package/cjs/data/table/helpers/collectTableRowEntries.js.map +1 -1
- package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +46 -0
- package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js +112 -0
- package/cjs/data/table/helpers/selection/SelectionSubtreeHelper.js.map +1 -0
- package/cjs/data/table/helpers/selection/getMultipleSelectProps.d.ts +3 -2
- package/cjs/data/table/helpers/selection/getMultipleSelectProps.js +43 -19
- package/cjs/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
- package/cjs/data/table/helpers/selection/selection.types.d.ts +1 -0
- package/cjs/data/table/helpers/table-keyboard.d.ts +1 -2
- package/cjs/data/table/helpers/table-keyboard.js +1 -2
- package/cjs/data/table/helpers/table-keyboard.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} +26 -19
- package/cjs/data/table/hooks/useTableDetailsPanel.js.map +1 -0
- package/cjs/data/table/hooks/useTableItems.d.ts +18 -17
- package/cjs/data/table/hooks/useTableItems.js +27 -15
- package/cjs/data/table/hooks/useTableItems.js.map +1 -1
- package/cjs/data/table/hooks/useTableSelection.d.ts +6 -3
- package/cjs/data/table/hooks/useTableSelection.js +10 -4
- 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 +12 -10
- 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 -39
- 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/form/checkbox/Checkbox.js +1 -0
- package/cjs/form/checkbox/Checkbox.js.map +1 -1
- package/cjs/form/radio/Radio.js +7 -1
- package/cjs/form/radio/Radio.js.map +1 -1
- package/cjs/modal/types.d.ts +8 -4
- 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 +4 -2
- package/esm/data/table/column-header/DataTableColumnHeader.js.map +1 -1
- package/esm/data/table/column-header/useTableColumnResize.d.ts +39 -14
- package/esm/data/table/column-header/useTableColumnResize.js +38 -40
- 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 +13 -5
- package/esm/data/table/helpers/collectTableRowEntries.js +26 -19
- package/esm/data/table/helpers/collectTableRowEntries.js.map +1 -1
- package/esm/data/table/helpers/selection/SelectionSubtreeHelper.d.ts +46 -0
- package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js +109 -0
- package/esm/data/table/helpers/selection/SelectionSubtreeHelper.js.map +1 -0
- package/esm/data/table/helpers/selection/getMultipleSelectProps.d.ts +3 -2
- package/esm/data/table/helpers/selection/getMultipleSelectProps.js +43 -19
- package/esm/data/table/helpers/selection/getMultipleSelectProps.js.map +1 -1
- package/esm/data/table/helpers/selection/selection.types.d.ts +1 -0
- package/esm/data/table/helpers/table-keyboard.d.ts +1 -2
- package/esm/data/table/helpers/table-keyboard.js +1 -2
- package/esm/data/table/helpers/table-keyboard.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/useTableDetailsPanel.js +58 -0
- package/esm/data/table/hooks/useTableDetailsPanel.js.map +1 -0
- package/esm/data/table/hooks/useTableItems.d.ts +18 -17
- package/esm/data/table/hooks/useTableItems.js +27 -15
- package/esm/data/table/hooks/useTableItems.js.map +1 -1
- package/esm/data/table/hooks/useTableSelection.d.ts +6 -3
- package/esm/data/table/hooks/useTableSelection.js +10 -4
- 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 +12 -10
- 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 -37
- 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/form/checkbox/Checkbox.js +1 -0
- package/esm/form/checkbox/Checkbox.js.map +1 -1
- package/esm/form/radio/Radio.js +7 -1
- package/esm/form/radio/Radio.js.map +1 -1
- package/esm/modal/types.d.ts +8 -4
- 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 +11 -7
- package/src/data/table/column-header/useTableColumnResize.ts +95 -54
- package/src/data/table/details-panel-row/DataTableDetailsPanelRow.tsx +53 -0
- package/src/data/table/helpers/collectTableRowEntries.ts +55 -31
- package/src/data/table/helpers/selection/SelectionSubtreeHelper.test.ts +66 -0
- package/src/data/table/helpers/selection/SelectionSubtreeHelper.ts +162 -0
- package/src/data/table/helpers/selection/getMultipleSelectProps.ts +57 -20
- package/src/data/table/helpers/selection/selection.types.ts +1 -0
- package/src/data/table/helpers/table-keyboard.ts +1 -2
- package/src/data/table/hooks/__tests__/useTableItems.test.ts +27 -6
- package/src/data/table/hooks/__tests__/useTableSelection.test.ts +182 -58
- package/src/data/table/hooks/useColumnOptions.ts +19 -5
- package/src/data/table/hooks/useTableDetailsPanel.tsx +182 -0
- package/src/data/table/hooks/useTableItems.ts +74 -60
- package/src/data/table/hooks/useTableSelection.ts +27 -12
- package/src/data/table/index.tsx +5 -3
- package/src/data/table/root/DataTable.types.ts +25 -10
- 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 +483 -219
- package/src/data/table/sub-row-toggle/DataTableSubRowToggle.tsx +39 -0
- package/src/data/table/tr/DataTableTr.tsx +14 -13
- package/src/form/checkbox/Checkbox.tsx +1 -0
- package/src/form/radio/Radio.tsx +7 -1
- package/src/modal/types.ts +8 -4
- 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 -29
- package/cjs/data/table/hooks/useTableExpansion.js.map +0 -1
- package/cjs/data/table/root/DataTableAuto.d.ts +0 -174
- 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 -29
- package/esm/data/table/hooks/useTableExpansion.js +0 -51
- package/esm/data/table/hooks/useTableExpansion.js.map +0 -1
- package/esm/data/table/root/DataTableAuto.d.ts +0 -174
- package/esm/data/table/root/DataTableAuto.js +0 -170
- package/esm/data/table/root/DataTableAuto.js.map +0 -1
- package/src/data/table/hooks/__tests__/useTableExpansion.test.tsx +0 -115
- package/src/data/table/hooks/useTableExpansion.tsx +0 -141
- package/src/data/table/root/DataTableAuto.test.tsx +0 -118
- package/src/data/table/root/DataTableAuto.tsx +0 -603
|
@@ -17,11 +17,10 @@ import { type ResizeProps, useTableColumnResize } from "./useTableColumnResize";
|
|
|
17
17
|
|
|
18
18
|
interface DataTableColumnHeaderProps
|
|
19
19
|
extends ResizeProps, DataTableBaseCellProps {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Accessible name of the column.
|
|
22
|
+
*/
|
|
23
|
+
label: string;
|
|
25
24
|
/**
|
|
26
25
|
* Makes the column header sortable. The entire header cell content becomes
|
|
27
26
|
* a clickable button when true.
|
|
@@ -59,15 +58,18 @@ const DataTableColumnHeader = forwardRef<
|
|
|
59
58
|
{
|
|
60
59
|
className,
|
|
61
60
|
children,
|
|
61
|
+
label,
|
|
62
62
|
sortable = false,
|
|
63
63
|
sortDirection = "none",
|
|
64
64
|
onSortClick,
|
|
65
|
+
resizable = true,
|
|
65
66
|
style,
|
|
66
67
|
width,
|
|
68
|
+
defaultWidth,
|
|
69
|
+
autoWidth,
|
|
67
70
|
minWidth,
|
|
68
71
|
maxWidth,
|
|
69
72
|
onWidthChange,
|
|
70
|
-
defaultWidth,
|
|
71
73
|
colSpan,
|
|
72
74
|
rowSpan,
|
|
73
75
|
UNSAFE_isSelection,
|
|
@@ -80,9 +82,11 @@ const DataTableColumnHeader = forwardRef<
|
|
|
80
82
|
const mergedRef = useMergeRefs(forwardedRef, thRef);
|
|
81
83
|
|
|
82
84
|
const resizeResult = useTableColumnResize({
|
|
85
|
+
resizable,
|
|
83
86
|
thRef,
|
|
84
87
|
width,
|
|
85
88
|
defaultWidth,
|
|
89
|
+
autoWidth,
|
|
86
90
|
minWidth,
|
|
87
91
|
maxWidth,
|
|
88
92
|
onWidthChange,
|
|
@@ -140,7 +144,7 @@ const DataTableColumnHeader = forwardRef<
|
|
|
140
144
|
aria-label={
|
|
141
145
|
resizeResult.isResizingWithKeyboard
|
|
142
146
|
? "Bruk pil venstre/høyre"
|
|
143
|
-
:
|
|
147
|
+
: `Endre bredde ${label}`
|
|
144
148
|
} // TODO Translate
|
|
145
149
|
data-active={resizeResult.isResizingWithKeyboard}
|
|
146
150
|
data-disable-keyboard-nav={resizeResult.isResizingWithKeyboard}
|
|
@@ -1,36 +1,64 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type DOMAttributes,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from "react";
|
|
2
8
|
import { useControllableState } from "../../../utils/hooks";
|
|
3
9
|
import { useDataTableContext } from "../root/DataTableRoot.context";
|
|
4
10
|
|
|
5
|
-
type ColumnWidth = number | string;
|
|
6
|
-
|
|
7
11
|
type ResizeProps = {
|
|
12
|
+
// If/when we add support for composition, consider mentioning that resizing only works on first row in thead.
|
|
8
13
|
/**
|
|
9
|
-
*
|
|
14
|
+
* Whether the column should be resizable by the user.
|
|
10
15
|
*
|
|
11
|
-
*
|
|
16
|
+
* **NB:** This is always disabled when `layout="auto"` on the root component.
|
|
17
|
+
* @default true
|
|
18
|
+
*/
|
|
19
|
+
resizable?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the column should automatically resize to fit its content. **Runs only once.**
|
|
22
|
+
*
|
|
23
|
+
* `onWidthChange` will be called with the new size. `minWidth` and `maxWidth` will be respected.
|
|
24
|
+
*
|
|
25
|
+
* If you don't need manual resizing support and want most of the columns to resize automatically,
|
|
26
|
+
* consider using `layout="auto"` on the root instead for better performance.
|
|
27
|
+
*
|
|
28
|
+
* **NB:** This can cause a layout shift. Set a good initial width with `width` or `defaultWidth` to mitigate this.
|
|
29
|
+
*/
|
|
30
|
+
autoWidth?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Minimum width of the column when resizing. Only used when `resizable` or `autoWidth` is enabled.
|
|
33
|
+
* @default 40
|
|
12
34
|
*/
|
|
13
|
-
|
|
35
|
+
minWidth?: number;
|
|
14
36
|
/**
|
|
15
|
-
*
|
|
37
|
+
* Maximum width of the column when resizing. Only used when `resizable` or `autoWidth` is enabled.
|
|
16
38
|
*/
|
|
17
|
-
|
|
39
|
+
maxWidth?: number;
|
|
40
|
+
// TODO: Consider "allowing" %-width on last column, if we find a solution to the overflow issue (width becomes 0px).
|
|
18
41
|
/**
|
|
19
|
-
*
|
|
42
|
+
* Controlled width of the column. Does not respect `minWidth` and `maxWidth`.
|
|
20
43
|
*
|
|
21
|
-
* Should be used
|
|
44
|
+
* Should only be used to fully control column width state. Otherwise, use `defaultWidth` and let the component handle resizing.
|
|
45
|
+
*
|
|
46
|
+
* **NB:** Percentage as initial width does not work well with resizing.
|
|
22
47
|
*/
|
|
23
|
-
|
|
48
|
+
width?: number | string;
|
|
24
49
|
/**
|
|
25
|
-
*
|
|
50
|
+
* Initial width of the column. Only used when `width` is not set and `resizable` is true.
|
|
51
|
+
* Does not respect `minWidth` and `maxWidth`.
|
|
26
52
|
*
|
|
27
|
-
*
|
|
53
|
+
* **NB:** Percentage as initial width does not work well with resizing.
|
|
54
|
+
* @default 140px
|
|
28
55
|
*/
|
|
29
|
-
|
|
56
|
+
defaultWidth?: number | string;
|
|
30
57
|
/**
|
|
31
58
|
* Called when the column width changes.
|
|
59
|
+
* @param width New width in pixels.
|
|
32
60
|
*/
|
|
33
|
-
onWidthChange?: (width:
|
|
61
|
+
onWidthChange?: (width: number) => void;
|
|
34
62
|
/**
|
|
35
63
|
* Forwarded styles
|
|
36
64
|
*/
|
|
@@ -41,7 +69,12 @@ type ResizeProps = {
|
|
|
41
69
|
colSpan?: number;
|
|
42
70
|
};
|
|
43
71
|
|
|
44
|
-
type
|
|
72
|
+
type WithUndefined<T> = {
|
|
73
|
+
[K in keyof T]: T[K] | undefined;
|
|
74
|
+
};
|
|
75
|
+
type Unomittable<T> = WithUndefined<Required<T>>;
|
|
76
|
+
|
|
77
|
+
type TableColumnResizeArgs = Unomittable<ResizeProps> & {
|
|
45
78
|
thRef: React.RefObject<HTMLTableCellElement | null>;
|
|
46
79
|
};
|
|
47
80
|
|
|
@@ -74,9 +107,11 @@ function useTableColumnResize(
|
|
|
74
107
|
args: TableColumnResizeArgs,
|
|
75
108
|
): TableColumnResizeResult {
|
|
76
109
|
const {
|
|
110
|
+
resizable,
|
|
77
111
|
thRef,
|
|
78
112
|
width: userWidth,
|
|
79
113
|
defaultWidth,
|
|
114
|
+
autoWidth,
|
|
80
115
|
onWidthChange,
|
|
81
116
|
maxWidth = Infinity,
|
|
82
117
|
minWidth = 40,
|
|
@@ -89,7 +124,7 @@ function useTableColumnResize(
|
|
|
89
124
|
const [isResizingWithKeyboard, setIsResizingWithKeyboard] = useState(false);
|
|
90
125
|
const ignoreNextOnClick = useRef(false);
|
|
91
126
|
|
|
92
|
-
const [width,
|
|
127
|
+
const [width, setWidth] = useControllableState({
|
|
93
128
|
value: userWidth,
|
|
94
129
|
defaultValue: defaultWidth ?? (colSpan ?? 1) * 140,
|
|
95
130
|
/**
|
|
@@ -100,14 +135,26 @@ function useTableColumnResize(
|
|
|
100
135
|
onChange: onWidthChange,
|
|
101
136
|
});
|
|
102
137
|
|
|
103
|
-
const
|
|
138
|
+
const setClampedWidth = useCallback(
|
|
104
139
|
(newWidth: number) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
140
|
+
setWidth(Math.min(Math.max(newWidth, minWidth), maxWidth));
|
|
141
|
+
},
|
|
142
|
+
[minWidth, maxWidth, setWidth],
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: We only want to run this on mount and when autoWidth changes
|
|
146
|
+
useEffect(
|
|
147
|
+
function autoResizeColumn() {
|
|
148
|
+
if (!autoWidth) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const newColumnWidth = getAutoColumnWidth(thRef);
|
|
153
|
+
if (newColumnWidth) {
|
|
154
|
+
setClampedWidth(newColumnWidth);
|
|
155
|
+
}
|
|
109
156
|
},
|
|
110
|
-
[
|
|
157
|
+
[autoWidth], // eslint-disable-line react-hooks/exhaustive-deps
|
|
111
158
|
);
|
|
112
159
|
|
|
113
160
|
const handleOnClick: DOMAttributes<HTMLButtonElement>["onClick"] =
|
|
@@ -135,19 +182,19 @@ function useTableColumnResize(
|
|
|
135
182
|
if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
|
|
136
183
|
event.preventDefault();
|
|
137
184
|
const delta = event.key === "ArrowRight" ? 20 : -20;
|
|
138
|
-
|
|
185
|
+
setClampedWidth(currentWidth + delta);
|
|
139
186
|
return;
|
|
140
187
|
}
|
|
141
188
|
if (event.key === "Home") {
|
|
142
189
|
event.preventDefault();
|
|
143
|
-
|
|
190
|
+
setClampedWidth(0); // will fall back to minWidth
|
|
144
191
|
return;
|
|
145
192
|
}
|
|
146
193
|
if (event.key === "End") {
|
|
147
194
|
event.preventDefault();
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
150
|
-
|
|
195
|
+
const newWidth = getAutoColumnWidth(thRef);
|
|
196
|
+
if (newWidth && newWidth > currentWidth) {
|
|
197
|
+
setClampedWidth(newWidth);
|
|
151
198
|
}
|
|
152
199
|
return;
|
|
153
200
|
}
|
|
@@ -155,7 +202,7 @@ function useTableColumnResize(
|
|
|
155
202
|
setIsResizingWithKeyboard(false);
|
|
156
203
|
}
|
|
157
204
|
},
|
|
158
|
-
[isResizingWithKeyboard,
|
|
205
|
+
[isResizingWithKeyboard, setClampedWidth, thRef],
|
|
159
206
|
);
|
|
160
207
|
|
|
161
208
|
const startResize = useCallback(
|
|
@@ -166,19 +213,16 @@ function useTableColumnResize(
|
|
|
166
213
|
const currentWidth = thRef.current?.offsetWidth ?? 0;
|
|
167
214
|
const newWidth = startWidth + (clientX - startX);
|
|
168
215
|
|
|
169
|
-
|
|
170
|
-
const max = parseWidth(maxWidth) ?? Infinity;
|
|
171
|
-
|
|
172
|
-
if (newWidth > max) {
|
|
216
|
+
if (newWidth > maxWidth) {
|
|
173
217
|
setWidth(newWidth < currentWidth ? newWidth : currentWidth);
|
|
174
218
|
return;
|
|
175
219
|
}
|
|
176
|
-
if (newWidth <
|
|
220
|
+
if (newWidth < minWidth) {
|
|
177
221
|
setWidth(newWidth > currentWidth ? newWidth : currentWidth);
|
|
178
222
|
return;
|
|
179
223
|
}
|
|
180
224
|
|
|
181
|
-
|
|
225
|
+
setClampedWidth(newWidth);
|
|
182
226
|
}
|
|
183
227
|
|
|
184
228
|
function onMouseMove(e: MouseEvent) {
|
|
@@ -206,7 +250,7 @@ function useTableColumnResize(
|
|
|
206
250
|
document.addEventListener("touchend", cleanup, { once: true });
|
|
207
251
|
document.addEventListener("touchcancel", cleanup, { once: true });
|
|
208
252
|
},
|
|
209
|
-
[maxWidth, minWidth, setWidth, thRef],
|
|
253
|
+
[maxWidth, minWidth, setWidth, setClampedWidth, thRef],
|
|
210
254
|
);
|
|
211
255
|
|
|
212
256
|
const handleMouseDown: DOMAttributes<HTMLButtonElement>["onMouseDown"] =
|
|
@@ -230,9 +274,9 @@ function useTableColumnResize(
|
|
|
230
274
|
useCallback(() => {
|
|
231
275
|
const newColumnWidth = getAutoColumnWidth(thRef);
|
|
232
276
|
if (newColumnWidth) {
|
|
233
|
-
|
|
277
|
+
setClampedWidth(newColumnWidth);
|
|
234
278
|
}
|
|
235
|
-
}, [
|
|
279
|
+
}, [setClampedWidth, thRef]);
|
|
236
280
|
|
|
237
281
|
if (tableContext.layout !== "fixed") {
|
|
238
282
|
return {
|
|
@@ -241,6 +285,16 @@ function useTableColumnResize(
|
|
|
241
285
|
};
|
|
242
286
|
}
|
|
243
287
|
|
|
288
|
+
if (!resizable) {
|
|
289
|
+
return {
|
|
290
|
+
style: {
|
|
291
|
+
...style,
|
|
292
|
+
width,
|
|
293
|
+
},
|
|
294
|
+
enabled: false,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
244
298
|
return {
|
|
245
299
|
style: {
|
|
246
300
|
...style,
|
|
@@ -259,20 +313,6 @@ function useTableColumnResize(
|
|
|
259
313
|
};
|
|
260
314
|
}
|
|
261
315
|
|
|
262
|
-
function parseWidth(width: ColumnWidth | undefined): number | undefined {
|
|
263
|
-
if (width == null) {
|
|
264
|
-
return undefined;
|
|
265
|
-
}
|
|
266
|
-
if (typeof width === "number") {
|
|
267
|
-
return width;
|
|
268
|
-
}
|
|
269
|
-
if (typeof width === "string") {
|
|
270
|
-
const parsed = parseInt(width, 10);
|
|
271
|
-
return Number.isNaN(parsed) ? undefined : parsed;
|
|
272
|
-
}
|
|
273
|
-
return undefined;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
316
|
function getAutoColumnWidth(
|
|
277
317
|
thRef: React.RefObject<HTMLTableCellElement | null>,
|
|
278
318
|
) {
|
|
@@ -285,7 +325,9 @@ function getAutoColumnWidth(
|
|
|
285
325
|
}
|
|
286
326
|
|
|
287
327
|
// Find needed width for header cell
|
|
288
|
-
const
|
|
328
|
+
const range = document.createRange();
|
|
329
|
+
range.selectNodeContents(thContent);
|
|
330
|
+
const contentWidth = range.getBoundingClientRect().width;
|
|
289
331
|
const paddingElStyle = window.getComputedStyle(thPaddingEl);
|
|
290
332
|
const thInlinePadding =
|
|
291
333
|
parseInt(paddingElStyle.paddingLeft, 10) +
|
|
@@ -301,7 +343,6 @@ function getAutoColumnWidth(
|
|
|
301
343
|
}
|
|
302
344
|
|
|
303
345
|
// Find needed width for each cell in column in tbody and tfoot
|
|
304
|
-
const range = document.createRange();
|
|
305
346
|
let skipRows = 0;
|
|
306
347
|
for (const row of rows) {
|
|
307
348
|
// Skip rows where the cell in this column is covered by a rowspan from a previous row
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
getDataTableDetailsPanelId,
|
|
4
|
+
useDataTableDetailsPanel,
|
|
5
|
+
} from "../hooks/useTableDetailsPanel";
|
|
6
|
+
import { useDataTableContext } from "../root/DataTableRoot.context";
|
|
7
|
+
|
|
8
|
+
function DataTableDetailsPanelRow<T>({
|
|
9
|
+
rowId,
|
|
10
|
+
rowData,
|
|
11
|
+
}: {
|
|
12
|
+
rowId: string | number;
|
|
13
|
+
rowData: T;
|
|
14
|
+
}) {
|
|
15
|
+
const { tableId, fullWidthColSpan } = useDataTableContext();
|
|
16
|
+
const {
|
|
17
|
+
enableDetailsPanel,
|
|
18
|
+
isExpanded,
|
|
19
|
+
getDetailsPanelContent,
|
|
20
|
+
getDetailsPanelHeight,
|
|
21
|
+
} = useDataTableDetailsPanel();
|
|
22
|
+
|
|
23
|
+
if (!enableDetailsPanel) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!isExpanded(rowId)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const content = getDetailsPanelContent?.(rowData);
|
|
32
|
+
const expansionId = getDataTableDetailsPanelId(tableId, rowId);
|
|
33
|
+
|
|
34
|
+
if (!content) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const panelHeight = getDetailsPanelHeight?.(rowData);
|
|
39
|
+
|
|
40
|
+
const style: React.CSSProperties = panelHeight
|
|
41
|
+
? { height: panelHeight, overflow: "auto" }
|
|
42
|
+
: { height: "auto" };
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<tr className="aksel-data-table__details-panel-row">
|
|
46
|
+
<td id={expansionId} colSpan={fullWidthColSpan}>
|
|
47
|
+
<div style={style}>{content}</div>
|
|
48
|
+
</td>
|
|
49
|
+
</tr>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { DataTableDetailsPanelRow };
|
|
@@ -2,9 +2,9 @@ type TableRowEntryId = string | number;
|
|
|
2
2
|
|
|
3
3
|
type CollectTableRowEntriesArgs<T> = {
|
|
4
4
|
items: T[];
|
|
5
|
-
getRowId
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
getRowId: (rowData: T, index: number) => TableRowEntryId;
|
|
6
|
+
getRows?: (rowData: T) => T[];
|
|
7
|
+
isRowExpandable?: (rowData: T) => boolean;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
interface ItemDetail<T> {
|
|
@@ -14,45 +14,69 @@ interface ItemDetail<T> {
|
|
|
14
14
|
children: readonly T[];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
type CollectTableRowEntriesReturn<T> = {
|
|
18
|
+
itemDetails: Map<T, ItemDetail<T>>;
|
|
19
|
+
/**
|
|
20
|
+
* Direct child ids for each row, used to traverse nested selection groups
|
|
21
|
+
* without storing every descendant list on each ancestor.
|
|
22
|
+
*/
|
|
23
|
+
childRowIdsById: Map<TableRowEntryId, TableRowEntryId[]>;
|
|
24
|
+
};
|
|
25
|
+
|
|
17
26
|
function collectTableRowEntries<T>({
|
|
18
27
|
items,
|
|
19
28
|
getRowId,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}: CollectTableRowEntriesArgs<T>):
|
|
29
|
+
getRows,
|
|
30
|
+
isRowExpandable,
|
|
31
|
+
}: CollectTableRowEntriesArgs<T>): CollectTableRowEntriesReturn<T> {
|
|
23
32
|
const itemDetailsMap = new Map<T, ItemDetail<T>>();
|
|
33
|
+
const childRowIdsById = new Map<TableRowEntryId, TableRowEntryId[]>();
|
|
24
34
|
|
|
25
|
-
const
|
|
26
|
-
|
|
35
|
+
const traverseRow = (
|
|
36
|
+
rowData: T,
|
|
37
|
+
rowIndex: number,
|
|
27
38
|
level: number,
|
|
28
39
|
parent: T | null,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
40
|
+
): TableRowEntryId => {
|
|
41
|
+
const rowId = getRowId(rowData, rowIndex);
|
|
42
|
+
|
|
43
|
+
const children =
|
|
44
|
+
((isRowExpandable?.(rowData) ?? true) ? getRows?.(rowData) : []) ?? [];
|
|
45
|
+
|
|
46
|
+
itemDetailsMap.set(rowData, {
|
|
47
|
+
id: rowId,
|
|
48
|
+
level,
|
|
49
|
+
parent,
|
|
50
|
+
children,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const childRowIds: TableRowEntryId[] = [];
|
|
54
|
+
|
|
55
|
+
for (let childIndex = 0; childIndex < children.length; childIndex++) {
|
|
56
|
+
const childRow = children[childIndex];
|
|
57
|
+
const childRowId = traverseRow(childRow, childIndex, level + 1, rowData);
|
|
58
|
+
childRowIds.push(childRowId);
|
|
49
59
|
}
|
|
60
|
+
|
|
61
|
+
childRowIdsById.set(rowId, childRowIds);
|
|
62
|
+
|
|
63
|
+
return rowId;
|
|
50
64
|
};
|
|
51
65
|
|
|
52
|
-
|
|
66
|
+
for (let rowIndex = 0; rowIndex < items.length; rowIndex++) {
|
|
67
|
+
traverseRow(items[rowIndex], rowIndex, 0, null);
|
|
68
|
+
}
|
|
53
69
|
|
|
54
|
-
return
|
|
70
|
+
return {
|
|
71
|
+
itemDetails: itemDetailsMap,
|
|
72
|
+
childRowIdsById,
|
|
73
|
+
};
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
export { collectTableRowEntries };
|
|
58
|
-
export type {
|
|
77
|
+
export type {
|
|
78
|
+
CollectTableRowEntriesArgs,
|
|
79
|
+
CollectTableRowEntriesReturn,
|
|
80
|
+
TableRowEntryId,
|
|
81
|
+
ItemDetail,
|
|
82
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { SelectionSubtreeHelper } from "./SelectionSubtreeHelper";
|
|
3
|
+
|
|
4
|
+
const childRowIdsById = new Map<string | number, (string | number)[]>([
|
|
5
|
+
["a", ["a1", "a2"]],
|
|
6
|
+
["a1", []],
|
|
7
|
+
["a2", ["a2a"]],
|
|
8
|
+
["a2a", []],
|
|
9
|
+
["b", []],
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
describe("SelectionSubtreeHelper", () => {
|
|
13
|
+
test("returns selectable subtree keys without duplicates", () => {
|
|
14
|
+
const helper = new SelectionSubtreeHelper({
|
|
15
|
+
childRowIdsById,
|
|
16
|
+
disabledKeysSet: new Set(["a2"]),
|
|
17
|
+
selectedKeysSet: new Set(),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(helper.getSelectableKeys(["a", "a1"])).toEqual(["a", "a1", "a2a"]);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("returns cached subtree selection stats", () => {
|
|
24
|
+
const helper = new SelectionSubtreeHelper({
|
|
25
|
+
childRowIdsById,
|
|
26
|
+
disabledKeysSet: new Set(["a2"]),
|
|
27
|
+
selectedKeysSet: new Set(["a", "a1", "a2a"]),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const firstStats = helper.getSelectionStats("a");
|
|
31
|
+
const secondStats = helper.getSelectionStats("a");
|
|
32
|
+
|
|
33
|
+
expect(firstStats).toEqual({ selectableCount: 3, selectedCount: 3 });
|
|
34
|
+
expect(secondStats).toBe(firstStats);
|
|
35
|
+
expect(helper.isFullySelected("a")).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("handles deep trees iteratively", () => {
|
|
39
|
+
const depth = 12000;
|
|
40
|
+
const deepChildRowIdsById = new Map<string | number, (string | number)[]>();
|
|
41
|
+
const selectedKeysSet = new Set<string | number>();
|
|
42
|
+
|
|
43
|
+
for (let index = 0; index < depth; index++) {
|
|
44
|
+
const key = `node-${index}`;
|
|
45
|
+
const childKey = `node-${index + 1}`;
|
|
46
|
+
|
|
47
|
+
deepChildRowIdsById.set(key, index === depth - 1 ? [] : [childKey]);
|
|
48
|
+
|
|
49
|
+
if (index % 2 === 0) {
|
|
50
|
+
selectedKeysSet.add(key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const helper = new SelectionSubtreeHelper({
|
|
55
|
+
childRowIdsById: deepChildRowIdsById,
|
|
56
|
+
disabledKeysSet: new Set(),
|
|
57
|
+
selectedKeysSet,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(helper.getSelectableKeys(["node-0"])).toHaveLength(depth);
|
|
61
|
+
expect(helper.getSelectionStats("node-0")).toEqual({
|
|
62
|
+
selectableCount: depth,
|
|
63
|
+
selectedCount: Math.ceil(depth / 2),
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|