@dbcdk/react-components 0.0.104 → 0.0.105
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/dist/components/accordion/Accordion.cjs +45 -31
- package/dist/components/accordion/Accordion.d.ts +5 -2
- package/dist/components/accordion/Accordion.js +45 -31
- package/dist/components/accordion/components/AccordionRow.cjs +36 -31
- package/dist/components/accordion/components/AccordionRow.js +36 -31
- package/dist/components/accordion/components/AccordionRow.module.css +37 -3
- package/dist/components/headline/CollapsibleHeadline.cjs +18 -9
- package/dist/components/headline/CollapsibleHeadline.d.ts +4 -4
- package/dist/components/headline/CollapsibleHeadline.js +19 -10
- package/dist/components/nav-bar/NavBar.cjs +13 -4
- package/dist/components/nav-bar/NavBar.d.ts +3 -2
- package/dist/components/nav-bar/NavBar.js +14 -5
- package/dist/components/nav-bar/NavBar.module.css +1 -1
- package/dist/components/page/Page.module.css +1 -1
- package/dist/components/split-pane/SplitPane.cjs +14 -3
- package/dist/components/split-pane/SplitPane.d.ts +2 -1
- package/dist/components/split-pane/SplitPane.js +14 -3
- package/dist/components/split-pane/SplitPane.module.css +7 -0
- package/package.json +1 -1
|
@@ -13,8 +13,11 @@ var styles__default = /*#__PURE__*/_interopDefault(styles);
|
|
|
13
13
|
function uniqSorted(nums) {
|
|
14
14
|
return Array.from(new Set(nums)).sort((a, b) => a - b);
|
|
15
15
|
}
|
|
16
|
-
function normalizeMultiple(indexes) {
|
|
17
|
-
|
|
16
|
+
function normalizeMultiple(indexes, itemCount) {
|
|
17
|
+
if (indexes === "all") {
|
|
18
|
+
return Array.from({ length: itemCount }, (_, i) => i);
|
|
19
|
+
}
|
|
20
|
+
return uniqSorted((indexes != null ? indexes : []).filter((n) => Number.isInteger(n) && n >= 0 && n < itemCount));
|
|
18
21
|
}
|
|
19
22
|
function Accordion({
|
|
20
23
|
items,
|
|
@@ -34,35 +37,40 @@ function Accordion({
|
|
|
34
37
|
react.useEffect(() => {
|
|
35
38
|
setHasMounted(true);
|
|
36
39
|
}, []);
|
|
37
|
-
const [internalSingle, setInternalSingle] = react.useState(
|
|
38
|
-
mode
|
|
39
|
-
|
|
40
|
+
const [internalSingle, setInternalSingle] = react.useState(() => {
|
|
41
|
+
if (mode !== "single") return null;
|
|
42
|
+
if (defaultOpenIndex !== null && Number.isInteger(defaultOpenIndex) && defaultOpenIndex >= 0 && defaultOpenIndex < items.length) {
|
|
43
|
+
return defaultOpenIndex;
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
});
|
|
40
47
|
const [internalMultiple, setInternalMultiple] = react.useState(() => {
|
|
41
48
|
if (mode !== "multiple") return [];
|
|
42
|
-
|
|
43
|
-
return normalizeMultiple(defaultOpenIndexes);
|
|
49
|
+
return normalizeMultiple(defaultOpenIndexes, items.length);
|
|
44
50
|
});
|
|
45
51
|
const currentOpenIndexes = react.useMemo(() => {
|
|
46
52
|
if (mode === "single") {
|
|
47
53
|
const current = isControlled ? openIndex != null ? openIndex : null : internalSingle;
|
|
48
|
-
return current
|
|
54
|
+
return current !== null && Number.isInteger(current) && current >= 0 && current < items.length ? [current] : [];
|
|
49
55
|
}
|
|
50
|
-
return isControlled ? normalizeMultiple(openIndexes) : internalMultiple;
|
|
51
|
-
}, [mode, isControlled, openIndex, openIndexes, internalSingle, internalMultiple]);
|
|
56
|
+
return isControlled ? normalizeMultiple(openIndexes, items.length) : normalizeMultiple(internalMultiple, items.length);
|
|
57
|
+
}, [mode, isControlled, openIndex, openIndexes, internalSingle, internalMultiple, items.length]);
|
|
52
58
|
const openSet = react.useMemo(() => new Set(currentOpenIndexes), [currentOpenIndexes]);
|
|
53
59
|
function commit(nextIndexes) {
|
|
54
60
|
if (mode === "single") {
|
|
55
61
|
const next = nextIndexes.length ? nextIndexes[0] : null;
|
|
56
|
-
if (isControlled)
|
|
57
|
-
|
|
62
|
+
if (isControlled) {
|
|
63
|
+
onOpenIndexChange == null ? void 0 : onOpenIndexChange(next);
|
|
64
|
+
} else {
|
|
58
65
|
setInternalSingle(next);
|
|
59
66
|
onOpenIndexChange == null ? void 0 : onOpenIndexChange(next);
|
|
60
67
|
}
|
|
61
68
|
return;
|
|
62
69
|
}
|
|
63
|
-
const normalized =
|
|
64
|
-
if (isControlled)
|
|
65
|
-
|
|
70
|
+
const normalized = normalizeMultiple(nextIndexes, items.length);
|
|
71
|
+
if (isControlled) {
|
|
72
|
+
onOpenIndexesChange == null ? void 0 : onOpenIndexesChange(normalized);
|
|
73
|
+
} else {
|
|
66
74
|
setInternalMultiple(normalized);
|
|
67
75
|
onOpenIndexesChange == null ? void 0 : onOpenIndexesChange(normalized);
|
|
68
76
|
}
|
|
@@ -75,27 +83,33 @@ function Accordion({
|
|
|
75
83
|
commit(isOpen ? [] : [index]);
|
|
76
84
|
return;
|
|
77
85
|
}
|
|
78
|
-
if (isOpen)
|
|
79
|
-
|
|
86
|
+
if (isOpen) {
|
|
87
|
+
commit(currentOpenIndexes.filter((i) => i !== index));
|
|
88
|
+
} else {
|
|
89
|
+
commit([...currentOpenIndexes, index]);
|
|
90
|
+
}
|
|
80
91
|
}
|
|
81
92
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
82
93
|
"div",
|
|
83
94
|
{
|
|
84
95
|
className: [styles__default.default.container, styles__default.default[size], variant !== "default" ? styles__default.default[variant] : ""].filter(Boolean).join(" "),
|
|
85
|
-
children: items.map((item, i) =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
children: items.map((item, i) => {
|
|
97
|
+
var _a;
|
|
98
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
99
|
+
AccordionRow.AccordionRow,
|
|
100
|
+
{
|
|
101
|
+
uid,
|
|
102
|
+
index: i,
|
|
103
|
+
item,
|
|
104
|
+
isOpen: openSet.has(i),
|
|
105
|
+
onToggle: toggle,
|
|
106
|
+
shouldAnimate: hasMounted,
|
|
107
|
+
headlineSize: size === "sm" ? 4 : 3,
|
|
108
|
+
variant
|
|
109
|
+
},
|
|
110
|
+
(_a = item.id) != null ? _a : i
|
|
111
|
+
);
|
|
112
|
+
})
|
|
99
113
|
}
|
|
100
114
|
);
|
|
101
115
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { JSX, ReactNode } from 'react';
|
|
2
2
|
import type { Severity } from '../../constants/severity.types';
|
|
3
3
|
export interface AccordionItem {
|
|
4
|
+
id?: string;
|
|
4
5
|
header: string;
|
|
5
6
|
subheader?: ReactNode;
|
|
6
7
|
headerAddition?: ReactNode;
|
|
8
|
+
headerActions?: ReactNode;
|
|
7
9
|
headerIcon?: ReactNode;
|
|
8
10
|
severity?: Severity;
|
|
9
11
|
children: ReactNode;
|
|
@@ -12,6 +14,7 @@ export interface AccordionItem {
|
|
|
12
14
|
type Size = 'sm' | 'md' | 'lg';
|
|
13
15
|
type Mode = 'single' | 'multiple';
|
|
14
16
|
type Variant = 'default' | 'outlined';
|
|
17
|
+
type OpenIndexes = number[] | 'all';
|
|
15
18
|
export interface AccordionProps {
|
|
16
19
|
items: AccordionItem[];
|
|
17
20
|
mode?: Mode;
|
|
@@ -19,10 +22,10 @@ export interface AccordionProps {
|
|
|
19
22
|
variant?: Variant;
|
|
20
23
|
/** Uncontrolled defaults */
|
|
21
24
|
defaultOpenIndex?: number | null;
|
|
22
|
-
defaultOpenIndexes?:
|
|
25
|
+
defaultOpenIndexes?: OpenIndexes;
|
|
23
26
|
/** Controlled state */
|
|
24
27
|
openIndex?: number | null;
|
|
25
|
-
openIndexes?:
|
|
28
|
+
openIndexes?: OpenIndexes;
|
|
26
29
|
/** Change callbacks */
|
|
27
30
|
onOpenIndexChange?: (index: number | null) => void;
|
|
28
31
|
onOpenIndexesChange?: (indexes: number[]) => void;
|
|
@@ -7,8 +7,11 @@ import { AccordionRow } from './components/AccordionRow';
|
|
|
7
7
|
function uniqSorted(nums) {
|
|
8
8
|
return Array.from(new Set(nums)).sort((a, b) => a - b);
|
|
9
9
|
}
|
|
10
|
-
function normalizeMultiple(indexes) {
|
|
11
|
-
|
|
10
|
+
function normalizeMultiple(indexes, itemCount) {
|
|
11
|
+
if (indexes === "all") {
|
|
12
|
+
return Array.from({ length: itemCount }, (_, i) => i);
|
|
13
|
+
}
|
|
14
|
+
return uniqSorted((indexes != null ? indexes : []).filter((n) => Number.isInteger(n) && n >= 0 && n < itemCount));
|
|
12
15
|
}
|
|
13
16
|
function Accordion({
|
|
14
17
|
items,
|
|
@@ -28,35 +31,40 @@ function Accordion({
|
|
|
28
31
|
useEffect(() => {
|
|
29
32
|
setHasMounted(true);
|
|
30
33
|
}, []);
|
|
31
|
-
const [internalSingle, setInternalSingle] = useState(
|
|
32
|
-
mode
|
|
33
|
-
|
|
34
|
+
const [internalSingle, setInternalSingle] = useState(() => {
|
|
35
|
+
if (mode !== "single") return null;
|
|
36
|
+
if (defaultOpenIndex !== null && Number.isInteger(defaultOpenIndex) && defaultOpenIndex >= 0 && defaultOpenIndex < items.length) {
|
|
37
|
+
return defaultOpenIndex;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
});
|
|
34
41
|
const [internalMultiple, setInternalMultiple] = useState(() => {
|
|
35
42
|
if (mode !== "multiple") return [];
|
|
36
|
-
|
|
37
|
-
return normalizeMultiple(defaultOpenIndexes);
|
|
43
|
+
return normalizeMultiple(defaultOpenIndexes, items.length);
|
|
38
44
|
});
|
|
39
45
|
const currentOpenIndexes = useMemo(() => {
|
|
40
46
|
if (mode === "single") {
|
|
41
47
|
const current = isControlled ? openIndex != null ? openIndex : null : internalSingle;
|
|
42
|
-
return current
|
|
48
|
+
return current !== null && Number.isInteger(current) && current >= 0 && current < items.length ? [current] : [];
|
|
43
49
|
}
|
|
44
|
-
return isControlled ? normalizeMultiple(openIndexes) : internalMultiple;
|
|
45
|
-
}, [mode, isControlled, openIndex, openIndexes, internalSingle, internalMultiple]);
|
|
50
|
+
return isControlled ? normalizeMultiple(openIndexes, items.length) : normalizeMultiple(internalMultiple, items.length);
|
|
51
|
+
}, [mode, isControlled, openIndex, openIndexes, internalSingle, internalMultiple, items.length]);
|
|
46
52
|
const openSet = useMemo(() => new Set(currentOpenIndexes), [currentOpenIndexes]);
|
|
47
53
|
function commit(nextIndexes) {
|
|
48
54
|
if (mode === "single") {
|
|
49
55
|
const next = nextIndexes.length ? nextIndexes[0] : null;
|
|
50
|
-
if (isControlled)
|
|
51
|
-
|
|
56
|
+
if (isControlled) {
|
|
57
|
+
onOpenIndexChange == null ? void 0 : onOpenIndexChange(next);
|
|
58
|
+
} else {
|
|
52
59
|
setInternalSingle(next);
|
|
53
60
|
onOpenIndexChange == null ? void 0 : onOpenIndexChange(next);
|
|
54
61
|
}
|
|
55
62
|
return;
|
|
56
63
|
}
|
|
57
|
-
const normalized =
|
|
58
|
-
if (isControlled)
|
|
59
|
-
|
|
64
|
+
const normalized = normalizeMultiple(nextIndexes, items.length);
|
|
65
|
+
if (isControlled) {
|
|
66
|
+
onOpenIndexesChange == null ? void 0 : onOpenIndexesChange(normalized);
|
|
67
|
+
} else {
|
|
60
68
|
setInternalMultiple(normalized);
|
|
61
69
|
onOpenIndexesChange == null ? void 0 : onOpenIndexesChange(normalized);
|
|
62
70
|
}
|
|
@@ -69,27 +77,33 @@ function Accordion({
|
|
|
69
77
|
commit(isOpen ? [] : [index]);
|
|
70
78
|
return;
|
|
71
79
|
}
|
|
72
|
-
if (isOpen)
|
|
73
|
-
|
|
80
|
+
if (isOpen) {
|
|
81
|
+
commit(currentOpenIndexes.filter((i) => i !== index));
|
|
82
|
+
} else {
|
|
83
|
+
commit([...currentOpenIndexes, index]);
|
|
84
|
+
}
|
|
74
85
|
}
|
|
75
86
|
return /* @__PURE__ */ jsx(
|
|
76
87
|
"div",
|
|
77
88
|
{
|
|
78
89
|
className: [styles.container, styles[size], variant !== "default" ? styles[variant] : ""].filter(Boolean).join(" "),
|
|
79
|
-
children: items.map((item, i) =>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
children: items.map((item, i) => {
|
|
91
|
+
var _a;
|
|
92
|
+
return /* @__PURE__ */ jsx(
|
|
93
|
+
AccordionRow,
|
|
94
|
+
{
|
|
95
|
+
uid,
|
|
96
|
+
index: i,
|
|
97
|
+
item,
|
|
98
|
+
isOpen: openSet.has(i),
|
|
99
|
+
onToggle: toggle,
|
|
100
|
+
shouldAnimate: hasMounted,
|
|
101
|
+
headlineSize: size === "sm" ? 4 : 3,
|
|
102
|
+
variant
|
|
103
|
+
},
|
|
104
|
+
(_a = item.id) != null ? _a : i
|
|
105
|
+
);
|
|
106
|
+
})
|
|
93
107
|
}
|
|
94
108
|
);
|
|
95
109
|
}
|
|
@@ -56,6 +56,7 @@ function AccordionRow({
|
|
|
56
56
|
variant = "default"
|
|
57
57
|
}) {
|
|
58
58
|
const isDisabled = !!item.disabled;
|
|
59
|
+
const headlineWeight = isOpen ? variant === "outlined" ? 500 : 600 : variant === "outlined" ? 400 : 500;
|
|
59
60
|
const buttonId = `${uid}-acc-btn-${index}`;
|
|
60
61
|
const panelId = `${uid}-acc-panel-${index}`;
|
|
61
62
|
const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen, shouldAnimate);
|
|
@@ -63,38 +64,42 @@ function AccordionRow({
|
|
|
63
64
|
"section",
|
|
64
65
|
{
|
|
65
66
|
className: `${styles__default.default.item} ${isOpen ? styles__default.default.open : ""} ${isDisabled ? styles__default.default.disabled : ""}`,
|
|
67
|
+
"data-state": isOpen ? "open" : "closed",
|
|
66
68
|
children: [
|
|
67
|
-
/* @__PURE__ */ jsxRuntime.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.headerRow, children: [
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
71
|
+
"button",
|
|
72
|
+
{
|
|
73
|
+
type: "button",
|
|
74
|
+
id: buttonId,
|
|
75
|
+
className: styles__default.default.trigger,
|
|
76
|
+
"aria-expanded": isOpen,
|
|
77
|
+
"aria-controls": panelId,
|
|
78
|
+
onClick: () => onToggle(index),
|
|
79
|
+
disabled: isDisabled,
|
|
80
|
+
children: [
|
|
81
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.title, children: [
|
|
82
|
+
item.headerIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.icon, children: item.headerIcon }) : null,
|
|
83
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
84
|
+
Headline.Headline,
|
|
85
|
+
{
|
|
86
|
+
disableMargin: true,
|
|
87
|
+
size: headlineSize,
|
|
88
|
+
weight: headlineWeight,
|
|
89
|
+
severity: item.severity,
|
|
90
|
+
subheader: item.subheader,
|
|
91
|
+
allowWrap: isOpen,
|
|
92
|
+
children: item.header
|
|
93
|
+
}
|
|
94
|
+
),
|
|
95
|
+
item.headerAddition ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.headerAddition, children: item.headerAddition }) : null
|
|
96
|
+
] }),
|
|
97
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.chevron, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, {}) })
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
),
|
|
101
|
+
item.headerActions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.headerActions, onClick: (event) => event.stopPropagation(), children: item.headerActions }) : null
|
|
102
|
+
] }),
|
|
98
103
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
99
104
|
"div",
|
|
100
105
|
{
|
|
@@ -50,6 +50,7 @@ function AccordionRow({
|
|
|
50
50
|
variant = "default"
|
|
51
51
|
}) {
|
|
52
52
|
const isDisabled = !!item.disabled;
|
|
53
|
+
const headlineWeight = isOpen ? variant === "outlined" ? 500 : 600 : variant === "outlined" ? 400 : 500;
|
|
53
54
|
const buttonId = `${uid}-acc-btn-${index}`;
|
|
54
55
|
const panelId = `${uid}-acc-panel-${index}`;
|
|
55
56
|
const { innerRef, height, onTransitionEnd } = useCollapsibleHeight(isOpen, shouldAnimate);
|
|
@@ -57,38 +58,42 @@ function AccordionRow({
|
|
|
57
58
|
"section",
|
|
58
59
|
{
|
|
59
60
|
className: `${styles.item} ${isOpen ? styles.open : ""} ${isDisabled ? styles.disabled : ""}`,
|
|
61
|
+
"data-state": isOpen ? "open" : "closed",
|
|
60
62
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
63
|
+
/* @__PURE__ */ jsxs("div", { className: styles.headerRow, children: [
|
|
64
|
+
/* @__PURE__ */ jsxs(
|
|
65
|
+
"button",
|
|
66
|
+
{
|
|
67
|
+
type: "button",
|
|
68
|
+
id: buttonId,
|
|
69
|
+
className: styles.trigger,
|
|
70
|
+
"aria-expanded": isOpen,
|
|
71
|
+
"aria-controls": panelId,
|
|
72
|
+
onClick: () => onToggle(index),
|
|
73
|
+
disabled: isDisabled,
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ jsxs("div", { className: styles.title, children: [
|
|
76
|
+
item.headerIcon ? /* @__PURE__ */ jsx("span", { className: styles.icon, children: item.headerIcon }) : null,
|
|
77
|
+
/* @__PURE__ */ jsx(
|
|
78
|
+
Headline,
|
|
79
|
+
{
|
|
80
|
+
disableMargin: true,
|
|
81
|
+
size: headlineSize,
|
|
82
|
+
weight: headlineWeight,
|
|
83
|
+
severity: item.severity,
|
|
84
|
+
subheader: item.subheader,
|
|
85
|
+
allowWrap: isOpen,
|
|
86
|
+
children: item.header
|
|
87
|
+
}
|
|
88
|
+
),
|
|
89
|
+
item.headerAddition ? /* @__PURE__ */ jsx("div", { className: styles.headerAddition, children: item.headerAddition }) : null
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsx("span", { className: styles.chevron, "aria-hidden": "true", children: /* @__PURE__ */ jsx(ChevronDown, {}) })
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
),
|
|
95
|
+
item.headerActions ? /* @__PURE__ */ jsx("div", { className: styles.headerActions, onClick: (event) => event.stopPropagation(), children: item.headerActions }) : null
|
|
96
|
+
] }),
|
|
92
97
|
/* @__PURE__ */ jsx(
|
|
93
98
|
"div",
|
|
94
99
|
{
|
|
@@ -1,23 +1,41 @@
|
|
|
1
|
+
.headerRow {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: stretch;
|
|
4
|
+
width: 100%;
|
|
5
|
+
background: var(--acc-trigger-bg, var(--color-bg-contextual-subtle));
|
|
6
|
+
}
|
|
7
|
+
|
|
1
8
|
.trigger {
|
|
2
9
|
all: unset;
|
|
3
10
|
box-sizing: border-box;
|
|
4
|
-
|
|
5
|
-
width: 100%;
|
|
6
11
|
display: flex;
|
|
7
12
|
align-items: center;
|
|
8
13
|
justify-content: space-between;
|
|
9
14
|
gap: var(--spacing-sm);
|
|
15
|
+
flex: 1 1 auto;
|
|
10
16
|
|
|
11
17
|
cursor: pointer;
|
|
12
18
|
user-select: none;
|
|
13
19
|
|
|
14
20
|
font-size: var(--acc-font-size);
|
|
15
21
|
padding: var(--acc-trigger-py) var(--acc-trigger-px);
|
|
16
|
-
background:
|
|
22
|
+
background: transparent;
|
|
17
23
|
|
|
18
24
|
min-width: 0;
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
.headerActions {
|
|
28
|
+
flex: 0 0 auto;
|
|
29
|
+
display: flex;
|
|
30
|
+
align-items: center;
|
|
31
|
+
padding-block: var(--acc-trigger-py);
|
|
32
|
+
padding-inline: 0 var(--acc-trigger-px);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.headerActions > * {
|
|
36
|
+
flex: 0 0 auto;
|
|
37
|
+
}
|
|
38
|
+
|
|
21
39
|
.trigger:focus-visible {
|
|
22
40
|
outline: none;
|
|
23
41
|
box-shadow: var(--focus-ring);
|
|
@@ -37,10 +55,18 @@
|
|
|
37
55
|
overflow: hidden;
|
|
38
56
|
}
|
|
39
57
|
|
|
58
|
+
.headerAddition {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: baseline;
|
|
61
|
+
flex: 1 1 auto;
|
|
62
|
+
min-width: 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
40
65
|
.icon {
|
|
41
66
|
flex: 0 0 auto;
|
|
42
67
|
display: inline-flex;
|
|
43
68
|
align-items: center;
|
|
69
|
+
align-self: center;
|
|
44
70
|
}
|
|
45
71
|
|
|
46
72
|
.icon svg {
|
|
@@ -88,6 +114,14 @@
|
|
|
88
114
|
border-bottom: var(--acc-item-separator, none);
|
|
89
115
|
}
|
|
90
116
|
|
|
117
|
+
.item[data-state='open'] .headerRow {
|
|
118
|
+
background: var(--color-bg-contextual);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
:global(.outlined) .item[data-state='open'] .headerRow {
|
|
122
|
+
box-shadow: inset 3px 0 0 var(--color-border-selected);
|
|
123
|
+
}
|
|
124
|
+
|
|
91
125
|
.item:last-child {
|
|
92
126
|
border-bottom: none;
|
|
93
127
|
}
|
|
@@ -27,17 +27,26 @@ function CollapsibleHeadline({
|
|
|
27
27
|
}) {
|
|
28
28
|
const generatedId = react.useId();
|
|
29
29
|
const panelId = controls != null ? controls : generatedId;
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
const isControlled = expanded !== void 0;
|
|
31
|
+
const [internalExpanded, setInternalExpanded] = react.useState(false);
|
|
32
|
+
const [hasToggled, setHasToggled] = react.useState(false);
|
|
33
|
+
const persistedExpanded = react.useSyncExternalStore(
|
|
34
|
+
() => () => void 0,
|
|
35
|
+
() => {
|
|
36
|
+
if (isControlled || !storageKey) return false;
|
|
37
|
+
return localStorage.getItem(storageKey) === "true";
|
|
38
|
+
},
|
|
39
|
+
() => false
|
|
40
|
+
);
|
|
41
|
+
const isExpanded = isControlled ? expanded : hasToggled ? internalExpanded : persistedExpanded;
|
|
36
42
|
const handleToggle = () => {
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
const next = !isExpanded;
|
|
44
|
+
if (!isControlled) {
|
|
45
|
+
setHasToggled(true);
|
|
39
46
|
setInternalExpanded(next);
|
|
40
|
-
|
|
47
|
+
if (storageKey) {
|
|
48
|
+
localStorage.setItem(storageKey, String(next));
|
|
49
|
+
}
|
|
41
50
|
}
|
|
42
51
|
onToggle == null ? void 0 : onToggle();
|
|
43
52
|
};
|
|
@@ -3,7 +3,7 @@ import type { HeadlineProps } from './Headline';
|
|
|
3
3
|
export interface CollapsibleHeadlineProps extends Omit<HeadlineProps, 'addition' | 'children'> {
|
|
4
4
|
/** The headline text — always visible. */
|
|
5
5
|
header: React.ReactNode;
|
|
6
|
-
/** Controlled expanded state.
|
|
6
|
+
/** Controlled expanded state. When omitted, the component manages its own state. */
|
|
7
7
|
expanded?: boolean;
|
|
8
8
|
/** Called when the toggle is clicked. */
|
|
9
9
|
onToggle?: () => void;
|
|
@@ -12,9 +12,9 @@ export interface CollapsibleHeadlineProps extends Omit<HeadlineProps, 'addition'
|
|
|
12
12
|
/** Extra content rendered between the headline text and the toggle button. */
|
|
13
13
|
addition?: React.ReactNode;
|
|
14
14
|
/**
|
|
15
|
-
* When set the component
|
|
16
|
-
* localStorage under this key.
|
|
17
|
-
*
|
|
15
|
+
* When set in uncontrolled mode, the component persists its expanded
|
|
16
|
+
* state to localStorage under this key. The server render still starts
|
|
17
|
+
* collapsed to stay hydration-safe.
|
|
18
18
|
*/
|
|
19
19
|
storageKey?: string;
|
|
20
20
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { ChevronDown } from 'lucide-react';
|
|
4
|
-
import { useId, useState } from 'react';
|
|
4
|
+
import { useId, useState, useSyncExternalStore } from 'react';
|
|
5
5
|
import { Headline } from './Headline';
|
|
6
6
|
import styles from './Headline.module.css';
|
|
7
7
|
import { Button } from '../button/Button';
|
|
@@ -21,17 +21,26 @@ function CollapsibleHeadline({
|
|
|
21
21
|
}) {
|
|
22
22
|
const generatedId = useId();
|
|
23
23
|
const panelId = controls != null ? controls : generatedId;
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
const isControlled = expanded !== void 0;
|
|
25
|
+
const [internalExpanded, setInternalExpanded] = useState(false);
|
|
26
|
+
const [hasToggled, setHasToggled] = useState(false);
|
|
27
|
+
const persistedExpanded = useSyncExternalStore(
|
|
28
|
+
() => () => void 0,
|
|
29
|
+
() => {
|
|
30
|
+
if (isControlled || !storageKey) return false;
|
|
31
|
+
return localStorage.getItem(storageKey) === "true";
|
|
32
|
+
},
|
|
33
|
+
() => false
|
|
34
|
+
);
|
|
35
|
+
const isExpanded = isControlled ? expanded : hasToggled ? internalExpanded : persistedExpanded;
|
|
30
36
|
const handleToggle = () => {
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
const next = !isExpanded;
|
|
38
|
+
if (!isControlled) {
|
|
39
|
+
setHasToggled(true);
|
|
33
40
|
setInternalExpanded(next);
|
|
34
|
-
|
|
41
|
+
if (storageKey) {
|
|
42
|
+
localStorage.setItem(storageKey, String(next));
|
|
43
|
+
}
|
|
35
44
|
}
|
|
36
45
|
onToggle == null ? void 0 : onToggle();
|
|
37
46
|
};
|
|
@@ -19,6 +19,7 @@ function NavBar({
|
|
|
19
19
|
logo: logo$1,
|
|
20
20
|
items = [],
|
|
21
21
|
productName,
|
|
22
|
+
productNameComponent: ProductNameComponent,
|
|
22
23
|
addition,
|
|
23
24
|
activeLink,
|
|
24
25
|
size
|
|
@@ -45,6 +46,17 @@ function NavBar({
|
|
|
45
46
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.label, children: label })
|
|
46
47
|
] }) }, id);
|
|
47
48
|
});
|
|
49
|
+
const productNameContent = productName ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
50
|
+
/* @__PURE__ */ jsxRuntime.jsx(logo.Logo, {}),
|
|
51
|
+
/* @__PURE__ */ jsxRuntime.jsx(Headline.Headline, { disableMargin: true, size: 1, children: productName })
|
|
52
|
+
] }) : null;
|
|
53
|
+
const productNameNode = (() => {
|
|
54
|
+
if (!productName || !productNameContent) return null;
|
|
55
|
+
if (ProductNameComponent) {
|
|
56
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ProductNameComponent, { className: styles__default.default.productName, children: productNameContent });
|
|
57
|
+
}
|
|
58
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles__default.default.productName, children: productNameContent });
|
|
59
|
+
})();
|
|
48
60
|
return /* @__PURE__ */ jsxRuntime.jsx(AppHeader.AppHeader, { size, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
49
61
|
"nav",
|
|
50
62
|
{
|
|
@@ -54,10 +66,7 @@ function NavBar({
|
|
|
54
66
|
children: [
|
|
55
67
|
(logo$1 || productName) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.logoRow, children: [
|
|
56
68
|
logo$1,
|
|
57
|
-
|
|
58
|
-
/* @__PURE__ */ jsxRuntime.jsx(logo.Logo, {}),
|
|
59
|
-
/* @__PURE__ */ jsxRuntime.jsx(Headline.Headline, { disableMargin: true, size: 1, children: productName })
|
|
60
|
-
] })
|
|
69
|
+
productNameNode
|
|
61
70
|
] }),
|
|
62
71
|
(navLinks == null ? void 0 : navLinks.length) > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.navContent, children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: styles__default.default.navItems, role: "list", children: navLinks }) }),
|
|
63
72
|
addition && !isMobile && /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.addition, children: addition }),
|
|
@@ -31,13 +31,14 @@ export type NavBarGroupItem = NavBarBase & {
|
|
|
31
31
|
type: 'group';
|
|
32
32
|
children: NavBarItem[];
|
|
33
33
|
};
|
|
34
|
-
interface NavBarProps {
|
|
34
|
+
export interface NavBarProps {
|
|
35
35
|
logo?: ReactNode;
|
|
36
36
|
items?: NavBarLinkItem[];
|
|
37
37
|
productName?: string;
|
|
38
|
+
productNameComponent?: ElementType<any>;
|
|
38
39
|
addition?: ReactNode;
|
|
39
40
|
activeLink?: string;
|
|
40
41
|
size?: AppHeaderSize;
|
|
41
42
|
}
|
|
42
|
-
export declare function NavBar({ logo, items, productName, addition, activeLink, size, }: NavBarProps): JSX.Element;
|
|
43
|
+
export declare function NavBar({ logo, items, productName, productNameComponent: ProductNameComponent, addition, activeLink, size, }: NavBarProps): JSX.Element;
|
|
43
44
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { X, Menu } from 'lucide-react';
|
|
4
4
|
import { useState, useRef } from 'react';
|
|
5
5
|
import styles from './NavBar.module.css';
|
|
@@ -13,6 +13,7 @@ function NavBar({
|
|
|
13
13
|
logo,
|
|
14
14
|
items = [],
|
|
15
15
|
productName,
|
|
16
|
+
productNameComponent: ProductNameComponent,
|
|
16
17
|
addition,
|
|
17
18
|
activeLink,
|
|
18
19
|
size
|
|
@@ -39,6 +40,17 @@ function NavBar({
|
|
|
39
40
|
/* @__PURE__ */ jsx("span", { className: styles.label, children: label })
|
|
40
41
|
] }) }, id);
|
|
41
42
|
});
|
|
43
|
+
const productNameContent = productName ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
44
|
+
/* @__PURE__ */ jsx(Logo, {}),
|
|
45
|
+
/* @__PURE__ */ jsx(Headline, { disableMargin: true, size: 1, children: productName })
|
|
46
|
+
] }) : null;
|
|
47
|
+
const productNameNode = (() => {
|
|
48
|
+
if (!productName || !productNameContent) return null;
|
|
49
|
+
if (ProductNameComponent) {
|
|
50
|
+
return /* @__PURE__ */ jsx(ProductNameComponent, { className: styles.productName, children: productNameContent });
|
|
51
|
+
}
|
|
52
|
+
return /* @__PURE__ */ jsx("span", { className: styles.productName, children: productNameContent });
|
|
53
|
+
})();
|
|
42
54
|
return /* @__PURE__ */ jsx(AppHeader, { size, children: /* @__PURE__ */ jsxs(
|
|
43
55
|
"nav",
|
|
44
56
|
{
|
|
@@ -48,10 +60,7 @@ function NavBar({
|
|
|
48
60
|
children: [
|
|
49
61
|
(logo || productName) && /* @__PURE__ */ jsxs("div", { className: styles.logoRow, children: [
|
|
50
62
|
logo,
|
|
51
|
-
|
|
52
|
-
/* @__PURE__ */ jsx(Logo, {}),
|
|
53
|
-
/* @__PURE__ */ jsx(Headline, { disableMargin: true, size: 1, children: productName })
|
|
54
|
-
] })
|
|
63
|
+
productNameNode
|
|
55
64
|
] }),
|
|
56
65
|
(navLinks == null ? void 0 : navLinks.length) > 0 && /* @__PURE__ */ jsx("div", { className: styles.navContent, children: /* @__PURE__ */ jsx("ul", { className: styles.navItems, role: "list", children: navLinks }) }),
|
|
57
66
|
addition && !isMobile && /* @__PURE__ */ jsx("div", { className: styles.addition, children: addition }),
|
|
@@ -21,7 +21,8 @@ function SplitPane({
|
|
|
21
21
|
direction = "horizontal",
|
|
22
22
|
showDivider = "hover",
|
|
23
23
|
gutterSize = 16,
|
|
24
|
-
storageKey
|
|
24
|
+
storageKey,
|
|
25
|
+
fillViewport = false
|
|
25
26
|
}) {
|
|
26
27
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
27
28
|
SplitPaneContext.SplitPaneProvider,
|
|
@@ -31,14 +32,23 @@ function SplitPane({
|
|
|
31
32
|
minPrimarySize,
|
|
32
33
|
minSecondarySize,
|
|
33
34
|
storageKey,
|
|
34
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
35
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
36
|
+
SplitPaneContainer,
|
|
37
|
+
{
|
|
38
|
+
showDivider,
|
|
39
|
+
gutterSize,
|
|
40
|
+
fillViewport,
|
|
41
|
+
children
|
|
42
|
+
}
|
|
43
|
+
)
|
|
35
44
|
}
|
|
36
45
|
);
|
|
37
46
|
}
|
|
38
47
|
function SplitPaneContainer({
|
|
39
48
|
children,
|
|
40
49
|
showDivider,
|
|
41
|
-
gutterSize
|
|
50
|
+
gutterSize,
|
|
51
|
+
fillViewport
|
|
42
52
|
}) {
|
|
43
53
|
const { direction, primarySize, containerRef } = SplitPaneContext.useSplitPaneContext();
|
|
44
54
|
const style = react.useMemo(
|
|
@@ -55,6 +65,7 @@ function SplitPaneContainer({
|
|
|
55
65
|
className: styles__default.default.container,
|
|
56
66
|
"data-direction": direction,
|
|
57
67
|
"data-divider": showDivider,
|
|
68
|
+
"data-fill-viewport": fillViewport,
|
|
58
69
|
style,
|
|
59
70
|
children
|
|
60
71
|
}
|
|
@@ -9,8 +9,9 @@ export interface SplitPaneProps {
|
|
|
9
9
|
showDivider?: 'hover' | 'always' | 'never';
|
|
10
10
|
gutterSize?: number;
|
|
11
11
|
storageKey?: string;
|
|
12
|
+
fillViewport?: boolean;
|
|
12
13
|
}
|
|
13
|
-
export declare function SplitPane({ children, initialPrimarySize, minPrimarySize, minSecondarySize, direction, showDivider, gutterSize, storageKey, }: SplitPaneProps): JSX.Element;
|
|
14
|
+
export declare function SplitPane({ children, initialPrimarySize, minPrimarySize, minSecondarySize, direction, showDivider, gutterSize, storageKey, fillViewport, }: SplitPaneProps): JSX.Element;
|
|
14
15
|
export declare function SplitPanePrimary({ children }: {
|
|
15
16
|
children: ReactNode;
|
|
16
17
|
}): JSX.Element;
|
|
@@ -15,7 +15,8 @@ function SplitPane({
|
|
|
15
15
|
direction = "horizontal",
|
|
16
16
|
showDivider = "hover",
|
|
17
17
|
gutterSize = 16,
|
|
18
|
-
storageKey
|
|
18
|
+
storageKey,
|
|
19
|
+
fillViewport = false
|
|
19
20
|
}) {
|
|
20
21
|
return /* @__PURE__ */ jsx(
|
|
21
22
|
SplitPaneProvider,
|
|
@@ -25,14 +26,23 @@ function SplitPane({
|
|
|
25
26
|
minPrimarySize,
|
|
26
27
|
minSecondarySize,
|
|
27
28
|
storageKey,
|
|
28
|
-
children: /* @__PURE__ */ jsx(
|
|
29
|
+
children: /* @__PURE__ */ jsx(
|
|
30
|
+
SplitPaneContainer,
|
|
31
|
+
{
|
|
32
|
+
showDivider,
|
|
33
|
+
gutterSize,
|
|
34
|
+
fillViewport,
|
|
35
|
+
children
|
|
36
|
+
}
|
|
37
|
+
)
|
|
29
38
|
}
|
|
30
39
|
);
|
|
31
40
|
}
|
|
32
41
|
function SplitPaneContainer({
|
|
33
42
|
children,
|
|
34
43
|
showDivider,
|
|
35
|
-
gutterSize
|
|
44
|
+
gutterSize,
|
|
45
|
+
fillViewport
|
|
36
46
|
}) {
|
|
37
47
|
const { direction, primarySize, containerRef } = useSplitPaneContext();
|
|
38
48
|
const style = useMemo(
|
|
@@ -49,6 +59,7 @@ function SplitPaneContainer({
|
|
|
49
59
|
className: styles.container,
|
|
50
60
|
"data-direction": direction,
|
|
51
61
|
"data-divider": showDivider,
|
|
62
|
+
"data-fill-viewport": fillViewport,
|
|
52
63
|
style,
|
|
53
64
|
children
|
|
54
65
|
}
|