rift-ds 1.0.0 → 1.1.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/LICENSE +1 -1
- package/README.md +11 -3
- package/components/AppLayout/AppLayout.css +13 -3
- package/components/AppLayout/AppLayout.d.ts +5 -1
- package/components/AppLayout/AppLayout.js +4 -0
- package/components/AppSidebar/AppSidebar.css +237 -0
- package/components/AppSidebar/AppSidebar.d.ts +32 -3
- package/components/AppSidebar/AppSidebar.js +187 -16
- package/components/BottomNav/BottomNav.css +417 -0
- package/components/BottomNav/BottomNav.d.ts +73 -0
- package/components/BottomNav/BottomNav.js +100 -0
- package/components/Chart/AreaChart.js +67 -56
- package/components/Chart/BarChart.js +67 -56
- package/components/Chart/ComboChart.js +93 -82
- package/components/Chart/LineChart.js +59 -48
- package/components/Chart/PieChart.js +56 -45
- package/components/Chart/RadarChart.js +60 -49
- package/components/Chart/RadialChart.js +70 -59
- package/components/Chart/ScatterChart.js +61 -50
- package/components/Chart/StackedBarChart.js +64 -53
- package/components/Chart/Treemap.js +34 -23
- package/components/Nav/Nav.d.ts +11 -3
- package/components/Nav/Nav.js +3 -2
- package/components/SidebarPanel/SidebarPanel.css +291 -0
- package/components/SidebarPanel/SidebarPanel.d.ts +45 -0
- package/components/SidebarPanel/SidebarPanel.js +166 -0
- package/components/Stepper/Stepper.d.ts +3 -1
- package/components/Stepper/Stepper.js +1 -1
- package/components/TopAppBar/TopAppBar.css +464 -0
- package/components/TopAppBar/TopAppBar.d.ts +80 -0
- package/components/TopAppBar/TopAppBar.js +138 -0
- package/components/registry.json +25 -1
- package/components/registry.json.d.ts +25 -1
- package/components/registry.json.js +1 -1
- package/index.d.ts +3 -0
- package/index.js +6 -0
- package/package.json +5 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback } from "react";
|
|
2
|
+
import { useId, useCallback } from "react";
|
|
3
3
|
import { ResponsiveContainer, BarChart, CartesianGrid, XAxis, YAxis, Tooltip, Bar } from "recharts";
|
|
4
4
|
import { getChartSeriesColors } from "./palette.js";
|
|
5
5
|
import "./Chart.css";
|
|
@@ -29,6 +29,8 @@ const StackedBarChart = ({
|
|
|
29
29
|
bare = false,
|
|
30
30
|
className = ""
|
|
31
31
|
}) => {
|
|
32
|
+
const titleId = useId();
|
|
33
|
+
const subtitleId = useId();
|
|
32
34
|
const baseClass = "ds-chart";
|
|
33
35
|
const classes = [baseClass, bare ? `${baseClass}--bare` : "", className].filter(Boolean).join(" ");
|
|
34
36
|
const textSecondary = getCSSVar("--color-text-secondary", "#303030");
|
|
@@ -40,58 +42,67 @@ const StackedBarChart = ({
|
|
|
40
42
|
(props) => /* @__PURE__ */ jsx(StackedTooltip, { ...props }),
|
|
41
43
|
[]
|
|
42
44
|
);
|
|
43
|
-
return /* @__PURE__ */ jsxs(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
45
|
+
return /* @__PURE__ */ jsxs(
|
|
46
|
+
"div",
|
|
47
|
+
{
|
|
48
|
+
className: classes,
|
|
49
|
+
role: "figure",
|
|
50
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
51
|
+
"aria-describedby": subtitle ? subtitleId : void 0,
|
|
52
|
+
children: [
|
|
53
|
+
(title || subtitle || summaryItems) && /* @__PURE__ */ jsxs("div", { className: `${baseClass}__header`, children: [
|
|
54
|
+
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__header-text`, children: [
|
|
55
|
+
title && /* @__PURE__ */ jsx("h3", { id: titleId, className: `${baseClass}__title`, children: title }),
|
|
56
|
+
subtitle && /* @__PURE__ */ jsx("p", { id: subtitleId, className: `${baseClass}__subtitle`, children: subtitle })
|
|
57
|
+
] }),
|
|
58
|
+
summaryItems && summaryItems.length > 0 && /* @__PURE__ */ jsx("div", { className: `${baseClass}__summary`, children: summaryItems.map((item, i) => /* @__PURE__ */ jsxs("div", { className: `${baseClass}__summary-item`, children: [
|
|
59
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__summary-label`, children: item.label }),
|
|
60
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__summary-value`, children: typeof item.value === "number" ? item.value.toLocaleString() : item.value })
|
|
61
|
+
] }, i)) })
|
|
62
|
+
] }),
|
|
63
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__body`, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsxs(BarChart, { data, margin: { top: 8, right: 4, bottom: 0, left: -12 }, children: [
|
|
64
|
+
/* @__PURE__ */ jsx(CartesianGrid, { vertical: false, stroke: gridColor }),
|
|
65
|
+
/* @__PURE__ */ jsx(
|
|
66
|
+
XAxis,
|
|
67
|
+
{
|
|
68
|
+
dataKey: xKey,
|
|
69
|
+
tick: { fill: textSecondary, fontSize: 12 },
|
|
70
|
+
tickLine: false,
|
|
71
|
+
axisLine: { stroke: gridColor }
|
|
72
|
+
}
|
|
73
|
+
),
|
|
74
|
+
/* @__PURE__ */ jsx(
|
|
75
|
+
YAxis,
|
|
76
|
+
{
|
|
77
|
+
tick: { fill: textSecondary, fontSize: 12 },
|
|
78
|
+
tickLine: false,
|
|
79
|
+
axisLine: false,
|
|
80
|
+
tickFormatter: yAxisFormatter
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsx(
|
|
84
|
+
Tooltip,
|
|
85
|
+
{
|
|
86
|
+
content: renderTooltip,
|
|
87
|
+
cursor: { fill: cursorColor, opacity: 0.4 }
|
|
88
|
+
}
|
|
89
|
+
),
|
|
90
|
+
series.map((s, i) => /* @__PURE__ */ jsx(
|
|
91
|
+
Bar,
|
|
92
|
+
{
|
|
93
|
+
dataKey: s.dataKey,
|
|
94
|
+
name: s.label,
|
|
95
|
+
fill: s.color || defaultColors[i % defaultColors.length],
|
|
96
|
+
stackId: "stack",
|
|
97
|
+
radius: i === series.length - 1 ? [3, 3, 0, 0] : [0, 0, 0, 0],
|
|
98
|
+
maxBarSize: 32
|
|
99
|
+
},
|
|
100
|
+
s.dataKey
|
|
101
|
+
))
|
|
102
|
+
] }) }) })
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
);
|
|
95
106
|
};
|
|
96
107
|
export {
|
|
97
108
|
StackedBarChart
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback } from "react";
|
|
2
|
+
import { useId, useCallback } from "react";
|
|
3
3
|
import { ResponsiveContainer, Treemap as Treemap$1, Tooltip } from "recharts";
|
|
4
4
|
import { getChartSeriesColors } from "./palette.js";
|
|
5
5
|
import "./Chart.css";
|
|
@@ -60,6 +60,8 @@ const Treemap = ({
|
|
|
60
60
|
bare = false,
|
|
61
61
|
className = ""
|
|
62
62
|
}) => {
|
|
63
|
+
const titleId = useId();
|
|
64
|
+
const subtitleId = useId();
|
|
63
65
|
const baseClass = "ds-chart";
|
|
64
66
|
const classes = [baseClass, bare ? `${baseClass}--bare` : "", className].filter(Boolean).join(" ");
|
|
65
67
|
const renderTooltip = useCallback(
|
|
@@ -67,28 +69,37 @@ const Treemap = ({
|
|
|
67
69
|
(props) => /* @__PURE__ */ jsx(TreemapTooltip, { ...props }),
|
|
68
70
|
[]
|
|
69
71
|
);
|
|
70
|
-
return /* @__PURE__ */ jsxs(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
children: /* @__PURE__ */ jsx(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
72
|
+
return /* @__PURE__ */ jsxs(
|
|
73
|
+
"div",
|
|
74
|
+
{
|
|
75
|
+
className: classes,
|
|
76
|
+
role: "figure",
|
|
77
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
78
|
+
"aria-describedby": subtitle ? subtitleId : void 0,
|
|
79
|
+
children: [
|
|
80
|
+
(title || subtitle || summaryItems) && /* @__PURE__ */ jsxs("div", { className: `${baseClass}__header`, children: [
|
|
81
|
+
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__header-text`, children: [
|
|
82
|
+
title && /* @__PURE__ */ jsx("h3", { id: titleId, className: `${baseClass}__title`, children: title }),
|
|
83
|
+
subtitle && /* @__PURE__ */ jsx("p", { id: subtitleId, className: `${baseClass}__subtitle`, children: subtitle })
|
|
84
|
+
] }),
|
|
85
|
+
summaryItems && summaryItems.length > 0 && /* @__PURE__ */ jsx("div", { className: `${baseClass}__summary`, children: summaryItems.map((item, i) => /* @__PURE__ */ jsxs("div", { className: `${baseClass}__summary-item`, children: [
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__summary-label`, children: item.label }),
|
|
87
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__summary-value`, children: typeof item.value === "number" ? item.value.toLocaleString() : item.value })
|
|
88
|
+
] }, i)) })
|
|
89
|
+
] }),
|
|
90
|
+
/* @__PURE__ */ jsx("div", { className: `${baseClass}__body`, children: /* @__PURE__ */ jsx(ResponsiveContainer, { width: "100%", height, children: /* @__PURE__ */ jsx(
|
|
91
|
+
Treemap$1,
|
|
92
|
+
{
|
|
93
|
+
data,
|
|
94
|
+
dataKey,
|
|
95
|
+
aspectRatio: 4 / 3,
|
|
96
|
+
content: /* @__PURE__ */ jsx(TreemapContent, {}),
|
|
97
|
+
children: /* @__PURE__ */ jsx(Tooltip, { content: renderTooltip })
|
|
98
|
+
}
|
|
99
|
+
) }) })
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
);
|
|
92
103
|
};
|
|
93
104
|
export {
|
|
94
105
|
Treemap
|
package/components/Nav/Nav.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
import { ButtonGroupProps } from '../ButtonGroup/ButtonGroup';
|
|
3
|
-
|
|
3
|
+
/** Props owned by Nav itself — everything else falls through to the `<nav>`. */
|
|
4
|
+
type NavOwnProps = {
|
|
4
5
|
/** Brand/logo text */
|
|
5
6
|
brandText?: string;
|
|
6
7
|
/** Brand icon element (img, svg, etc.) */
|
|
@@ -11,9 +12,16 @@ export interface NavProps {
|
|
|
11
12
|
trailing?: React.ReactNode;
|
|
12
13
|
/** Additional CSS classes */
|
|
13
14
|
className?: string;
|
|
15
|
+
};
|
|
16
|
+
export interface NavProps extends NavOwnProps, Omit<React.ComponentPropsWithoutRef<'nav'>, keyof NavOwnProps> {
|
|
14
17
|
}
|
|
15
18
|
/**
|
|
16
19
|
* Nav component from Figma design system
|
|
17
|
-
* Renders a horizontal navigation bar using ButtonGroup
|
|
20
|
+
* Renders a horizontal navigation bar using ButtonGroup.
|
|
21
|
+
*
|
|
22
|
+
* The landmark is labelled "Main" by default so assistive tech can tell it
|
|
23
|
+
* apart from any other navigation on the page; pass `aria-label` to name it
|
|
24
|
+
* differently. Unrecognised props are spread onto the `<nav>`.
|
|
18
25
|
*/
|
|
19
|
-
export declare const Nav: ({ brandText, brandIcon, buttons, trailing, className, }: NavProps) => React.JSX.Element;
|
|
26
|
+
export declare const Nav: ({ brandText, brandIcon, buttons, trailing, className, ...rest }: NavProps) => React.JSX.Element;
|
|
27
|
+
export {};
|
package/components/Nav/Nav.js
CHANGED
|
@@ -7,10 +7,11 @@ const Nav = ({
|
|
|
7
7
|
brandIcon,
|
|
8
8
|
buttons,
|
|
9
9
|
trailing,
|
|
10
|
-
className = ""
|
|
10
|
+
className = "",
|
|
11
|
+
...rest
|
|
11
12
|
}) => {
|
|
12
13
|
const baseClass = "ds-nav";
|
|
13
|
-
return /* @__PURE__ */ jsxs("nav", { className: `${baseClass} ${className}`, children: [
|
|
14
|
+
return /* @__PURE__ */ jsxs("nav", { "aria-label": "Main", ...rest, className: `${baseClass} ${className}`, children: [
|
|
14
15
|
(brandText || brandIcon) && /* @__PURE__ */ jsxs("div", { className: `${baseClass}__brand`, children: [
|
|
15
16
|
brandIcon && /* @__PURE__ */ jsx("span", { className: `${baseClass}__brand-icon`, children: brandIcon }),
|
|
16
17
|
brandText && /* @__PURE__ */ jsx("span", { className: `${baseClass}__brand-text`, children: brandText })
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
SIDEBAR PANEL — the secondary navigation column
|
|
3
|
+
A heading, optional group labels, flat rows and
|
|
4
|
+
one level of accordion nesting. Row geometry
|
|
5
|
+
repeats AppSidebar's sub-items (40px pill rows,
|
|
6
|
+
12px edge inset, tree-line connectors), so the
|
|
7
|
+
two columns read as one navigation system.
|
|
8
|
+
============================================ */
|
|
9
|
+
|
|
10
|
+
/* ============================================
|
|
11
|
+
WRAPPER
|
|
12
|
+
============================================ */
|
|
13
|
+
.ds-sidebar-panel {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
gap: var(--gap-400);
|
|
17
|
+
width: var(--ds-sidebar-panel-width, 240px);
|
|
18
|
+
height: 100%;
|
|
19
|
+
min-height: 0;
|
|
20
|
+
padding: var(--padding-500) 0;
|
|
21
|
+
box-sizing: border-box;
|
|
22
|
+
background-color: var(--color-bg-page-primary);
|
|
23
|
+
color: var(--color-text-primary);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* ============================================
|
|
27
|
+
BACK ROW — the drill-in's way out
|
|
28
|
+
============================================ */
|
|
29
|
+
.ds-sidebar-panel__back {
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
gap: var(--gap-100);
|
|
33
|
+
height: 40px;
|
|
34
|
+
margin: 0 var(--padding-300);
|
|
35
|
+
padding: var(--padding-200);
|
|
36
|
+
/* The chevron glyph carries its own side bearing, so the row drops its
|
|
37
|
+
left padding and the glyph's ink lands on the rows' text edge. */
|
|
38
|
+
padding-left: 0;
|
|
39
|
+
border: none;
|
|
40
|
+
border-radius: var(--radius-pill);
|
|
41
|
+
background: transparent;
|
|
42
|
+
color: var(--color-text-secondary);
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
text-align: left;
|
|
45
|
+
flex-shrink: 0;
|
|
46
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ds-sidebar-panel__back:hover {
|
|
50
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.ds-sidebar-panel__back-icon {
|
|
54
|
+
--icon-size: var(--icon-size-600);
|
|
55
|
+
color: inherit;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* ============================================
|
|
59
|
+
HEADER — title + collapse control
|
|
60
|
+
============================================ */
|
|
61
|
+
.ds-sidebar-panel__header {
|
|
62
|
+
display: flex;
|
|
63
|
+
justify-content: space-between;
|
|
64
|
+
align-items: flex-start;
|
|
65
|
+
gap: var(--gap-200);
|
|
66
|
+
min-height: 24px;
|
|
67
|
+
padding: 0 var(--padding-500);
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.ds-sidebar-panel__title {
|
|
72
|
+
margin: 0;
|
|
73
|
+
font-family: var(--font-overline-family);
|
|
74
|
+
font-size: var(--font-overline-size);
|
|
75
|
+
font-weight: var(--font-overline-weight);
|
|
76
|
+
line-height: var(--font-overline-line-height);
|
|
77
|
+
letter-spacing: var(--font-overline-letter-spacing);
|
|
78
|
+
text-transform: uppercase;
|
|
79
|
+
color: var(--color-text-secondary);
|
|
80
|
+
min-width: 0;
|
|
81
|
+
/* Wraps rather than truncates: the heading names the section, and a
|
|
82
|
+
clipped name is the one thing the reader cannot recover from. */
|
|
83
|
+
overflow-wrap: anywhere;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.ds-sidebar-panel__collapse {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
width: 32px;
|
|
91
|
+
height: 32px;
|
|
92
|
+
/* Pulls the 32px hit area back so the 24px glyph sits on the same
|
|
93
|
+
right edge as the rows' badges and chevrons. */
|
|
94
|
+
margin-right: calc(var(--padding-100) * -1);
|
|
95
|
+
/* Centred on the heading's first line however many lines it wraps to. */
|
|
96
|
+
margin-top: calc((var(--font-overline-line-height) - 32px) / 2);
|
|
97
|
+
margin-bottom: calc((var(--font-overline-line-height) - 32px) / 2);
|
|
98
|
+
padding: 0;
|
|
99
|
+
flex-shrink: 0;
|
|
100
|
+
border: none;
|
|
101
|
+
border-radius: var(--radius-pill);
|
|
102
|
+
background: transparent;
|
|
103
|
+
color: var(--color-icon-primary);
|
|
104
|
+
cursor: pointer;
|
|
105
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.ds-sidebar-panel__collapse:hover {
|
|
109
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.ds-sidebar-panel__collapse .material-symbols-rounded {
|
|
113
|
+
--icon-size: var(--icon-size-600);
|
|
114
|
+
color: inherit;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* ============================================
|
|
118
|
+
BODY + GROUPS
|
|
119
|
+
============================================ */
|
|
120
|
+
.ds-sidebar-panel__body {
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
gap: var(--gap-500);
|
|
124
|
+
flex: 1;
|
|
125
|
+
min-height: 0;
|
|
126
|
+
overflow-y: auto;
|
|
127
|
+
overflow-x: hidden;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ds-sidebar-panel__group {
|
|
131
|
+
display: flex;
|
|
132
|
+
flex-direction: column;
|
|
133
|
+
gap: var(--gap-100);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.ds-sidebar-panel__group-label {
|
|
137
|
+
padding: 0 var(--padding-500);
|
|
138
|
+
font-family: var(--font-paragraph-sm-family);
|
|
139
|
+
font-size: var(--font-paragraph-sm-size);
|
|
140
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
141
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
142
|
+
color: var(--color-text-tertiary);
|
|
143
|
+
white-space: nowrap;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.ds-sidebar-panel__list,
|
|
147
|
+
.ds-sidebar-panel__nested-list {
|
|
148
|
+
display: flex;
|
|
149
|
+
flex-direction: column;
|
|
150
|
+
gap: var(--gap-100);
|
|
151
|
+
margin: 0;
|
|
152
|
+
padding: 0;
|
|
153
|
+
list-style: none;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* ============================================
|
|
157
|
+
ROWS
|
|
158
|
+
============================================ */
|
|
159
|
+
.ds-sidebar-panel__row {
|
|
160
|
+
display: flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
gap: var(--gap-200);
|
|
163
|
+
width: calc(100% - var(--padding-300) * 2);
|
|
164
|
+
height: 40px;
|
|
165
|
+
margin: 0 var(--padding-300);
|
|
166
|
+
padding: var(--padding-200);
|
|
167
|
+
box-sizing: border-box;
|
|
168
|
+
border: none;
|
|
169
|
+
border-radius: var(--radius-pill);
|
|
170
|
+
background: transparent;
|
|
171
|
+
color: var(--color-text-primary);
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
text-align: left;
|
|
174
|
+
text-decoration: none;
|
|
175
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.ds-sidebar-panel__row:hover,
|
|
179
|
+
.ds-sidebar-panel__row--active {
|
|
180
|
+
background-color: var(--color-action-passive-bg-hover);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.ds-sidebar-panel__row:focus-visible,
|
|
184
|
+
.ds-sidebar-panel__back:focus-visible,
|
|
185
|
+
.ds-sidebar-panel__collapse:focus-visible {
|
|
186
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
187
|
+
outline-offset: -2px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.ds-sidebar-panel__label {
|
|
191
|
+
flex: 1;
|
|
192
|
+
min-width: 0;
|
|
193
|
+
font-family: var(--font-paragraph-family);
|
|
194
|
+
font-size: var(--font-paragraph-size);
|
|
195
|
+
font-weight: var(--font-paragraph-weight);
|
|
196
|
+
line-height: var(--font-paragraph-line-height);
|
|
197
|
+
letter-spacing: var(--font-paragraph-letter-spacing);
|
|
198
|
+
color: inherit;
|
|
199
|
+
white-space: nowrap;
|
|
200
|
+
overflow: hidden;
|
|
201
|
+
text-overflow: ellipsis;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* The current page and a collapsed accordion hiding it carry the same
|
|
205
|
+
emphasis, so a reader can find their place without opening anything. */
|
|
206
|
+
.ds-sidebar-panel__row--active .ds-sidebar-panel__label,
|
|
207
|
+
.ds-sidebar-panel__row--holds-active .ds-sidebar-panel__label {
|
|
208
|
+
font-family: var(--font-paragraph-emphasis-family);
|
|
209
|
+
font-weight: var(--font-paragraph-emphasis-weight);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.ds-sidebar-panel__badge {
|
|
213
|
+
flex-shrink: 0;
|
|
214
|
+
font-family: var(--font-caption-family);
|
|
215
|
+
font-size: var(--font-caption-size);
|
|
216
|
+
font-weight: var(--font-paragraph-sm-emphasis-weight);
|
|
217
|
+
line-height: var(--font-caption-line-height);
|
|
218
|
+
color: var(--color-text-secondary);
|
|
219
|
+
background-color: var(--color-bg-container-tertiary);
|
|
220
|
+
border-radius: var(--radius-pill);
|
|
221
|
+
padding: var(--padding-050) var(--padding-200);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* On a filled row the pill steps back to the page ground, or it would
|
|
225
|
+
share the row's fill and dissolve into it. */
|
|
226
|
+
.ds-sidebar-panel__row--active .ds-sidebar-panel__badge,
|
|
227
|
+
.ds-sidebar-panel__row:hover .ds-sidebar-panel__badge {
|
|
228
|
+
background-color: var(--color-bg-page-primary);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.ds-sidebar-panel__chevron {
|
|
232
|
+
--icon-size: var(--icon-size-500);
|
|
233
|
+
flex-shrink: 0;
|
|
234
|
+
/* Pulls the glyph's side bearing out, so its ink ends on the same right
|
|
235
|
+
edge as a badge in the row above. */
|
|
236
|
+
margin-right: calc(var(--padding-100) * -1);
|
|
237
|
+
color: var(--color-icon-secondary);
|
|
238
|
+
transition: transform var(--motion-duration-slow) var(--motion-ease-emphasized);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.ds-sidebar-panel__chevron--open {
|
|
242
|
+
transform: rotate(180deg);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* ============================================
|
|
246
|
+
NESTED ROWS (accordion children)
|
|
247
|
+
The grid-row trick animates to the content's
|
|
248
|
+
own height, with no max-height guess to clip.
|
|
249
|
+
============================================ */
|
|
250
|
+
.ds-sidebar-panel__nested {
|
|
251
|
+
display: grid;
|
|
252
|
+
grid-template-rows: 0fr;
|
|
253
|
+
transition: grid-template-rows var(--motion-duration-slow) var(--motion-ease-emphasized);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.ds-sidebar-panel__nested--open {
|
|
257
|
+
grid-template-rows: 1fr;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.ds-sidebar-panel__nested-list {
|
|
261
|
+
min-height: 0;
|
|
262
|
+
overflow: hidden;
|
|
263
|
+
/* The tree line: aligned under the parent label's first letter, so the
|
|
264
|
+
children visibly hang from it (12px inset + 8px row padding). */
|
|
265
|
+
position: relative;
|
|
266
|
+
padding-top: var(--gap-100);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.ds-sidebar-panel__nested-list::before {
|
|
270
|
+
content: '';
|
|
271
|
+
position: absolute;
|
|
272
|
+
top: var(--gap-100);
|
|
273
|
+
bottom: 0;
|
|
274
|
+
left: calc(var(--padding-300) + var(--padding-200));
|
|
275
|
+
width: var(--border-025);
|
|
276
|
+
background-color: var(--color-bg-container-border);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.ds-sidebar-panel__row--nested {
|
|
280
|
+
width: calc(100% - var(--padding-300) * 2 - var(--padding-400));
|
|
281
|
+
margin-left: calc(var(--padding-300) + var(--padding-400));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Icons take the colour of the text around them, whatever a consumer
|
|
285
|
+
stylesheet sets on the icon font class globally. */
|
|
286
|
+
.ds-sidebar-panel .material-symbols-rounded {
|
|
287
|
+
color: inherit;
|
|
288
|
+
}
|
|
289
|
+
.ds-sidebar-panel .ds-sidebar-panel__chevron {
|
|
290
|
+
color: var(--color-icon-secondary);
|
|
291
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface SidebarPanelItem {
|
|
3
|
+
/** Unique key for this item */
|
|
4
|
+
key: string;
|
|
5
|
+
/** Display label */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Renders the item as a real link to this URL instead of a button. Ignored when the item has children, whose row is the accordion toggle */
|
|
8
|
+
href?: string;
|
|
9
|
+
/** Click handler — also fires on a link item, so a consumer can route client-side */
|
|
10
|
+
onClick?: () => void;
|
|
11
|
+
/** Trailing count pill, e.g. unread items */
|
|
12
|
+
badge?: string | number;
|
|
13
|
+
/** Group heading this item sits under; consecutive items sharing a group render beneath one heading */
|
|
14
|
+
group?: string;
|
|
15
|
+
/** Nested items — turns this row into an accordion. One level deep: grandchildren are not rendered */
|
|
16
|
+
children?: SidebarPanelItem[];
|
|
17
|
+
}
|
|
18
|
+
type SidebarPanelOwnProps = {
|
|
19
|
+
/** Items to list, optionally grouped with `group` and nested one level with `children` */
|
|
20
|
+
items: SidebarPanelItem[];
|
|
21
|
+
/** Heading at the top of the panel, usually the label of the item that opened it. Also the panel's accessible name */
|
|
22
|
+
title?: string;
|
|
23
|
+
/** Key of the item for the current page. Its accordion parent starts open */
|
|
24
|
+
activeKey?: string;
|
|
25
|
+
/** Keys of the accordion rows open on first render, in addition to the active item's parent */
|
|
26
|
+
defaultOpenKeys?: string[];
|
|
27
|
+
/** Renders a collapse button beside the heading and calls this when it is pressed */
|
|
28
|
+
onCollapse?: () => void;
|
|
29
|
+
/** Renders a back row above the heading and calls this when it is pressed; the drill-in navigation on small screens */
|
|
30
|
+
onBack?: () => void;
|
|
31
|
+
/** Label of the back row */
|
|
32
|
+
backLabel?: string;
|
|
33
|
+
/** Additional CSS classes */
|
|
34
|
+
className?: string;
|
|
35
|
+
};
|
|
36
|
+
export interface SidebarPanelProps extends SidebarPanelOwnProps, Omit<React.ComponentPropsWithoutRef<'nav'>, keyof SidebarPanelOwnProps> {
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* SidebarPanel — the secondary column of app navigation. Lists the pages
|
|
40
|
+
* inside one section, with optional group headings and one level of
|
|
41
|
+
* accordion nesting. Stands alone, or opens beside `AppSidebar` when its
|
|
42
|
+
* items carry deeper levels (see `subNav` there).
|
|
43
|
+
*/
|
|
44
|
+
export declare const SidebarPanel: React.ForwardRefExoticComponent<SidebarPanelProps & React.RefAttributes<HTMLElement>>;
|
|
45
|
+
export {};
|