@navikt/ds-react 4.7.4 → 4.9.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/_docs.json +389 -1
- package/cjs/index.js +1 -0
- package/cjs/layout/stack/HStack.js +51 -0
- package/cjs/layout/stack/Spacer.js +21 -0
- package/cjs/layout/stack/Stack.js +51 -0
- package/cjs/layout/stack/VStack.js +51 -0
- package/cjs/layout/stack/index.js +9 -0
- package/cjs/layout/stack/package.json +6 -0
- package/cjs/layout/utilities/css.js +17 -0
- package/cjs/table/ExpandableRow.js +20 -8
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/index.js.map +1 -1
- package/esm/layout/stack/HStack.d.ts +24 -0
- package/esm/layout/stack/HStack.js +26 -0
- package/esm/layout/stack/HStack.js.map +1 -0
- package/esm/layout/stack/Spacer.d.ts +14 -0
- package/esm/layout/stack/Spacer.js +15 -0
- package/esm/layout/stack/Spacer.js.map +1 -0
- package/esm/layout/stack/Stack.d.ts +26 -0
- package/esm/layout/stack/Stack.js +23 -0
- package/esm/layout/stack/Stack.js.map +1 -0
- package/esm/layout/stack/VStack.d.ts +24 -0
- package/esm/layout/stack/VStack.js +26 -0
- package/esm/layout/stack/VStack.js.map +1 -0
- package/esm/layout/stack/index.d.ts +3 -0
- package/esm/layout/stack/index.js +4 -0
- package/esm/layout/stack/index.js.map +1 -0
- package/esm/layout/utilities/css.d.ts +10 -0
- package/esm/layout/utilities/css.js +14 -0
- package/esm/layout/utilities/css.js.map +1 -0
- package/esm/table/ExpandableRow.d.ts +6 -1
- package/esm/table/ExpandableRow.js +20 -8
- package/esm/table/ExpandableRow.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/layout/stack/HStack.tsx +30 -0
- package/src/layout/stack/Spacer.tsx +15 -0
- package/src/layout/stack/Stack.tsx +76 -0
- package/src/layout/stack/VStack.tsx +30 -0
- package/src/layout/stack/index.ts +3 -0
- package/src/layout/stack/stack.stories.tsx +161 -0
- package/src/layout/utilities/css.ts +56 -0
- package/src/table/ExpandableRow.tsx +28 -8
- package/src/table/stories/table-expandable.stories.tsx +62 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta } from "@storybook/react";
|
|
3
|
+
import { HStack, VStack, Spacer } from ".";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: "ds-react/Stack",
|
|
7
|
+
component: HStack,
|
|
8
|
+
} satisfies Meta<typeof HStack>;
|
|
9
|
+
|
|
10
|
+
export const Horizontal = {
|
|
11
|
+
render: () => (
|
|
12
|
+
<HStack gap="4">
|
|
13
|
+
<Placeholders count={4} />
|
|
14
|
+
</HStack>
|
|
15
|
+
),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const Spacing = {
|
|
19
|
+
render: () => (
|
|
20
|
+
<div style={{ height: "80vh", display: "flex" }}>
|
|
21
|
+
<VStack gap="8">
|
|
22
|
+
<Spacer />
|
|
23
|
+
<HStack gap="4">
|
|
24
|
+
<Placeholders count={1} />
|
|
25
|
+
<Spacer />
|
|
26
|
+
<Placeholders count={1} />
|
|
27
|
+
</HStack>
|
|
28
|
+
<HStack gap="4">
|
|
29
|
+
<Placeholders count={1} />
|
|
30
|
+
<Placeholders count={1} />
|
|
31
|
+
</HStack>
|
|
32
|
+
<HStack gap="4">
|
|
33
|
+
<Placeholders count={2} />
|
|
34
|
+
</HStack>
|
|
35
|
+
</VStack>
|
|
36
|
+
</div>
|
|
37
|
+
),
|
|
38
|
+
parameters: {
|
|
39
|
+
layout: "fullscreen",
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Vertical = {
|
|
44
|
+
render: () => (
|
|
45
|
+
<VStack gap="4">
|
|
46
|
+
<Placeholders count={4} />
|
|
47
|
+
</VStack>
|
|
48
|
+
),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const VerticalDemo = {
|
|
52
|
+
render: () => (
|
|
53
|
+
<VStack gap="2">
|
|
54
|
+
<VStack>
|
|
55
|
+
<Placeholders count={4} />
|
|
56
|
+
</VStack>
|
|
57
|
+
<Placeholders count={4} />
|
|
58
|
+
<VStack>
|
|
59
|
+
<Placeholders count={4} />
|
|
60
|
+
</VStack>
|
|
61
|
+
</VStack>
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const VerticalAlign = {
|
|
66
|
+
render: () => (
|
|
67
|
+
<VStack gap="4">
|
|
68
|
+
<VStack align="start">
|
|
69
|
+
<Placeholders count={2} />
|
|
70
|
+
</VStack>
|
|
71
|
+
<VStack align="center">
|
|
72
|
+
<Placeholders count={2} />
|
|
73
|
+
</VStack>
|
|
74
|
+
<VStack align="end">
|
|
75
|
+
<Placeholders count={2} />
|
|
76
|
+
</VStack>
|
|
77
|
+
</VStack>
|
|
78
|
+
),
|
|
79
|
+
parameters: {
|
|
80
|
+
layout: "fullscreen",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const OverrideComponent = {
|
|
85
|
+
render: () => (
|
|
86
|
+
<VStack gap="4" as="form" onSubmit={(e) => e.preventDefault()}>
|
|
87
|
+
<Placeholders count={4} />
|
|
88
|
+
</VStack>
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export const Responsive = {
|
|
93
|
+
render: () => (
|
|
94
|
+
<VStack gap={{ xs: "1", sm: "3", md: "6", lg: "10", xl: "16" }}>
|
|
95
|
+
<Placeholders count={4} />
|
|
96
|
+
</VStack>
|
|
97
|
+
),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const Nested = {
|
|
101
|
+
render: () => (
|
|
102
|
+
<VStack gap="16">
|
|
103
|
+
<Placeholders count={2}>
|
|
104
|
+
<VStack gap="4">
|
|
105
|
+
<Placeholders count={2} color="gray" />
|
|
106
|
+
</VStack>
|
|
107
|
+
</Placeholders>
|
|
108
|
+
</VStack>
|
|
109
|
+
),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const DividerDemo = {
|
|
113
|
+
render: () => (
|
|
114
|
+
<div style={{ height: "80vh", width: "40rem" }}>
|
|
115
|
+
<VStack gap={{ xs: "2", md: "6", lg: "12" }}>
|
|
116
|
+
<HStack gap={{ xs: "2", md: "6", lg: "12" }}>
|
|
117
|
+
<Placeholders count={1} />
|
|
118
|
+
<Spacer />
|
|
119
|
+
<Placeholders count={1} />
|
|
120
|
+
</HStack>
|
|
121
|
+
<hr
|
|
122
|
+
style={{
|
|
123
|
+
border: "none",
|
|
124
|
+
borderBottom: "1px solid var(--a-border-divider)",
|
|
125
|
+
margin: 0,
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
<HStack gap={{ xs: "2", md: "6", lg: "12" }}>
|
|
129
|
+
<Placeholders count={2} />
|
|
130
|
+
</HStack>
|
|
131
|
+
</VStack>
|
|
132
|
+
</div>
|
|
133
|
+
),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
function Placeholders({
|
|
137
|
+
count,
|
|
138
|
+
children,
|
|
139
|
+
color,
|
|
140
|
+
}: {
|
|
141
|
+
count: number;
|
|
142
|
+
children?: React.ReactNode;
|
|
143
|
+
color?: string;
|
|
144
|
+
}) {
|
|
145
|
+
return (
|
|
146
|
+
<>
|
|
147
|
+
{Array.from({ length: count }, (_, i) => (
|
|
148
|
+
<div
|
|
149
|
+
key={i}
|
|
150
|
+
style={{
|
|
151
|
+
backgroundColor: color ?? "var(--a-purple-200)",
|
|
152
|
+
height: children ? "" : "3rem",
|
|
153
|
+
width: children ? "" : "3rem",
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
{children}
|
|
157
|
+
</div>
|
|
158
|
+
))}
|
|
159
|
+
</>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type BreakpointsAlias = "xs" | "sm" | "md" | "lg" | "xl";
|
|
2
|
+
export type SpacingScale =
|
|
3
|
+
| "0"
|
|
4
|
+
| "05"
|
|
5
|
+
| "1"
|
|
6
|
+
| "2"
|
|
7
|
+
| "3"
|
|
8
|
+
| "4"
|
|
9
|
+
| "5"
|
|
10
|
+
| "6"
|
|
11
|
+
| "7"
|
|
12
|
+
| "8"
|
|
13
|
+
| "9"
|
|
14
|
+
| "10"
|
|
15
|
+
| "11"
|
|
16
|
+
| "12"
|
|
17
|
+
| "14"
|
|
18
|
+
| "16"
|
|
19
|
+
| "18"
|
|
20
|
+
| "20"
|
|
21
|
+
| "24"
|
|
22
|
+
| "32";
|
|
23
|
+
|
|
24
|
+
export type ResponsiveProp<T> =
|
|
25
|
+
| T
|
|
26
|
+
| {
|
|
27
|
+
// eslint-disable-next-line no-unused-vars
|
|
28
|
+
[Breakpoint in BreakpointsAlias]?: T;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function getResponsiveProps(
|
|
32
|
+
componentName: string,
|
|
33
|
+
componentProp: string,
|
|
34
|
+
tokenSubgroup: string,
|
|
35
|
+
responsiveProp?:
|
|
36
|
+
| string
|
|
37
|
+
| {
|
|
38
|
+
// eslint-disable-next-line no-unused-vars
|
|
39
|
+
[Breakpoint in BreakpointsAlias]?: string;
|
|
40
|
+
}
|
|
41
|
+
) {
|
|
42
|
+
if (!responsiveProp) return {};
|
|
43
|
+
|
|
44
|
+
if (typeof responsiveProp === "string") {
|
|
45
|
+
return {
|
|
46
|
+
[`--ac-${componentName}-${componentProp}-xs`]: `var(--a-${tokenSubgroup}-${responsiveProp})`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return Object.fromEntries(
|
|
51
|
+
Object.entries(responsiveProp).map(([breakpointAlias, aliasOrScale]) => [
|
|
52
|
+
`--ac-${componentName}-${componentProp}-${breakpointAlias}`,
|
|
53
|
+
`var(--a-${tokenSubgroup}-${aliasOrScale})`,
|
|
54
|
+
])
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -31,10 +31,15 @@ export interface ExpandableRowProps extends Omit<RowProps, "content"> {
|
|
|
31
31
|
*/
|
|
32
32
|
onOpenChange?: (open: boolean) => void;
|
|
33
33
|
/**
|
|
34
|
-
* Disable
|
|
34
|
+
* Disable expansion. shadeOnHover will not be visible.
|
|
35
35
|
* @default false
|
|
36
36
|
*/
|
|
37
37
|
expansionDisabled?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Makes the whole row clickable
|
|
40
|
+
* @default false
|
|
41
|
+
*/
|
|
42
|
+
expandOnRowClick?: boolean;
|
|
38
43
|
/**
|
|
39
44
|
* The width of the expanded row's internal cell
|
|
40
45
|
* @default 999
|
|
@@ -58,6 +63,7 @@ export const ExpandableRow: ExpandableRowType = forwardRef(
|
|
|
58
63
|
open,
|
|
59
64
|
onOpenChange,
|
|
60
65
|
expansionDisabled = false,
|
|
66
|
+
expandOnRowClick = false,
|
|
61
67
|
colSpan = 999,
|
|
62
68
|
...rest
|
|
63
69
|
},
|
|
@@ -65,9 +71,22 @@ export const ExpandableRow: ExpandableRowType = forwardRef(
|
|
|
65
71
|
) => {
|
|
66
72
|
const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);
|
|
67
73
|
const id = useId();
|
|
68
|
-
|
|
69
74
|
const isOpen = open ?? internalOpen;
|
|
70
75
|
|
|
76
|
+
const expansionHandler = (e) => {
|
|
77
|
+
onOpenChange?.(!isOpen);
|
|
78
|
+
if (open === undefined) {
|
|
79
|
+
setInternalOpen((open) => !open);
|
|
80
|
+
}
|
|
81
|
+
e.stopPropagation();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const onRowClick = (e) => {
|
|
85
|
+
if (e.target.nodeName === "TD" || e.target.nodeName === "TH") {
|
|
86
|
+
expansionHandler(e);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
71
90
|
return (
|
|
72
91
|
<>
|
|
73
92
|
<Row
|
|
@@ -75,7 +94,13 @@ export const ExpandableRow: ExpandableRowType = forwardRef(
|
|
|
75
94
|
ref={ref}
|
|
76
95
|
className={cl("navds-table__expandable-row", className, {
|
|
77
96
|
"navds-table__expandable-row--open": isOpen,
|
|
97
|
+
"navds-table__expandable-row--expansion-disabled":
|
|
98
|
+
expansionDisabled,
|
|
78
99
|
})}
|
|
100
|
+
onClick={(e) => {
|
|
101
|
+
!expansionDisabled && expandOnRowClick && onRowClick(e);
|
|
102
|
+
rest?.onClick?.(e);
|
|
103
|
+
}}
|
|
79
104
|
>
|
|
80
105
|
{togglePlacement === "right" && children}
|
|
81
106
|
<DataCell
|
|
@@ -89,12 +114,7 @@ export const ExpandableRow: ExpandableRowType = forwardRef(
|
|
|
89
114
|
className="navds-table__toggle-expand-button"
|
|
90
115
|
aria-controls={id}
|
|
91
116
|
aria-expanded={isOpen}
|
|
92
|
-
onClick={
|
|
93
|
-
onOpenChange?.(!isOpen);
|
|
94
|
-
if (open === undefined) {
|
|
95
|
-
setInternalOpen((open) => !open);
|
|
96
|
-
}
|
|
97
|
-
}}
|
|
117
|
+
onClick={expansionHandler}
|
|
98
118
|
>
|
|
99
119
|
<ChevronDownIcon
|
|
100
120
|
className="navds-table__expandable-icon"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import { Table } from "..";
|
|
3
|
-
import { Link } from "../..";
|
|
3
|
+
import { Button, Checkbox, Link } from "../..";
|
|
4
4
|
|
|
5
5
|
export default {
|
|
6
6
|
title: "ds-react/Table",
|
|
@@ -37,6 +37,7 @@ export const Expandable = () => {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
export const ExpandableSmall = () => {
|
|
40
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
40
41
|
const [open, setOpen] = useState(false);
|
|
41
42
|
return (
|
|
42
43
|
<Table size="small">
|
|
@@ -227,3 +228,63 @@ export const ExpandableOpen = () => {
|
|
|
227
228
|
</Table>
|
|
228
229
|
);
|
|
229
230
|
};
|
|
231
|
+
|
|
232
|
+
export const ClickableRow = {
|
|
233
|
+
render: () => {
|
|
234
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
235
|
+
const [isRowOpen1, setIsRowOpen1] = useState(false);
|
|
236
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
237
|
+
const [isRowOpen2, setIsRowOpen2] = useState(false);
|
|
238
|
+
|
|
239
|
+
return (
|
|
240
|
+
<>
|
|
241
|
+
<Table zebraStripes>
|
|
242
|
+
<Table.Header>
|
|
243
|
+
<Table.Row>
|
|
244
|
+
<Table.HeaderCell>Navn</Table.HeaderCell>
|
|
245
|
+
<Table.HeaderCell>Info</Table.HeaderCell>
|
|
246
|
+
<Table.HeaderCell aria-hidden />
|
|
247
|
+
</Table.Row>
|
|
248
|
+
</Table.Header>
|
|
249
|
+
<Table.Body>
|
|
250
|
+
<Table.ExpandableRow
|
|
251
|
+
content={<div>placeholder row 1</div>}
|
|
252
|
+
togglePlacement="right"
|
|
253
|
+
onOpenChange={setIsRowOpen1}
|
|
254
|
+
data-testid="row1"
|
|
255
|
+
open={isRowOpen1}
|
|
256
|
+
expandOnRowClick
|
|
257
|
+
>
|
|
258
|
+
<Table.DataCell>Ola</Table.DataCell>
|
|
259
|
+
<Table.DataCell>
|
|
260
|
+
<Button
|
|
261
|
+
size="xsmall"
|
|
262
|
+
onClick={(e) => {
|
|
263
|
+
alert("Mer info");
|
|
264
|
+
}}
|
|
265
|
+
>
|
|
266
|
+
Mer info
|
|
267
|
+
</Button>
|
|
268
|
+
</Table.DataCell>
|
|
269
|
+
</Table.ExpandableRow>
|
|
270
|
+
<Table.ExpandableRow
|
|
271
|
+
content={<div>placeholder row 2</div>}
|
|
272
|
+
togglePlacement="right"
|
|
273
|
+
onOpenChange={setIsRowOpen2}
|
|
274
|
+
data-testid="row2"
|
|
275
|
+
open={isRowOpen2}
|
|
276
|
+
expandOnRowClick
|
|
277
|
+
>
|
|
278
|
+
<Table.DataCell>Hans</Table.DataCell>
|
|
279
|
+
<Table.DataCell>
|
|
280
|
+
<Checkbox hideLabel size="small">
|
|
281
|
+
Sett
|
|
282
|
+
</Checkbox>
|
|
283
|
+
</Table.DataCell>
|
|
284
|
+
</Table.ExpandableRow>
|
|
285
|
+
</Table.Body>
|
|
286
|
+
</Table>
|
|
287
|
+
</>
|
|
288
|
+
);
|
|
289
|
+
},
|
|
290
|
+
};
|