@navikt/ds-react 8.10.4 → 8.10.5
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/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +11 -12
- package/cjs/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
- package/cjs/data/drag-and-drop/root/DragAndDrop.context.d.ts +4 -2
- package/cjs/data/drag-and-drop/root/DragAndDrop.context.js.map +1 -1
- package/cjs/data/drag-and-drop/root/DragAndDropRoot.d.ts +5 -5
- package/cjs/data/drag-and-drop/root/DragAndDropRoot.js +49 -28
- package/cjs/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
- package/cjs/data/drag-and-drop/types.d.ts +0 -4
- package/cjs/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.d.ts → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts} +3 -3
- package/cjs/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js} +5 -5
- package/cjs/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +1 -0
- package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +27 -0
- package/cjs/data/{drag-and-drop-old/item/DataDragAndDropItem.js → drag-and-drop-legacy/item/DragAndDropItemLegacy.js} +12 -12
- package/cjs/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +1 -0
- package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +5 -0
- package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +6 -0
- package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +1 -0
- package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +24 -0
- package/cjs/data/{drag-and-drop-old/root/DataDragAndDropRoot.js → drag-and-drop-legacy/root/DragAndDropLegacyRoot.js} +10 -10
- package/cjs/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +1 -0
- package/cjs/data/stories/Data.test-data.js +0 -1
- package/cjs/data/stories/Data.test-data.js.map +1 -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/details-panel-row/DataTableDetailsPanelRow.js +1 -1
- package/cjs/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -1
- package/cjs/data/table/helpers/collectTableRowEntries.d.ts +7 -5
- package/cjs/data/table/helpers/collectTableRowEntries.js +18 -10
- package/cjs/data/table/helpers/collectTableRowEntries.js.map +1 -1
- package/cjs/data/table/helpers/table-focus.d.ts +0 -3
- package/cjs/data/table/helpers/table-focus.js +38 -8
- package/cjs/data/table/helpers/table-focus.js.map +1 -1
- package/cjs/data/table/hooks/useGridCache.js +2 -2
- package/cjs/data/table/hooks/useGridCache.js.map +1 -1
- package/cjs/data/table/hooks/useTableDetailsPanel.js +1 -1
- package/cjs/data/table/hooks/useTableDetailsPanel.js.map +1 -1
- package/cjs/data/table/hooks/useTableItems.d.ts +4 -4
- package/cjs/data/table/hooks/useTableItems.js +8 -8
- package/cjs/data/table/hooks/useTableItems.js.map +1 -1
- package/cjs/data/table/hooks/useTableKeyboardNav.js +5 -1
- package/cjs/data/table/hooks/useTableKeyboardNav.js.map +1 -1
- package/cjs/data/table/root/DataTable.types.d.ts +0 -3
- package/cjs/data/table/root/DataTableRoot.d.ts +1 -1
- package/cjs/data/table/root/DataTableRoot.js +7 -11
- package/cjs/data/table/root/DataTableRoot.js.map +1 -1
- package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js +11 -12
- package/esm/data/drag-and-drop/drag-handler/DragAndDropDragHandler.js.map +1 -1
- package/esm/data/drag-and-drop/root/DragAndDrop.context.d.ts +4 -2
- package/esm/data/drag-and-drop/root/DragAndDrop.context.js.map +1 -1
- package/esm/data/drag-and-drop/root/DragAndDropRoot.d.ts +5 -5
- package/esm/data/drag-and-drop/root/DragAndDropRoot.js +49 -28
- package/esm/data/drag-and-drop/root/DragAndDropRoot.js.map +1 -1
- package/esm/data/drag-and-drop/types.d.ts +0 -4
- package/esm/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.d.ts → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.d.ts} +3 -3
- package/esm/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js} +4 -4
- package/esm/data/drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.js.map +1 -0
- package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.d.ts +27 -0
- package/esm/data/{drag-and-drop-old/item/DataDragAndDropItem.js → drag-and-drop-legacy/item/DragAndDropItemLegacy.js} +11 -11
- package/esm/data/drag-and-drop-legacy/item/DragAndDropItemLegacy.js.map +1 -0
- package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.d.ts +5 -0
- package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js +3 -0
- package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacy.context.js.map +1 -0
- package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.d.ts +24 -0
- package/esm/data/{drag-and-drop-old/root/DataDragAndDropRoot.js → drag-and-drop-legacy/root/DragAndDropLegacyRoot.js} +8 -8
- package/esm/data/drag-and-drop-legacy/root/DragAndDropLegacyRoot.js.map +1 -0
- package/esm/data/stories/Data.test-data.js +0 -1
- package/esm/data/stories/Data.test-data.js.map +1 -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/details-panel-row/DataTableDetailsPanelRow.js +1 -1
- package/esm/data/table/details-panel-row/DataTableDetailsPanelRow.js.map +1 -1
- package/esm/data/table/helpers/collectTableRowEntries.d.ts +7 -5
- package/esm/data/table/helpers/collectTableRowEntries.js +18 -10
- package/esm/data/table/helpers/collectTableRowEntries.js.map +1 -1
- package/esm/data/table/helpers/table-focus.d.ts +0 -3
- package/esm/data/table/helpers/table-focus.js +38 -8
- package/esm/data/table/helpers/table-focus.js.map +1 -1
- package/esm/data/table/hooks/useGridCache.js +2 -2
- package/esm/data/table/hooks/useGridCache.js.map +1 -1
- package/esm/data/table/hooks/useTableDetailsPanel.js +1 -1
- package/esm/data/table/hooks/useTableDetailsPanel.js.map +1 -1
- package/esm/data/table/hooks/useTableItems.d.ts +4 -4
- package/esm/data/table/hooks/useTableItems.js +8 -8
- package/esm/data/table/hooks/useTableItems.js.map +1 -1
- package/esm/data/table/hooks/useTableKeyboardNav.js +6 -2
- package/esm/data/table/hooks/useTableKeyboardNav.js.map +1 -1
- package/esm/data/table/root/DataTable.types.d.ts +0 -3
- package/esm/data/table/root/DataTableRoot.d.ts +1 -1
- package/esm/data/table/root/DataTableRoot.js +7 -11
- package/esm/data/table/root/DataTableRoot.js.map +1 -1
- package/package.json +8 -7
- package/src/data/drag-and-drop/drag-handler/DragAndDropDragHandler.tsx +11 -16
- package/src/data/drag-and-drop/root/DragAndDrop.context.tsx +4 -2
- package/src/data/drag-and-drop/root/DragAndDropRoot.tsx +85 -40
- package/src/data/drag-and-drop/types.ts +0 -5
- package/src/data/{drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.tsx → drag-and-drop-legacy/drag-handler/DragAndDropDragHandlerLegacy.tsx} +5 -5
- package/src/data/{drag-and-drop-old/item/DataDragAndDropItem.tsx → drag-and-drop-legacy/item/DragAndDropItemLegacy.tsx} +13 -13
- package/src/data/{drag-and-drop-old/root/DataDragAndDrop.context.tsx → drag-and-drop-legacy/root/DragAndDropLegacy.context.tsx} +3 -3
- package/src/data/{drag-and-drop-old/root/DataDragAndDropRoot.tsx → drag-and-drop-legacy/root/DragAndDropLegacyRoot.tsx} +19 -21
- package/src/data/stories/Data.test-data.tsx +0 -1
- package/src/data/table/column-header/DataTableColumnHeader.tsx +2 -0
- package/src/data/table/details-panel-row/DataTableDetailsPanelRow.tsx +5 -1
- package/src/data/table/helpers/collectTableRowEntries.ts +31 -17
- package/src/data/table/helpers/table-focus.ts +63 -9
- package/src/data/table/hooks/__tests__/useTableItems.test.ts +46 -7
- package/src/data/table/hooks/useGridCache.ts +3 -2
- package/src/data/table/hooks/useTableDetailsPanel.tsx +5 -2
- package/src/data/table/hooks/useTableItems.ts +20 -19
- package/src/data/table/hooks/useTableKeyboardNav.ts +6 -2
- package/src/data/table/root/DataTable.types.ts +0 -3
- package/src/data/table/root/DataTableRoot.tsx +34 -34
- package/src/data/table/root/agent-feature-gap.md +96 -0
- package/cjs/data/drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js.map +0 -1
- package/cjs/data/drag-and-drop-old/item/DataDragAndDropItem.d.ts +0 -27
- package/cjs/data/drag-and-drop-old/item/DataDragAndDropItem.js.map +0 -1
- package/cjs/data/drag-and-drop-old/root/DataDragAndDrop.context.d.ts +0 -5
- package/cjs/data/drag-and-drop-old/root/DataDragAndDrop.context.js +0 -6
- package/cjs/data/drag-and-drop-old/root/DataDragAndDrop.context.js.map +0 -1
- package/cjs/data/drag-and-drop-old/root/DataDragAndDropRoot.d.ts +0 -24
- package/cjs/data/drag-and-drop-old/root/DataDragAndDropRoot.js.map +0 -1
- package/esm/data/drag-and-drop-old/drag-handler/DataDragAndDropDragHandler.js.map +0 -1
- package/esm/data/drag-and-drop-old/item/DataDragAndDropItem.d.ts +0 -27
- package/esm/data/drag-and-drop-old/item/DataDragAndDropItem.js.map +0 -1
- package/esm/data/drag-and-drop-old/root/DataDragAndDrop.context.d.ts +0 -5
- package/esm/data/drag-and-drop-old/root/DataDragAndDrop.context.js +0 -3
- package/esm/data/drag-and-drop-old/root/DataDragAndDrop.context.js.map +0 -1
- package/esm/data/drag-and-drop-old/root/DataDragAndDropRoot.d.ts +0 -24
- package/esm/data/drag-and-drop-old/root/DataDragAndDropRoot.js.map +0 -1
|
@@ -3,10 +3,10 @@ import React, { useRef } from "react";
|
|
|
3
3
|
import { HStack } from "../../../primitives/stack";
|
|
4
4
|
import { cl } from "../../../utils/helpers";
|
|
5
5
|
import { useMergeRefs } from "../../../utils/hooks";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { DragAndDropDragHandlerLegacy } from "../drag-handler/DragAndDropDragHandlerLegacy";
|
|
7
|
+
import { DragAndDropLegacyContext } from "../root/DragAndDropLegacy.context";
|
|
8
8
|
|
|
9
|
-
interface
|
|
9
|
+
interface DragAndDropItemLegacyProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
10
10
|
children: React.ReactNode;
|
|
11
11
|
/**
|
|
12
12
|
* Unique id
|
|
@@ -21,17 +21,17 @@ interface DataDragAndDropItemProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
21
21
|
/**
|
|
22
22
|
* TODO
|
|
23
23
|
*
|
|
24
|
-
* @see 🏷️ {@link
|
|
24
|
+
* @see 🏷️ {@link DragAndDropItemLegacyProps}
|
|
25
25
|
* @example
|
|
26
26
|
* ```tsx
|
|
27
|
-
* <
|
|
27
|
+
* <DragAndDropLegacy.Item numOfSelectedRows={selectedRows.length} onClear={handleClear}>
|
|
28
28
|
* TODO
|
|
29
|
-
* </
|
|
29
|
+
* </DragAndDropLegacy.Item>
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
const
|
|
32
|
+
const DragAndDropItemLegacy = React.forwardRef<
|
|
33
33
|
HTMLDivElement,
|
|
34
|
-
|
|
34
|
+
DragAndDropItemLegacyProps
|
|
35
35
|
>(({ children, id, index, className, ...rest }, forwardedRef) => {
|
|
36
36
|
const handleRef = useRef<HTMLDivElement>(null);
|
|
37
37
|
const { ref, isDragging, isDropTarget } = useSortable({
|
|
@@ -40,7 +40,7 @@ const DataDragAndDropItem = React.forwardRef<
|
|
|
40
40
|
handle: handleRef,
|
|
41
41
|
});
|
|
42
42
|
const mergedRef = useMergeRefs(ref, forwardedRef);
|
|
43
|
-
const context = React.useContext(
|
|
43
|
+
const context = React.useContext(DragAndDropLegacyContext);
|
|
44
44
|
const mouseDragging = isDragging && context?.inputMethod === "mouse";
|
|
45
45
|
const mouseDropTarget = isDropTarget && context?.inputMethod === "mouse";
|
|
46
46
|
const keyboardDragging = isDragging && context?.inputMethod === "keyboard";
|
|
@@ -58,7 +58,7 @@ const DataDragAndDropItem = React.forwardRef<
|
|
|
58
58
|
data-drop-target={mouseDropTarget}
|
|
59
59
|
tabIndex={-1}
|
|
60
60
|
>
|
|
61
|
-
<
|
|
61
|
+
<DragAndDropDragHandlerLegacy
|
|
62
62
|
handleRef={handleRef}
|
|
63
63
|
keyboardDragging={keyboardDragging}
|
|
64
64
|
alt
|
|
@@ -69,6 +69,6 @@ const DataDragAndDropItem = React.forwardRef<
|
|
|
69
69
|
);
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
export default
|
|
73
|
-
export {
|
|
74
|
-
export type {
|
|
72
|
+
export default DragAndDropItemLegacy;
|
|
73
|
+
export { DragAndDropItemLegacy };
|
|
74
|
+
export type { DragAndDropItemLegacyProps };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createContext } from "react";
|
|
2
2
|
|
|
3
|
-
interface
|
|
3
|
+
interface DragAndDropContextLegacyType {
|
|
4
4
|
inputMethod: "mouse" | "keyboard" | null;
|
|
5
5
|
// setInputMethod: (method: "mouse" | "keyboard" | null) => void;
|
|
6
6
|
// setItems: React.Dispatch<React.SetStateAction<any[]>>;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export const
|
|
10
|
-
|
|
9
|
+
export const DragAndDropLegacyContext = createContext<
|
|
10
|
+
DragAndDropContextLegacyType | undefined
|
|
11
11
|
>(undefined);
|
|
@@ -2,34 +2,32 @@ import { DragDropProvider, DragOverlay } from "@dnd-kit/react";
|
|
|
2
2
|
import { isSortable } from "@dnd-kit/react/sortable";
|
|
3
3
|
import React, { forwardRef, isValidElement } from "react";
|
|
4
4
|
import { VStack } from "../../../primitives/stack";
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
} from "../item/DataDragAndDropItem";
|
|
8
|
-
import { DataDragAndDropContext } from "./DataDragAndDrop.context";
|
|
5
|
+
import DragAndDropItemLegacy from "../item/DragAndDropItemLegacy";
|
|
6
|
+
import { DragAndDropLegacyContext } from "./DragAndDropLegacy.context";
|
|
9
7
|
|
|
10
|
-
interface
|
|
8
|
+
interface DragAndDropLegacyProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
11
9
|
children: any[];
|
|
12
10
|
setItems: React.Dispatch<React.SetStateAction<any[]>>;
|
|
13
11
|
}
|
|
14
12
|
|
|
15
|
-
interface
|
|
16
|
-
|
|
13
|
+
interface DragAndDropLegacyRootComponent extends React.ForwardRefExoticComponent<
|
|
14
|
+
DragAndDropLegacyProps & React.RefAttributes<HTMLDivElement>
|
|
17
15
|
> {
|
|
18
16
|
/**
|
|
19
|
-
* @see 🏷️ {@link
|
|
17
|
+
* @see 🏷️ {@link DragAndDropItemLegacyProps}
|
|
20
18
|
* * @example
|
|
21
19
|
* ```jsx
|
|
22
|
-
* <
|
|
23
|
-
* <
|
|
20
|
+
* <DragAndDropLegacy>
|
|
21
|
+
* <DragAndDropLegacy.Item id="1" index={0}>
|
|
24
22
|
* ...
|
|
25
|
-
* </
|
|
26
|
-
* </
|
|
23
|
+
* </DragAndDropLegacy.Item>
|
|
24
|
+
* </DragAndDropLegacy>
|
|
27
25
|
* ```
|
|
28
26
|
*/
|
|
29
|
-
Item: typeof
|
|
27
|
+
Item: typeof DragAndDropItemLegacy;
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
const
|
|
30
|
+
const DragAndDropLegacy = forwardRef<HTMLDivElement, DragAndDropLegacyProps>(
|
|
33
31
|
({ setItems, children, ...rest }, forwardedRef) => {
|
|
34
32
|
const [inputMethod, setInputMethod] = React.useState<
|
|
35
33
|
"mouse" | "keyboard" | null
|
|
@@ -45,7 +43,7 @@ const DataDragAndDrop = forwardRef<HTMLDivElement, DataDragAndDropProps>(
|
|
|
45
43
|
};
|
|
46
44
|
|
|
47
45
|
return (
|
|
48
|
-
<
|
|
46
|
+
<DragAndDropLegacyContext.Provider value={{ inputMethod }}>
|
|
49
47
|
<DragDropProvider
|
|
50
48
|
// TODO Look into overriding default keybinds, might eliminate context need
|
|
51
49
|
onBeforeDragStart={(event) =>
|
|
@@ -84,13 +82,13 @@ const DataDragAndDrop = forwardRef<HTMLDivElement, DataDragAndDropProps>(
|
|
|
84
82
|
}}
|
|
85
83
|
</DragOverlay>
|
|
86
84
|
</DragDropProvider>
|
|
87
|
-
</
|
|
85
|
+
</DragAndDropLegacyContext.Provider>
|
|
88
86
|
);
|
|
89
87
|
},
|
|
90
|
-
) as
|
|
88
|
+
) as DragAndDropLegacyRootComponent;
|
|
91
89
|
|
|
92
|
-
|
|
90
|
+
DragAndDropLegacy.Item = DragAndDropItemLegacy;
|
|
93
91
|
|
|
94
|
-
export {
|
|
95
|
-
export default
|
|
96
|
-
export type {
|
|
92
|
+
export { DragAndDropLegacy, DragAndDropItemLegacy };
|
|
93
|
+
export default DragAndDropLegacy;
|
|
94
|
+
export type { DragAndDropLegacyProps };
|
|
@@ -111,6 +111,7 @@ const DataTableColumnHeader = forwardRef<
|
|
|
111
111
|
>
|
|
112
112
|
{sortable ? (
|
|
113
113
|
<button
|
|
114
|
+
type="button"
|
|
114
115
|
className="aksel-data-table__th-sort-button"
|
|
115
116
|
onClick={onSortClick}
|
|
116
117
|
>
|
|
@@ -140,6 +141,7 @@ const DataTableColumnHeader = forwardRef<
|
|
|
140
141
|
{resizeResult.enabled && !UNSAFE_isSelection && (
|
|
141
142
|
<button
|
|
142
143
|
{...resizeResult.resizeHandlerProps}
|
|
144
|
+
type="button"
|
|
143
145
|
className="aksel-data-table__th-resize-handle"
|
|
144
146
|
aria-label={
|
|
145
147
|
resizeResult.isResizingWithKeyboard
|
|
@@ -43,7 +43,11 @@ function DataTableDetailsPanelRow<T>({
|
|
|
43
43
|
|
|
44
44
|
return (
|
|
45
45
|
<tr className="aksel-data-table__details-panel-row">
|
|
46
|
-
<td
|
|
46
|
+
<td
|
|
47
|
+
id={expansionId}
|
|
48
|
+
colSpan={fullWidthColSpan}
|
|
49
|
+
className="aksel-data-table__details-panel-row-cell"
|
|
50
|
+
>
|
|
47
51
|
<div style={style}>{content}</div>
|
|
48
52
|
</td>
|
|
49
53
|
</tr>
|
|
@@ -2,20 +2,22 @@ type TableRowEntryId = string | number;
|
|
|
2
2
|
|
|
3
3
|
type CollectTableRowEntriesArgs<T> = {
|
|
4
4
|
items: T[];
|
|
5
|
-
getRowId
|
|
5
|
+
getRowId?: (rowData: T, index: number) => TableRowEntryId;
|
|
6
6
|
getRows?: (rowData: T) => T[];
|
|
7
7
|
isRowExpandable?: (rowData: T) => boolean;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
interface ItemDetail<T> {
|
|
11
|
-
id:
|
|
11
|
+
id: TableRowEntryId;
|
|
12
|
+
rowData: T;
|
|
12
13
|
level: number;
|
|
13
|
-
|
|
14
|
-
children: readonly
|
|
14
|
+
parentId: TableRowEntryId | null;
|
|
15
|
+
children: readonly TableRowEntryId[];
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
type CollectTableRowEntriesReturn<T> = {
|
|
18
|
-
itemDetails: Map<
|
|
19
|
+
itemDetails: Map<TableRowEntryId, ItemDetail<T>>;
|
|
20
|
+
rootRowIds: TableRowEntryId[];
|
|
19
21
|
/**
|
|
20
22
|
* Direct child ids for each row, used to traverse nested selection groups
|
|
21
23
|
* without storing every descendant list on each ancestor.
|
|
@@ -29,50 +31,62 @@ function collectTableRowEntries<T>({
|
|
|
29
31
|
getRows,
|
|
30
32
|
isRowExpandable,
|
|
31
33
|
}: CollectTableRowEntriesArgs<T>): CollectTableRowEntriesReturn<T> {
|
|
32
|
-
const itemDetailsMap = new Map<
|
|
34
|
+
const itemDetailsMap = new Map<TableRowEntryId, ItemDetail<T>>();
|
|
33
35
|
const childRowIdsById = new Map<TableRowEntryId, TableRowEntryId[]>();
|
|
36
|
+
const rootRowIds: TableRowEntryId[] = [];
|
|
34
37
|
|
|
35
38
|
const traverseRow = (
|
|
36
39
|
rowData: T,
|
|
37
40
|
rowIndex: number,
|
|
38
41
|
level: number,
|
|
39
|
-
|
|
42
|
+
parentRowId: TableRowEntryId | null,
|
|
40
43
|
): TableRowEntryId => {
|
|
41
|
-
const rowId = getRowId
|
|
44
|
+
const rowId = getRowId
|
|
45
|
+
? getRowId(rowData, rowIndex)
|
|
46
|
+
: getFallbackTableRowId(rowIndex, parentRowId);
|
|
42
47
|
|
|
43
48
|
const children =
|
|
44
49
|
((isRowExpandable?.(rowData) ?? true) ? getRows?.(rowData) : []) ?? [];
|
|
45
50
|
|
|
46
|
-
itemDetailsMap.set(rowData, {
|
|
47
|
-
id: rowId,
|
|
48
|
-
level,
|
|
49
|
-
parent,
|
|
50
|
-
children,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
51
|
const childRowIds: TableRowEntryId[] = [];
|
|
54
52
|
|
|
55
53
|
for (let childIndex = 0; childIndex < children.length; childIndex++) {
|
|
56
54
|
const childRow = children[childIndex];
|
|
57
|
-
const childRowId = traverseRow(childRow, childIndex, level + 1,
|
|
55
|
+
const childRowId = traverseRow(childRow, childIndex, level + 1, rowId);
|
|
58
56
|
childRowIds.push(childRowId);
|
|
59
57
|
}
|
|
60
58
|
|
|
59
|
+
itemDetailsMap.set(rowId, {
|
|
60
|
+
id: rowId,
|
|
61
|
+
rowData,
|
|
62
|
+
level,
|
|
63
|
+
parentId: parentRowId,
|
|
64
|
+
children: childRowIds,
|
|
65
|
+
});
|
|
66
|
+
|
|
61
67
|
childRowIdsById.set(rowId, childRowIds);
|
|
62
68
|
|
|
63
69
|
return rowId;
|
|
64
70
|
};
|
|
65
71
|
|
|
66
72
|
for (let rowIndex = 0; rowIndex < items.length; rowIndex++) {
|
|
67
|
-
traverseRow(items[rowIndex], rowIndex, 0, null);
|
|
73
|
+
rootRowIds.push(traverseRow(items[rowIndex], rowIndex, 0, null));
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
return {
|
|
71
77
|
itemDetails: itemDetailsMap,
|
|
78
|
+
rootRowIds,
|
|
72
79
|
childRowIdsById,
|
|
73
80
|
};
|
|
74
81
|
}
|
|
75
82
|
|
|
83
|
+
function getFallbackTableRowId(
|
|
84
|
+
rowIndex: number,
|
|
85
|
+
parentRowId: TableRowEntryId | null,
|
|
86
|
+
): string {
|
|
87
|
+
return parentRowId == null ? String(rowIndex) : `${parentRowId}.${rowIndex}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
76
90
|
export { collectTableRowEntries };
|
|
77
91
|
export type {
|
|
78
92
|
CollectTableRowEntriesArgs,
|
|
@@ -121,16 +121,70 @@ function prepareCellFocus(cell: Element): HTMLElement | null {
|
|
|
121
121
|
/**
|
|
122
122
|
* Applies focus and scroll to an element.
|
|
123
123
|
*/
|
|
124
|
+
function getStickyOffsets(element: HTMLElement): {
|
|
125
|
+
stickyOffsetStart: number;
|
|
126
|
+
stickyOffsetEnd: number;
|
|
127
|
+
stickyHeaderHeight: number;
|
|
128
|
+
} {
|
|
129
|
+
const table = element.closest(".aksel-data-table");
|
|
130
|
+
|
|
131
|
+
if (!table) {
|
|
132
|
+
return {
|
|
133
|
+
stickyOffsetStart: 0,
|
|
134
|
+
stickyOffsetEnd: 0,
|
|
135
|
+
stickyHeaderHeight: 0,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const stickyHeader = table.querySelector<HTMLElement>(
|
|
140
|
+
`.aksel-data-table__tr[data-sticky="true"]`,
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
const stickyNodesStart = table.querySelectorAll<HTMLElement>(
|
|
144
|
+
`.aksel-data-table__column-header[data-sticky="start"]`,
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const stickyNodesEnd = table.querySelectorAll<HTMLElement>(
|
|
148
|
+
`.aksel-data-table__column-header[data-sticky="end"]`,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
stickyOffsetStart: Array.from(stickyNodesStart).reduce(
|
|
153
|
+
(offset, node) => offset + node.getBoundingClientRect().width,
|
|
154
|
+
0,
|
|
155
|
+
),
|
|
156
|
+
stickyOffsetEnd: Array.from(stickyNodesEnd).reduce(
|
|
157
|
+
(offset, node) => offset + node.getBoundingClientRect().width,
|
|
158
|
+
0,
|
|
159
|
+
),
|
|
160
|
+
stickyHeaderHeight: stickyHeader?.getBoundingClientRect().height ?? 0,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
124
164
|
function applyFocusAndScroll(element: HTMLElement): void {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
element.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
165
|
+
const { stickyOffsetStart, stickyOffsetEnd, stickyHeaderHeight } =
|
|
166
|
+
getStickyOffsets(element);
|
|
167
|
+
|
|
168
|
+
const originalScrollMarginInline = element.style.scrollMarginInline;
|
|
169
|
+
const originalScrollMarginBlockStart = element.style.scrollMarginBlockStart;
|
|
170
|
+
|
|
171
|
+
element.style.scrollMarginInline = `${stickyOffsetStart}px ${stickyOffsetEnd}px`;
|
|
172
|
+
element.style.scrollMarginBlockStart = `${stickyHeaderHeight}px`;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
element.focus({
|
|
176
|
+
preventScroll: true,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
element.scrollIntoView({
|
|
180
|
+
behavior: "auto",
|
|
181
|
+
block: "nearest",
|
|
182
|
+
inline: "nearest",
|
|
183
|
+
});
|
|
184
|
+
} finally {
|
|
185
|
+
element.style.scrollMarginBlockStart = originalScrollMarginBlockStart;
|
|
186
|
+
element.style.scrollMarginInline = originalScrollMarginInline;
|
|
187
|
+
}
|
|
134
188
|
}
|
|
135
189
|
|
|
136
190
|
/**
|
|
@@ -45,6 +45,12 @@ const fallbackRows: FallbackTestRow[] = [
|
|
|
45
45
|
},
|
|
46
46
|
];
|
|
47
47
|
|
|
48
|
+
const duplicatedRowObject: TestRow = {
|
|
49
|
+
id: "shared",
|
|
50
|
+
name: "Shared",
|
|
51
|
+
subRows: [{ id: "shared-child", name: "Child" }],
|
|
52
|
+
};
|
|
53
|
+
|
|
48
54
|
const getSubRows = (row: TestRow) => row.subRows ?? [];
|
|
49
55
|
|
|
50
56
|
const getVisibleIds = (rows: TestRow[]) => rows.map((row) => row.id);
|
|
@@ -59,16 +65,18 @@ describe("useTableItems", () => {
|
|
|
59
65
|
);
|
|
60
66
|
|
|
61
67
|
expect(getVisibleIds(result.current.items)).toEqual(["a", "b"]);
|
|
62
|
-
expect(result.current.itemDetails.get(
|
|
68
|
+
expect(result.current.itemDetails.get("a")).toMatchObject({
|
|
63
69
|
id: "a",
|
|
70
|
+
rowData: plainRows[0],
|
|
64
71
|
level: 0,
|
|
65
|
-
|
|
72
|
+
parentId: null,
|
|
66
73
|
children: [],
|
|
67
74
|
});
|
|
68
|
-
expect(result.current.itemDetails.get(
|
|
75
|
+
expect(result.current.itemDetails.get("b")).toMatchObject({
|
|
69
76
|
id: "b",
|
|
77
|
+
rowData: plainRows[1],
|
|
70
78
|
level: 0,
|
|
71
|
-
|
|
79
|
+
parentId: null,
|
|
72
80
|
children: [],
|
|
73
81
|
});
|
|
74
82
|
});
|
|
@@ -102,14 +110,13 @@ describe("useTableItems", () => {
|
|
|
102
110
|
expect(result.current.childRowIdsById.get("b")).toEqual(["b1"]);
|
|
103
111
|
});
|
|
104
112
|
|
|
105
|
-
test("uses
|
|
113
|
+
test("uses unique fallback ids to reveal child rows when getRowId is omitted", () => {
|
|
106
114
|
const { result } = renderHook(() =>
|
|
107
115
|
useTableItems({
|
|
108
116
|
items: fallbackRows,
|
|
109
|
-
getRowId: (_, index) => index,
|
|
110
117
|
subRows: {
|
|
111
118
|
getRows: (row: any) => row.subRows ?? [],
|
|
112
|
-
defaultExpandedRowIds: [0],
|
|
119
|
+
defaultExpandedRowIds: ["0"],
|
|
113
120
|
},
|
|
114
121
|
}),
|
|
115
122
|
);
|
|
@@ -118,6 +125,7 @@ describe("useTableItems", () => {
|
|
|
118
125
|
"Parent",
|
|
119
126
|
"Child",
|
|
120
127
|
]);
|
|
128
|
+
expect(result.current.childRowIdsById.get("0")).toEqual(["0.0"]);
|
|
121
129
|
});
|
|
122
130
|
|
|
123
131
|
test("updates visible rows in depth-first order for controlled expanded ids", () => {
|
|
@@ -149,4 +157,35 @@ describe("useTableItems", () => {
|
|
|
149
157
|
"b1",
|
|
150
158
|
]);
|
|
151
159
|
});
|
|
160
|
+
|
|
161
|
+
test("tracks duplicated row objects by row id instead of object identity", () => {
|
|
162
|
+
const { result } = renderHook(() =>
|
|
163
|
+
useTableItems({
|
|
164
|
+
items: [duplicatedRowObject, duplicatedRowObject],
|
|
165
|
+
subRows: {
|
|
166
|
+
getRows: getSubRows,
|
|
167
|
+
defaultExpandedRowIds: ["0"],
|
|
168
|
+
},
|
|
169
|
+
}),
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
expect(result.current.visibleRowIds).toEqual(["0", "0.0", "1"]);
|
|
173
|
+
expect(getVisibleIds(result.current.items)).toEqual([
|
|
174
|
+
"shared",
|
|
175
|
+
"shared-child",
|
|
176
|
+
"shared",
|
|
177
|
+
]);
|
|
178
|
+
expect(result.current.itemDetails.get("0")).toMatchObject({
|
|
179
|
+
id: "0",
|
|
180
|
+
rowData: duplicatedRowObject,
|
|
181
|
+
parentId: null,
|
|
182
|
+
children: ["0.0"],
|
|
183
|
+
});
|
|
184
|
+
expect(result.current.itemDetails.get("1")).toMatchObject({
|
|
185
|
+
id: "1",
|
|
186
|
+
rowData: duplicatedRowObject,
|
|
187
|
+
parentId: null,
|
|
188
|
+
children: ["1.0"],
|
|
189
|
+
});
|
|
190
|
+
});
|
|
152
191
|
});
|
|
@@ -14,7 +14,7 @@ function useGridCache(tableRef: HTMLTableElement | null, enabled: boolean) {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
const [activeCell, setActiveCell] = useState<Element | null>(null);
|
|
17
|
-
const activeCellRef = useValueAsRef(activeCell)
|
|
17
|
+
const activeCellRef = useValueAsRef(activeCell);
|
|
18
18
|
const observerRef = useRef<MutationObserver | null>(null);
|
|
19
19
|
|
|
20
20
|
useEffect(() => {
|
|
@@ -24,7 +24,8 @@ function useGridCache(tableRef: HTMLTableElement | null, enabled: boolean) {
|
|
|
24
24
|
|
|
25
25
|
observerRef.current = new MutationObserver(() => {
|
|
26
26
|
gridCacheRef.current.dirty = true;
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
if (activeCellRef.current && !activeCellRef.current.isConnected) {
|
|
28
29
|
setActiveCell(null);
|
|
29
30
|
}
|
|
30
31
|
});
|
|
@@ -90,7 +90,10 @@ function DataTableDetailsPanelProvider<T>({
|
|
|
90
90
|
const tableItemsContext = useTableItemsContext(false);
|
|
91
91
|
|
|
92
92
|
const { itemDetails } = tableItemsContext ?? {
|
|
93
|
-
itemDetails: new Map
|
|
93
|
+
itemDetails: new Map<
|
|
94
|
+
string | number,
|
|
95
|
+
{ rowData: T; id: string | number; level: number }
|
|
96
|
+
>(),
|
|
94
97
|
};
|
|
95
98
|
|
|
96
99
|
const expandableIds = React.useMemo(() => {
|
|
@@ -100,7 +103,7 @@ function DataTableDetailsPanelProvider<T>({
|
|
|
100
103
|
|
|
101
104
|
const ids = new Set<string | number>();
|
|
102
105
|
|
|
103
|
-
for (const
|
|
106
|
+
for (const { rowData, id, level } of itemDetails.values()) {
|
|
104
107
|
/* We only allow Master - Details pattern on top level rows */
|
|
105
108
|
if (level > 0) {
|
|
106
109
|
continue;
|
|
@@ -17,13 +17,13 @@ type SubRowsProps<T> = {
|
|
|
17
17
|
|
|
18
18
|
type UseTableItemsArgs<T> = {
|
|
19
19
|
items: T[];
|
|
20
|
-
getRowId
|
|
20
|
+
getRowId?: (rowData: T) => TableRowEntryId;
|
|
21
21
|
subRows?: SubRowsProps<T>;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
type useTableItemsReturn<T> = {
|
|
25
25
|
items: T[];
|
|
26
|
-
itemDetails: Map<
|
|
26
|
+
itemDetails: Map<TableRowEntryId, ItemDetail<T>>;
|
|
27
27
|
/** Row ids for the rows currently rendered in the table body. */
|
|
28
28
|
visibleRowIds: TableRowEntryId[];
|
|
29
29
|
/** Direct child ids for each row, used to traverse selection groups lazily. */
|
|
@@ -57,32 +57,35 @@ function useTableItems<T>(args: UseTableItemsArgs<T>): useTableItemsReturn<T> {
|
|
|
57
57
|
|
|
58
58
|
const { itemDetails, visibleItems, visibleRowIds, childRowIdsById } =
|
|
59
59
|
useMemo(() => {
|
|
60
|
-
const {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
const {
|
|
61
|
+
itemDetails: rowEntriesMap,
|
|
62
|
+
rootRowIds,
|
|
63
|
+
childRowIdsById: _childRowIdsById,
|
|
64
|
+
} = collectTableRowEntries({
|
|
65
|
+
items,
|
|
66
|
+
getRowId,
|
|
67
|
+
getRows,
|
|
68
|
+
isRowExpandable,
|
|
69
|
+
});
|
|
67
70
|
|
|
68
71
|
const localVisibleItems: T[] = [];
|
|
69
72
|
const localVisibleRowIds: TableRowEntryId[] = [];
|
|
70
73
|
|
|
71
|
-
const addVisibleRows = (
|
|
72
|
-
const details = rowEntriesMap.get(
|
|
74
|
+
const addVisibleRows = (rowId: TableRowEntryId): TableRowEntryId[] => {
|
|
75
|
+
const details = rowEntriesMap.get(rowId);
|
|
73
76
|
|
|
74
77
|
if (!details) {
|
|
75
78
|
return [];
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
localVisibleItems.push(rowData);
|
|
81
|
+
localVisibleItems.push(details.rowData);
|
|
79
82
|
localVisibleRowIds.push(details.id);
|
|
80
83
|
|
|
81
84
|
const visibleDescendantRowIds: TableRowEntryId[] = [];
|
|
82
85
|
|
|
83
86
|
if (expandedIdsSet.has(details.id)) {
|
|
84
|
-
for (const
|
|
85
|
-
const childVisibleRowIds = addVisibleRows(
|
|
87
|
+
for (const childRowId of details.children) {
|
|
88
|
+
const childVisibleRowIds = addVisibleRows(childRowId);
|
|
86
89
|
visibleDescendantRowIds.push(...childVisibleRowIds);
|
|
87
90
|
}
|
|
88
91
|
}
|
|
@@ -90,8 +93,8 @@ function useTableItems<T>(args: UseTableItemsArgs<T>): useTableItemsReturn<T> {
|
|
|
90
93
|
return [details.id, ...visibleDescendantRowIds];
|
|
91
94
|
};
|
|
92
95
|
|
|
93
|
-
for (const
|
|
94
|
-
addVisibleRows(
|
|
96
|
+
for (const rowId of rootRowIds) {
|
|
97
|
+
addVisibleRows(rowId);
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
return {
|
|
@@ -125,9 +128,7 @@ function useTableItems<T>(args: UseTableItemsArgs<T>): useTableItemsReturn<T> {
|
|
|
125
128
|
|
|
126
129
|
const { Provider: TableItemsProvider, useContext: useTableItemsContext } =
|
|
127
130
|
/* TODO: Can we type this better? */
|
|
128
|
-
createStrictContext<
|
|
129
|
-
Omit<useTableItemsReturn<any>, "visibleRowIds" | "childRowIdsById">
|
|
130
|
-
>({
|
|
131
|
+
createStrictContext<Omit<useTableItemsReturn<any>, "childRowIdsById">>({
|
|
131
132
|
name: "TableItemsContext",
|
|
132
133
|
errorMessage:
|
|
133
134
|
"useTableItemsContext must be used within a TableItemsProvider",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import { useEventCallback } from "../../../utils/hooks";
|
|
3
3
|
import { focusInitialTableTarget } from "../helpers/table-cell";
|
|
4
|
-
import { focusCellAndUpdateTabIndex } from "../helpers/table-focus";
|
|
4
|
+
import { focusCell, focusCellAndUpdateTabIndex } from "../helpers/table-focus";
|
|
5
5
|
import {
|
|
6
6
|
findFirstCell,
|
|
7
7
|
findFirstCellInRow,
|
|
@@ -137,6 +137,10 @@ function useTableKeyboardNav({
|
|
|
137
137
|
const target = event.target as Element | null;
|
|
138
138
|
|
|
139
139
|
if (tableRef && target === tableRef) {
|
|
140
|
+
if (activeCell) {
|
|
141
|
+
focusCell(activeCell);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
140
144
|
focusInitialTableTarget(tableRef);
|
|
141
145
|
return;
|
|
142
146
|
}
|
|
@@ -173,7 +177,7 @@ function useTableKeyboardNav({
|
|
|
173
177
|
|
|
174
178
|
return {
|
|
175
179
|
/* Table should only have tabIndex until the focus is moved inside and is enabled */
|
|
176
|
-
tabIndex: enabled ?
|
|
180
|
+
tabIndex: enabled ? 0 : undefined,
|
|
177
181
|
setTableRef,
|
|
178
182
|
};
|
|
179
183
|
}
|
|
@@ -29,9 +29,6 @@ type ColumnDefinition<T, DetailsT = Record<string, any>> = Pick<
|
|
|
29
29
|
* Assigned to the cell's `th` element instead of `td` if true.
|
|
30
30
|
*
|
|
31
31
|
* Should be used for cells that act as row headers. Each row should have one rowheader, and only have one cell with `isRowHeader: true`,
|
|
32
|
-
*
|
|
33
|
-
* TODO: Not implemented
|
|
34
|
-
* - Add a generic tablecell component that can render either a td or th based on context or this prop.
|
|
35
32
|
*/
|
|
36
33
|
isRowHeader?: boolean;
|
|
37
34
|
/**
|