@navikt/ds-react 8.2.1 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/accordion/AccordionItem.d.ts +8 -6
- package/cjs/accordion/AccordionItem.js +1 -7
- package/cjs/accordion/AccordionItem.js.map +1 -1
- package/cjs/data/stories/DataTableProfiler.d.ts +6 -0
- package/cjs/data/stories/DataTableProfiler.js +124 -0
- package/cjs/data/stories/DataTableProfiler.js.map +1 -0
- package/cjs/data/stories/dummy-data.d.ts +2 -3
- package/cjs/data/stories/dummy-data.js +30 -9
- package/cjs/data/stories/dummy-data.js.map +1 -1
- package/cjs/data/table/index.d.ts +2 -2
- package/cjs/data/table/index.js +2 -1
- package/cjs/data/table/index.js.map +1 -1
- package/cjs/data/table/root/DataTableRoot.d.ts +15 -2
- package/cjs/data/table/root/DataTableRoot.js +4 -1
- package/cjs/data/table/root/DataTableRoot.js.map +1 -1
- package/cjs/data/table/tfoot/DataTableTfoot.d.ts +5 -0
- package/cjs/data/table/tfoot/DataTableTfoot.js +55 -0
- package/cjs/data/table/tfoot/DataTableTfoot.js.map +1 -0
- package/cjs/data/table/th/DataTableTh.d.ts +20 -4
- package/cjs/data/table/th/DataTableTh.js +24 -6
- package/cjs/data/table/th/DataTableTh.js.map +1 -1
- package/cjs/data/table/th/DataTableThActions.d.ts +5 -0
- package/cjs/data/table/th/DataTableThActions.js +23 -0
- package/cjs/data/table/th/DataTableThActions.js.map +1 -0
- package/cjs/data/table/th/DataTableThSortHandle.d.ts +6 -0
- package/cjs/data/table/th/DataTableThSortHandle.js +82 -0
- package/cjs/data/table/th/DataTableThSortHandle.js.map +1 -0
- package/cjs/expansion-card/ExpansionCard.d.ts +6 -5
- package/cjs/expansion-card/ExpansionCard.js +3 -9
- package/cjs/expansion-card/ExpansionCard.js.map +1 -1
- package/cjs/tooltip/Tooltip.d.ts +1 -1
- package/cjs/tooltip/Tooltip.js +35 -2
- package/cjs/tooltip/Tooltip.js.map +1 -1
- package/cjs/utils/i18n/locales/en.d.ts +3 -0
- package/cjs/utils/i18n/locales/en.js +3 -0
- package/cjs/utils/i18n/locales/en.js.map +1 -1
- package/cjs/utils/i18n/locales/nb.d.ts +4 -0
- package/cjs/utils/i18n/locales/nb.js +4 -0
- package/cjs/utils/i18n/locales/nb.js.map +1 -1
- package/cjs/utils/i18n/locales/nn.d.ts +3 -0
- package/cjs/utils/i18n/locales/nn.js +3 -0
- package/cjs/utils/i18n/locales/nn.js.map +1 -1
- package/esm/accordion/AccordionItem.d.ts +8 -6
- package/esm/accordion/AccordionItem.js +2 -8
- package/esm/accordion/AccordionItem.js.map +1 -1
- package/esm/data/stories/DataTableProfiler.d.ts +6 -0
- package/esm/data/stories/DataTableProfiler.js +89 -0
- package/esm/data/stories/DataTableProfiler.js.map +1 -0
- package/esm/data/stories/dummy-data.d.ts +2 -3
- package/esm/data/stories/dummy-data.js +30 -9
- package/esm/data/stories/dummy-data.js.map +1 -1
- package/esm/data/table/index.d.ts +2 -2
- package/esm/data/table/index.js +1 -1
- package/esm/data/table/index.js.map +1 -1
- package/esm/data/table/root/DataTableRoot.d.ts +15 -2
- package/esm/data/table/root/DataTableRoot.js +3 -1
- package/esm/data/table/root/DataTableRoot.js.map +1 -1
- package/esm/data/table/tfoot/DataTableTfoot.d.ts +5 -0
- package/esm/data/table/tfoot/DataTableTfoot.js +19 -0
- package/esm/data/table/tfoot/DataTableTfoot.js.map +1 -0
- package/esm/data/table/th/DataTableTh.d.ts +20 -4
- package/esm/data/table/th/DataTableTh.js +25 -7
- package/esm/data/table/th/DataTableTh.js.map +1 -1
- package/esm/data/table/th/DataTableThActions.d.ts +5 -0
- package/esm/data/table/th/DataTableThActions.js +18 -0
- package/esm/data/table/th/DataTableThActions.js.map +1 -0
- package/esm/data/table/th/DataTableThSortHandle.d.ts +6 -0
- package/esm/data/table/th/DataTableThSortHandle.js +47 -0
- package/esm/data/table/th/DataTableThSortHandle.js.map +1 -0
- package/esm/expansion-card/ExpansionCard.d.ts +6 -5
- package/esm/expansion-card/ExpansionCard.js +4 -10
- package/esm/expansion-card/ExpansionCard.js.map +1 -1
- package/esm/tooltip/Tooltip.d.ts +1 -1
- package/esm/tooltip/Tooltip.js +35 -2
- package/esm/tooltip/Tooltip.js.map +1 -1
- package/esm/utils/i18n/locales/en.d.ts +3 -0
- package/esm/utils/i18n/locales/en.js +3 -0
- package/esm/utils/i18n/locales/en.js.map +1 -1
- package/esm/utils/i18n/locales/nb.d.ts +4 -0
- package/esm/utils/i18n/locales/nb.js +4 -0
- package/esm/utils/i18n/locales/nb.js.map +1 -1
- package/esm/utils/i18n/locales/nn.d.ts +3 -0
- package/esm/utils/i18n/locales/nn.js +3 -0
- package/esm/utils/i18n/locales/nn.js.map +1 -1
- package/package.json +3 -3
- package/src/accordion/AccordionItem.tsx +11 -18
- package/src/data/stories/DataTableProfiler.tsx +215 -0
- package/src/data/stories/dummy-data.tsx +39 -17
- package/src/data/table/index.tsx +2 -0
- package/src/data/table/root/DataTableRoot.tsx +19 -0
- package/src/data/table/tfoot/DataTableTfoot.tsx +21 -0
- package/src/data/table/th/DataTableTh.tsx +68 -31
- package/src/data/table/th/DataTableThActions.tsx +32 -0
- package/src/data/table/th/DataTableThSortHandle.tsx +67 -0
- package/src/expansion-card/ExpansionCard.tsx +15 -21
- package/src/tooltip/Tooltip.tsx +66 -11
- package/src/utils/i18n/locales/en.ts +3 -0
- package/src/utils/i18n/locales/nb.ts +3 -0
- package/src/utils/i18n/locales/nn.ts +3 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createColumnHelper } from "@tanstack/react-table";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import { HStack } from "../../layout/stack";
|
|
4
3
|
import { Tag } from "../../tag";
|
|
5
4
|
|
|
6
5
|
// Helper function to get random integer between min and max (inclusive)
|
|
@@ -18,7 +17,7 @@ const getRandomItems = <T,>(arr: T[], min = 1, max = 5): T[] => {
|
|
|
18
17
|
return shuffled.slice(0, count);
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
interface PersonInfo {
|
|
20
|
+
export interface PersonInfo {
|
|
22
21
|
// id: number;
|
|
23
22
|
name: string;
|
|
24
23
|
nationalId: string;
|
|
@@ -66,26 +65,49 @@ export const columns = [
|
|
|
66
65
|
{
|
|
67
66
|
header: "Age",
|
|
68
67
|
accessorKey: "age",
|
|
68
|
+
footer: ({ table }) => {
|
|
69
|
+
const ages: number[] = [];
|
|
70
|
+
table.getFilteredRowModel().rows.forEach((row) => {
|
|
71
|
+
const value = row.getValue("age");
|
|
72
|
+
value && ages.push(value);
|
|
73
|
+
});
|
|
74
|
+
return `Avg: ${(ages.reduce((a, b) => a + b, 0) / ages.length).toFixed(2)}`;
|
|
75
|
+
},
|
|
69
76
|
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
|
|
78
|
+
columnHelper.accessor("forceSensitive", {
|
|
79
|
+
cell: (info) => {
|
|
80
|
+
const value = info.getValue();
|
|
81
|
+
return (
|
|
82
|
+
<Tag
|
|
83
|
+
size="small"
|
|
84
|
+
variant="moderate"
|
|
85
|
+
data-color={value ? "accent" : "warning"}
|
|
86
|
+
>{`${value ? "Yes" : "No"}`}</Tag>
|
|
87
|
+
);
|
|
88
|
+
},
|
|
89
|
+
footer: ({ table }) => {
|
|
90
|
+
const totals = new Map();
|
|
91
|
+
totals.set("Yes", 0);
|
|
92
|
+
totals.set("No", 0);
|
|
93
|
+
table.getFilteredRowModel().rows.forEach((row) => {
|
|
94
|
+
const value = row.getValue("forceSensitive");
|
|
95
|
+
totals.set(
|
|
96
|
+
value ? "Yes" : "No",
|
|
97
|
+
(totals.get(value ? "Yes" : "No") ?? 0) + 1,
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
return `Yes: ${totals.get("Yes")}, No: ${totals.get("No")}`;
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
74
103
|
{
|
|
75
104
|
header: "Home system",
|
|
76
105
|
accessorKey: "homeSystem",
|
|
77
106
|
},
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<Tag key={skill} size="small">
|
|
83
|
-
{skill}
|
|
84
|
-
</Tag>
|
|
85
|
-
))}
|
|
86
|
-
</HStack>
|
|
87
|
-
),
|
|
88
|
-
}),
|
|
107
|
+
{
|
|
108
|
+
header: "Skills",
|
|
109
|
+
accessorKey: "skills",
|
|
110
|
+
},
|
|
89
111
|
];
|
|
90
112
|
|
|
91
113
|
export const homeSystemOptions = [
|
package/src/data/table/index.tsx
CHANGED
|
@@ -7,6 +7,7 @@ export {
|
|
|
7
7
|
DataTableTr,
|
|
8
8
|
DataTableTh,
|
|
9
9
|
DataTableTd,
|
|
10
|
+
DataTableTfoot,
|
|
10
11
|
} from "./root/DataTableRoot";
|
|
11
12
|
export type {
|
|
12
13
|
DataTableProps,
|
|
@@ -16,4 +17,5 @@ export type {
|
|
|
16
17
|
DataTableTrProps,
|
|
17
18
|
DataTableThProps,
|
|
18
19
|
DataTableTdProps,
|
|
20
|
+
DataTableTfootProps,
|
|
19
21
|
} from "./root/DataTableRoot";
|
|
@@ -9,6 +9,10 @@ import {
|
|
|
9
9
|
type DataTableTbodyProps,
|
|
10
10
|
} from "../tbody/DataTableTbody";
|
|
11
11
|
import { DataTableTd, type DataTableTdProps } from "../td/DataTableTd";
|
|
12
|
+
import {
|
|
13
|
+
DataTableTfoot,
|
|
14
|
+
type DataTableTfootProps,
|
|
15
|
+
} from "../tfoot/DataTableTfoot";
|
|
12
16
|
import { DataTableTh, type DataTableThProps } from "../th/DataTableTh";
|
|
13
17
|
import {
|
|
14
18
|
DataTableThead,
|
|
@@ -101,6 +105,18 @@ interface DataTableRootComponent extends React.ForwardRefExoticComponent<
|
|
|
101
105
|
* ```
|
|
102
106
|
*/
|
|
103
107
|
Td: typeof DataTableTd;
|
|
108
|
+
/**
|
|
109
|
+
* @see 🏷️ {@link DataTableTfootProps}
|
|
110
|
+
* @example
|
|
111
|
+
* ```jsx
|
|
112
|
+
* <DataTable>
|
|
113
|
+
* <DataTable.Tfoot>
|
|
114
|
+
* ...
|
|
115
|
+
* </DataTable.Tfoot>
|
|
116
|
+
* </DataTable>
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
Tfoot: typeof DataTableTfoot;
|
|
104
120
|
}
|
|
105
121
|
|
|
106
122
|
const DataTable = forwardRef<HTMLTableElement, DataTableProps>(
|
|
@@ -123,6 +139,7 @@ DataTable.Tbody = DataTableTbody;
|
|
|
123
139
|
DataTable.Th = DataTableTh;
|
|
124
140
|
DataTable.Tr = DataTableTr;
|
|
125
141
|
DataTable.Td = DataTableTd;
|
|
142
|
+
DataTable.Tfoot = DataTableTfoot;
|
|
126
143
|
|
|
127
144
|
export {
|
|
128
145
|
DataTable,
|
|
@@ -132,6 +149,7 @@ export {
|
|
|
132
149
|
DataTableTh,
|
|
133
150
|
DataTableThead,
|
|
134
151
|
DataTableTr,
|
|
152
|
+
DataTableTfoot,
|
|
135
153
|
};
|
|
136
154
|
export default DataTable;
|
|
137
155
|
export type {
|
|
@@ -142,4 +160,5 @@ export type {
|
|
|
142
160
|
DataTableThProps,
|
|
143
161
|
DataTableTheadProps,
|
|
144
162
|
DataTableTrProps,
|
|
163
|
+
DataTableTfootProps,
|
|
145
164
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import { cl } from "../../../utils/helpers";
|
|
3
|
+
|
|
4
|
+
type DataTableTfootProps = React.HTMLAttributes<HTMLTableSectionElement>;
|
|
5
|
+
|
|
6
|
+
const DataTableTfoot = forwardRef<HTMLTableSectionElement, DataTableTfootProps>(
|
|
7
|
+
({ className, children, ...rest }, forwardedRef) => {
|
|
8
|
+
return (
|
|
9
|
+
<tfoot
|
|
10
|
+
{...rest}
|
|
11
|
+
ref={forwardedRef}
|
|
12
|
+
className={cl("aksel-data-table__tfoot", className)}
|
|
13
|
+
>
|
|
14
|
+
{children}
|
|
15
|
+
</tfoot>
|
|
16
|
+
);
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
export { DataTableTfoot };
|
|
21
|
+
export type { DataTableTfootProps };
|
|
@@ -1,64 +1,101 @@
|
|
|
1
1
|
import React, { forwardRef } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
PushPinIcon,
|
|
6
|
-
} from "@navikt/aksel-icons";
|
|
7
|
-
import { Button } from "../../../button";
|
|
2
|
+
import { FunnelIcon, SortDownIcon, SortUpIcon } from "@navikt/aksel-icons";
|
|
3
|
+
import { HStack, Spacer } from "../../../layout/stack";
|
|
4
|
+
import { ActionMenu } from "../../../overlays/action-menu";
|
|
8
5
|
import { cl } from "../../../utils/helpers";
|
|
6
|
+
import { DataTableThActions } from "./DataTableThActions";
|
|
7
|
+
import { DataTableThSortHandle } from "./DataTableThSortHandle";
|
|
9
8
|
|
|
10
9
|
type DataTableThProps = React.HTMLAttributes<HTMLTableCellElement> & {
|
|
11
10
|
resizeHandler?: React.MouseEventHandler<HTMLButtonElement>;
|
|
12
|
-
isPinned?: boolean;
|
|
13
|
-
pinningHandler?: React.MouseEventHandler<HTMLButtonElement>;
|
|
14
11
|
size?: number;
|
|
12
|
+
sortDirection?: "asc" | "desc" | "none" | false;
|
|
13
|
+
onSortChange?: (direction: "asc" | "desc" | "none", event: Event) => void;
|
|
14
|
+
render?: {
|
|
15
|
+
filterMenu?: {
|
|
16
|
+
title: string;
|
|
17
|
+
content: React.ReactNode;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
15
20
|
};
|
|
16
21
|
|
|
22
|
+
/**
|
|
23
|
+
* TODO:
|
|
24
|
+
* - Plan for pinning: Move it into "settings" dialog like here: https://cloudscape.design/examples/react/table.html
|
|
25
|
+
*/
|
|
17
26
|
const DataTableTh = forwardRef<HTMLTableCellElement, DataTableThProps>(
|
|
18
27
|
(
|
|
19
28
|
{
|
|
20
29
|
className,
|
|
21
30
|
children,
|
|
22
31
|
resizeHandler,
|
|
23
|
-
isPinned = false,
|
|
24
|
-
pinningHandler,
|
|
25
32
|
size,
|
|
33
|
+
sortDirection,
|
|
34
|
+
onSortChange,
|
|
35
|
+
style,
|
|
36
|
+
render,
|
|
26
37
|
...rest
|
|
27
38
|
},
|
|
28
39
|
forwardedRef,
|
|
29
40
|
) => {
|
|
41
|
+
const { filterMenu } = render || {};
|
|
42
|
+
|
|
30
43
|
return (
|
|
31
44
|
<th
|
|
32
45
|
{...rest}
|
|
33
46
|
ref={forwardedRef}
|
|
34
47
|
className={cl("aksel-data-table__th", className)}
|
|
35
|
-
style={{ width: size }}
|
|
48
|
+
style={{ width: size, ...style }}
|
|
36
49
|
>
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
variant="secondary"
|
|
43
|
-
icon={
|
|
44
|
-
isPinned ? (
|
|
45
|
-
<PushPinFillIcon aria-hidden title="Fest kolonne" />
|
|
46
|
-
) : (
|
|
47
|
-
<PushPinIcon aria-hidden title="Løstne kolonne" />
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
+
<HStack align="center" gap="space-8" wrap={false}>
|
|
51
|
+
<div className="aksel-data-table__th-content">{children}</div>
|
|
52
|
+
<DataTableThSortHandle
|
|
53
|
+
sortDirection={sortDirection}
|
|
54
|
+
onSortChange={onSortChange}
|
|
50
55
|
/>
|
|
51
|
-
|
|
56
|
+
<Spacer />
|
|
57
|
+
|
|
58
|
+
<DataTableThActions>
|
|
59
|
+
{/* TODO: onSortChange just rotates between the three states now */}
|
|
60
|
+
{/* TODO: Sorting texts do not handle different data-types now */}
|
|
61
|
+
{sortDirection && (
|
|
62
|
+
<ActionMenu.Group label="Sortering">
|
|
63
|
+
<ActionMenu.Item
|
|
64
|
+
onSelect={(event) => onSortChange?.("desc", event)}
|
|
65
|
+
icon={<SortUpIcon aria-hidden />}
|
|
66
|
+
>
|
|
67
|
+
{sortDirection === "desc" ? "Fjern sortering" : "A-Z"}
|
|
68
|
+
</ActionMenu.Item>
|
|
69
|
+
<ActionMenu.Item
|
|
70
|
+
onSelect={(event) => onSortChange?.("asc", event)}
|
|
71
|
+
icon={<SortDownIcon aria-hidden />}
|
|
72
|
+
>
|
|
73
|
+
{sortDirection === "asc" ? "Fjern sortering" : "Z-A"}
|
|
74
|
+
</ActionMenu.Item>
|
|
75
|
+
</ActionMenu.Group>
|
|
76
|
+
)}
|
|
77
|
+
{filterMenu && (
|
|
78
|
+
<ActionMenu.Group label="Filter">
|
|
79
|
+
<ActionMenu.Sub>
|
|
80
|
+
<ActionMenu.SubTrigger icon={<FunnelIcon aria-hidden />}>
|
|
81
|
+
{filterMenu.title}
|
|
82
|
+
</ActionMenu.SubTrigger>
|
|
83
|
+
<ActionMenu.SubContent>
|
|
84
|
+
{/* TODO: ActionMenu stops tab from working, so user cant tab "into" filter now even when wrapper has focus */}
|
|
85
|
+
{filterMenu.content}
|
|
86
|
+
</ActionMenu.SubContent>
|
|
87
|
+
</ActionMenu.Sub>
|
|
88
|
+
</ActionMenu.Group>
|
|
89
|
+
)}
|
|
90
|
+
</DataTableThActions>
|
|
91
|
+
</HStack>
|
|
92
|
+
|
|
52
93
|
{resizeHandler && (
|
|
53
|
-
<
|
|
94
|
+
<button
|
|
54
95
|
onMouseDown={resizeHandler}
|
|
55
96
|
onMouseUp={resizeHandler}
|
|
56
97
|
className={cl("aksel-data-table__th-resize-handle")}
|
|
57
|
-
|
|
58
|
-
variant="secondary"
|
|
59
|
-
icon={
|
|
60
|
-
<CaretLeftRightIcon aria-hidden title="Endre kolonnestørrelse" />
|
|
61
|
-
}
|
|
98
|
+
data-color="neutral"
|
|
62
99
|
/>
|
|
63
100
|
)}
|
|
64
101
|
</th>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { MenuElipsisVerticalIcon } from "@navikt/aksel-icons";
|
|
3
|
+
import { Button } from "../../../button";
|
|
4
|
+
import { ActionMenu } from "../../../overlays/action-menu";
|
|
5
|
+
|
|
6
|
+
function DataTableThActions({ children }: { children?: React.ReactNode }) {
|
|
7
|
+
const [open, setOpen] = React.useState(false);
|
|
8
|
+
/* TODO: Fix this */
|
|
9
|
+
// @ts-expect-error Temp hack to hide when no children present
|
|
10
|
+
if (!children || !children.filter(Boolean).length) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<ActionMenu open={open} onOpenChange={setOpen}>
|
|
16
|
+
<ActionMenu.Trigger>
|
|
17
|
+
<Button
|
|
18
|
+
data-color="neutral"
|
|
19
|
+
variant="tertiary"
|
|
20
|
+
size="small"
|
|
21
|
+
icon={<MenuElipsisVerticalIcon title="Åpne kolonnemeny" />}
|
|
22
|
+
onClick={() => setOpen(!open)}
|
|
23
|
+
data-expanded={open}
|
|
24
|
+
className="aksel-data-table__th-action-button"
|
|
25
|
+
/>
|
|
26
|
+
</ActionMenu.Trigger>
|
|
27
|
+
<ActionMenu.Content>{children}</ActionMenu.Content>
|
|
28
|
+
</ActionMenu>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { DataTableThActions };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ArrowsUpDownIcon,
|
|
4
|
+
SortDownIcon,
|
|
5
|
+
SortUpIcon,
|
|
6
|
+
} from "@navikt/aksel-icons";
|
|
7
|
+
import { Button } from "../../../button";
|
|
8
|
+
|
|
9
|
+
const ICON_CONFIG = {
|
|
10
|
+
desc: {
|
|
11
|
+
icon: SortDownIcon,
|
|
12
|
+
title: "Sorter stigende",
|
|
13
|
+
},
|
|
14
|
+
asc: {
|
|
15
|
+
icon: SortUpIcon,
|
|
16
|
+
title: "Ingen sortering",
|
|
17
|
+
},
|
|
18
|
+
none: {
|
|
19
|
+
icon: ArrowsUpDownIcon,
|
|
20
|
+
title: "Sorter synkende",
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function DataTableThSortHandle({
|
|
25
|
+
sortDirection = false,
|
|
26
|
+
onSortChange,
|
|
27
|
+
}: {
|
|
28
|
+
sortDirection?: "asc" | "desc" | "none" | false;
|
|
29
|
+
onSortChange?: (direction: "asc" | "desc" | "none", event: Event) => void;
|
|
30
|
+
}) {
|
|
31
|
+
const IconConfig = useMemo(() => {
|
|
32
|
+
if (!sortDirection) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return ICON_CONFIG[sortDirection];
|
|
36
|
+
}, [sortDirection]);
|
|
37
|
+
|
|
38
|
+
if (!sortDirection || !IconConfig) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Button
|
|
44
|
+
data-color="neutral"
|
|
45
|
+
variant="tertiary"
|
|
46
|
+
size="small"
|
|
47
|
+
icon={<IconConfig.icon title={IconConfig.title} />}
|
|
48
|
+
onClick={(event) => {
|
|
49
|
+
if (!onSortChange) return;
|
|
50
|
+
|
|
51
|
+
/* TODO: This configuration is not a given */
|
|
52
|
+
let newDirection: "asc" | "desc" | "none";
|
|
53
|
+
if (sortDirection === "none") {
|
|
54
|
+
newDirection = "asc";
|
|
55
|
+
} else if (sortDirection === "asc") {
|
|
56
|
+
newDirection = "desc";
|
|
57
|
+
} else {
|
|
58
|
+
newDirection = "none";
|
|
59
|
+
}
|
|
60
|
+
/* TODO: Handle types better */
|
|
61
|
+
onSortChange(newDirection, event as unknown as Event);
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export { DataTableThSortHandle };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
2
|
import type { AkselColor } from "../types";
|
|
3
3
|
import type { OverridableComponent } from "../utils-external";
|
|
4
4
|
import { cl } from "../utils/helpers";
|
|
@@ -19,10 +19,9 @@ import {
|
|
|
19
19
|
} from "./ExpansionCardTitle";
|
|
20
20
|
import { ExpansionCardContext } from "./context";
|
|
21
21
|
|
|
22
|
-
interface ExpansionCardComponent
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
> {
|
|
22
|
+
interface ExpansionCardComponent extends React.ForwardRefExoticComponent<
|
|
23
|
+
ExpansionCardProps & React.RefAttributes<HTMLDivElement>
|
|
24
|
+
> {
|
|
26
25
|
/**
|
|
27
26
|
* @see 🏷️ {@link ExpansionCardHeaderProps}
|
|
28
27
|
*/
|
|
@@ -48,20 +47,23 @@ interface ExpansionCardComponent
|
|
|
48
47
|
>;
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
interface ExpansionCardCommonProps
|
|
52
|
-
|
|
50
|
+
interface ExpansionCardCommonProps extends Omit<
|
|
51
|
+
React.HTMLAttributes<HTMLDivElement>,
|
|
52
|
+
"onToggle"
|
|
53
|
+
> {
|
|
53
54
|
children: React.ReactNode;
|
|
54
55
|
/**
|
|
55
|
-
* Callback for when Card is
|
|
56
|
+
* Callback for when Card is opened/closed.
|
|
56
57
|
*/
|
|
57
58
|
onToggle?: (open: boolean) => void;
|
|
58
59
|
/**
|
|
59
|
-
* Controlled open-state
|
|
60
|
-
*
|
|
60
|
+
* Controlled open-state.
|
|
61
|
+
*
|
|
62
|
+
* Using this removes automatic control of open-state.
|
|
61
63
|
*/
|
|
62
64
|
open?: boolean;
|
|
63
65
|
/**
|
|
64
|
-
*
|
|
66
|
+
* The open state when initially rendered. Use when you do not need to control the open state.
|
|
65
67
|
* @default false
|
|
66
68
|
*/
|
|
67
69
|
defaultOpen?: boolean;
|
|
@@ -102,7 +104,7 @@ export type ExpansionCardProps = ExpansionCardCommonProps &
|
|
|
102
104
|
*
|
|
103
105
|
* @example
|
|
104
106
|
* ```jsx
|
|
105
|
-
* <ExpansionCard aria-label="
|
|
107
|
+
* <ExpansionCard aria-label="Utbetaling av sykepenger">
|
|
106
108
|
* <ExpansionCard.Header>
|
|
107
109
|
* <ExpansionCard.Title>Utbetaling av sykepenger</ExpansionCard.Title>
|
|
108
110
|
* </ExpansionCard.Header>
|
|
@@ -125,14 +127,9 @@ export const ExpansionCard = forwardRef<HTMLDivElement, ExpansionCardProps>(
|
|
|
125
127
|
},
|
|
126
128
|
ref,
|
|
127
129
|
) => {
|
|
128
|
-
const shouldFade = useRef<boolean>(!(Boolean(open) || defaultOpen));
|
|
129
|
-
|
|
130
130
|
const [_open, _setOpen] = useControllableState({
|
|
131
131
|
value: open,
|
|
132
|
-
onChange:
|
|
133
|
-
onToggle?.(newValue);
|
|
134
|
-
shouldFade.current = true;
|
|
135
|
-
},
|
|
132
|
+
onChange: onToggle,
|
|
136
133
|
defaultValue: defaultOpen,
|
|
137
134
|
});
|
|
138
135
|
|
|
@@ -151,9 +148,6 @@ export const ExpansionCard = forwardRef<HTMLDivElement, ExpansionCardProps>(
|
|
|
151
148
|
"aksel-expansioncard",
|
|
152
149
|
className,
|
|
153
150
|
`aksel-expansioncard--${size}`,
|
|
154
|
-
{
|
|
155
|
-
"aksel-expansioncard--no-animation": !shouldFade.current,
|
|
156
|
-
},
|
|
157
151
|
)}
|
|
158
152
|
ref={ref}
|
|
159
153
|
/>
|
package/src/tooltip/Tooltip.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
useInteractions,
|
|
13
13
|
} from "@floating-ui/react";
|
|
14
14
|
import React, { HTMLAttributes, forwardRef, useRef } from "react";
|
|
15
|
+
import { HStack } from "../layout/stack";
|
|
15
16
|
import { useModalContext } from "../modal/Modal.context";
|
|
16
17
|
import { Portal } from "../portal";
|
|
17
18
|
import { Detail } from "../typography";
|
|
@@ -19,6 +20,7 @@ import { useId } from "../utils-external";
|
|
|
19
20
|
import { Slot } from "../utils/components/slot/Slot";
|
|
20
21
|
import { cl } from "../utils/helpers";
|
|
21
22
|
import { useControllableState, useMergeRefs } from "../utils/hooks";
|
|
23
|
+
import { useI18n } from "../utils/i18n/i18n.hooks";
|
|
22
24
|
|
|
23
25
|
export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
|
|
24
26
|
/**
|
|
@@ -79,7 +81,7 @@ export interface TooltipProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
79
81
|
/**
|
|
80
82
|
* List of Keyboard-keys for shortcuts.
|
|
81
83
|
*/
|
|
82
|
-
keys?: string[];
|
|
84
|
+
keys?: string[] | [string[], string[]];
|
|
83
85
|
/**
|
|
84
86
|
* When false, Tooltip labels the element, and child-elements content will be ignored by screen-readers.
|
|
85
87
|
* When true, content is added as additional information to the child element.
|
|
@@ -204,7 +206,7 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
|
|
204
206
|
ref={refs.setReference}
|
|
205
207
|
{...getReferenceProps()}
|
|
206
208
|
{...labelProps}
|
|
207
|
-
aria-keyshortcuts={keys
|
|
209
|
+
aria-keyshortcuts={ariaShortcuts(keys)}
|
|
208
210
|
>
|
|
209
211
|
{children}
|
|
210
212
|
</Slot>
|
|
@@ -232,15 +234,7 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
|
|
232
234
|
data-state="open"
|
|
233
235
|
>
|
|
234
236
|
{content}
|
|
235
|
-
{keys
|
|
236
|
-
<span className="aksel-tooltip__keys" aria-hidden>
|
|
237
|
-
{keys.map((key) => (
|
|
238
|
-
<Detail as="kbd" key={key} className="aksel-tooltip__key">
|
|
239
|
-
{key}
|
|
240
|
-
</Detail>
|
|
241
|
-
))}
|
|
242
|
-
</span>
|
|
243
|
-
)}
|
|
237
|
+
<TooltipShortcuts shortcuts={keys} />
|
|
244
238
|
{_arrow && (
|
|
245
239
|
<div
|
|
246
240
|
ref={(node) => {
|
|
@@ -269,4 +263,65 @@ export const Tooltip = forwardRef<HTMLDivElement, TooltipProps>(
|
|
|
269
263
|
},
|
|
270
264
|
);
|
|
271
265
|
|
|
266
|
+
function isKeyShortcutNested(
|
|
267
|
+
shortcuts: TooltipProps["keys"],
|
|
268
|
+
): shortcuts is [string[], string[]] {
|
|
269
|
+
return Array.isArray(shortcuts?.[0]);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-keyshortcuts
|
|
274
|
+
* Space-separated shortcuts is valid syntax
|
|
275
|
+
*/
|
|
276
|
+
function ariaShortcuts(shortcuts: TooltipProps["keys"]) {
|
|
277
|
+
if (!shortcuts) {
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (isKeyShortcutNested(shortcuts)) {
|
|
282
|
+
return shortcuts.map((key) => key.join("+")).join(" ");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return shortcuts.join("+");
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function TooltipShortcuts({ shortcuts }: { shortcuts: TooltipProps["keys"] }) {
|
|
289
|
+
const translate = useI18n("Tooltip");
|
|
290
|
+
|
|
291
|
+
if (!shortcuts) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (isKeyShortcutNested(shortcuts)) {
|
|
296
|
+
return (
|
|
297
|
+
<span className="aksel-tooltip__keys" aria-hidden>
|
|
298
|
+
{shortcuts.map((key, index) => (
|
|
299
|
+
<>
|
|
300
|
+
<HStack gap="space-4">
|
|
301
|
+
{key.map((k, i) => (
|
|
302
|
+
<Detail as="kbd" key={i} className="aksel-tooltip__key">
|
|
303
|
+
{k}
|
|
304
|
+
</Detail>
|
|
305
|
+
))}
|
|
306
|
+
</HStack>
|
|
307
|
+
{index < shortcuts.length - 1 && (
|
|
308
|
+
<span> {translate("shortcutSeparator")} </span>
|
|
309
|
+
)}
|
|
310
|
+
</>
|
|
311
|
+
))}
|
|
312
|
+
</span>
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
<span className="aksel-tooltip__keys" aria-hidden>
|
|
318
|
+
{shortcuts.map((k, i) => (
|
|
319
|
+
<Detail as="kbd" key={i} className="aksel-tooltip__key">
|
|
320
|
+
{k}
|
|
321
|
+
</Detail>
|
|
322
|
+
))}
|
|
323
|
+
</span>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
272
327
|
export default Tooltip;
|