@robr0/design-system 0.10.0 → 0.12.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/README.md +9 -8
- package/charts.d.ts +1 -0
- package/charts.js +2 -0
- package/components/AgentPlan/AgentPlan.css +14 -3
- package/components/AiButton/AiButton.css +1 -1
- package/components/Alert/Alert.css +9 -0
- package/components/AlertDialog/AlertDialog.css +3 -1
- package/components/AlertDialog/AlertDialog.js +2 -3
- package/components/AppLayout/AppLayout.d.ts +7 -1
- package/components/AppLayout/AppLayout.js +2 -1
- package/components/AppSidebar/AppSidebar.css +113 -40
- package/components/AppSidebar/AppSidebar.d.ts +14 -1
- package/components/AppSidebar/AppSidebar.js +26 -17
- package/components/Badge/Badge.css +4 -5
- package/components/Card/Card.css +7 -2
- package/components/CardStack/CardStack.css +106 -0
- package/components/CardStack/CardStack.d.ts +44 -0
- package/components/CardStack/CardStack.js +140 -0
- package/components/Carousel/Carousel.css +9 -0
- package/components/Carousel/Carousel.js +37 -4
- package/components/Chart/AreaChart.d.ts +5 -1
- package/components/Chart/AreaChart.js +11 -9
- package/components/Chart/BarChart.d.ts +3 -1
- package/components/Chart/BarChart.js +3 -3
- package/components/Chart/Chart.css +45 -0
- package/components/Chart/ComboChart.d.ts +40 -0
- package/components/Chart/ComboChart.js +142 -0
- package/components/Chart/LineChart.d.ts +3 -1
- package/components/Chart/LineChart.js +7 -6
- package/components/Chart/PieChart.d.ts +3 -1
- package/components/Chart/PieChart.js +5 -18
- package/components/Chart/RadarChart.d.ts +3 -1
- package/components/Chart/RadarChart.js +8 -7
- package/components/Chart/RadialChart.d.ts +7 -1
- package/components/Chart/RadialChart.js +53 -58
- package/components/Chart/ScatterChart.d.ts +3 -1
- package/components/Chart/ScatterChart.js +6 -16
- package/components/Chart/StackedBarChart.d.ts +3 -1
- package/components/Chart/StackedBarChart.js +5 -18
- package/components/Chart/Treemap.d.ts +3 -1
- package/components/Chart/Treemap.js +6 -20
- package/components/Chart/palette.d.ts +1 -0
- package/components/Chart/palette.js +17 -0
- package/components/ChatMarker/ChatMarker.css +9 -0
- package/components/ChatMessage/ChatMessage.css +16 -0
- package/components/ChatThread/ChatThread.js +2 -2
- package/components/Chip/Chip.css +9 -0
- package/components/CodeBlock/CodeBlock.css +10 -1
- package/components/CodeBlock/CodeBlock.js +2 -1
- package/components/ColorPicker/ColorPicker.js +10 -0
- package/components/Combobox/Combobox.css +9 -0
- package/components/CommandPalette/CommandPalette.css +9 -0
- package/components/CommandPalette/CommandPalette.js +31 -5
- package/components/Composer/Composer.css +118 -0
- package/components/Composer/Composer.d.ts +7 -0
- package/components/Composer/Composer.js +7 -1
- package/components/ContactCard/ContactCard.css +9 -0
- package/components/ContextMenu/ContextMenu.js +39 -3
- package/components/DatePicker/DatePicker.js +16 -0
- package/components/Dialog/Dialog.css +3 -1
- package/components/Dialog/Dialog.js +5 -4
- package/components/DocumentChip/DocumentChip.css +9 -0
- package/components/Dropdown/Dropdown.js +22 -3
- package/components/DropdownMenu/DropdownMenu.js +43 -6
- package/components/EmptyState/EmptyState.css +9 -0
- package/components/FileInput/FileInput.css +9 -0
- package/components/FunnelChart/FunnelChart.css +41 -0
- package/components/FunnelChart/FunnelChart.d.ts +40 -0
- package/components/FunnelChart/FunnelChart.js +48 -0
- package/components/Globe/Globe.css +155 -0
- package/components/Globe/Globe.d.ts +96 -0
- package/components/Globe/Globe.js +415 -0
- package/components/InterruptCard/InterruptCard.css +27 -17
- package/components/InterruptCard/InterruptCard.d.ts +1 -1
- package/components/InterruptCard/InterruptCard.js +1 -1
- package/components/LegendTile/LegendTile.css +60 -0
- package/components/LegendTile/LegendTile.d.ts +30 -0
- package/components/LegendTile/LegendTile.js +21 -0
- package/components/MapCallout/MapCallout.css +46 -0
- package/components/MapCallout/MapCallout.d.ts +29 -0
- package/components/MapCallout/MapCallout.js +17 -0
- package/components/MapLegend/MapLegend.css +88 -0
- package/components/MapLegend/MapLegend.d.ts +39 -0
- package/components/MapLegend/MapLegend.js +68 -0
- package/components/MessageActions/MessageActions.css +9 -0
- package/components/MessageCard/MessageCard.css +68 -16
- package/components/MessageCard/MessageCard.d.ts +1 -1
- package/components/MessageCard/MessageCard.js +6 -4
- package/components/ModelPicker/ModelPicker.css +4 -1
- package/components/ModelPicker/ModelPicker.js +43 -1
- package/components/NotificationCenter/NotificationCenter.css +9 -0
- package/components/NotificationCenter/NotificationCenter.js +26 -10
- package/components/NumberInput/NumberInput.css +9 -0
- package/components/Panel/Panel.css +26 -0
- package/components/Panel/Panel.d.ts +22 -0
- package/components/Panel/Panel.js +19 -0
- package/components/Popover/Popover.css +3 -1
- package/components/Popover/Popover.js +2 -1
- package/components/SourceChip/SourceChip.css +9 -0
- package/components/Stat/Stat.css +44 -2
- package/components/Stat/Stat.d.ts +3 -1
- package/components/Stat/Stat.js +7 -1
- package/components/Stepper/Stepper.css +9 -0
- package/components/TagInput/TagInput.css +9 -0
- package/components/TimePicker/TimePicker.js +4 -1
- package/components/Toast/Toast.css +32 -11
- package/components/Toast/Toast.js +5 -4
- package/components/ToggleGroup/ToggleGroup.css +9 -0
- package/components/ToolCall/ToolCall.css +18 -6
- package/components/Tooltip/Tooltip.js +20 -16
- package/components/registry.json +70 -0
- package/components/registry.json.d.ts +70 -0
- package/components/registry.json.js +2 -2
- package/index.d.ts +7 -0
- package/index.js +14 -0
- package/package.json +5 -1
- package/tokens/motion.d.ts +23 -0
- package/tokens/motion.js +14 -0
- package/tokens/registry.json +21 -1
- package/tokens/registry.json.d.ts +21 -1
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-dark.css +14 -0
- package/tokens/tokens-light.css +22 -0
- package/tokens/tokens-primitives.css +2 -0
- package/tokens/tokens-typography.css +32 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
-
import React, { useState } from "react";
|
|
3
|
+
import React, { useState, useId } from "react";
|
|
4
4
|
import { EmptyState } from "../EmptyState/EmptyState.js";
|
|
5
5
|
import "./NotificationCenter.css";
|
|
6
6
|
import "../../fonts/material-symbols.css";
|
|
@@ -42,6 +42,11 @@ const NotificationCenter = React.forwardRef(
|
|
|
42
42
|
const isTabControlled = activeTab !== void 0;
|
|
43
43
|
const [uncontrolledTab, setUncontrolledTab] = useState(defaultTab ?? tabs?.[0]?.value);
|
|
44
44
|
const currentTab = isTabControlled ? activeTab : uncontrolledTab;
|
|
45
|
+
const idBase = useId();
|
|
46
|
+
const panelId = `${idBase}-panel`;
|
|
47
|
+
const tabIdFor = (index) => `${idBase}-tab-${index}`;
|
|
48
|
+
const activeTabIndex = tabs?.findIndex((tab) => tab.value === currentTab) ?? -1;
|
|
49
|
+
const hasTabs = !!tabs && tabs.length > 0;
|
|
45
50
|
const selectTab = (value) => {
|
|
46
51
|
if (!isTabControlled) setUncontrolledTab(value);
|
|
47
52
|
onTabChange?.(value);
|
|
@@ -80,21 +85,23 @@ const NotificationCenter = React.forwardRef(
|
|
|
80
85
|
/* @__PURE__ */ jsxs("header", { className: `${baseClass}__header`, children: [
|
|
81
86
|
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__heading`, children: [
|
|
82
87
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__title`, children: title }),
|
|
83
|
-
unreadCount !== void 0 && unreadCount > 0 && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__unread`, children: [
|
|
88
|
+
unreadCount !== void 0 && unreadCount > 0 && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__unread`, "aria-live": "polite", children: [
|
|
84
89
|
unreadCount,
|
|
85
90
|
" unread"
|
|
86
91
|
] })
|
|
87
92
|
] }),
|
|
88
93
|
onMarkAllRead && /* @__PURE__ */ jsx("button", { type: "button", className: `${baseClass}__mark-all`, onClick: onMarkAllRead, children: markAllLabel })
|
|
89
94
|
] }),
|
|
90
|
-
|
|
95
|
+
hasTabs && /* @__PURE__ */ jsx("div", { className: `${baseClass}__tabs`, role: "tablist", "aria-label": `${title} filters`, children: tabs.map((tab, index) => {
|
|
91
96
|
const isActive = tab.value === currentTab;
|
|
92
97
|
return /* @__PURE__ */ jsxs(
|
|
93
98
|
"button",
|
|
94
99
|
{
|
|
95
100
|
type: "button",
|
|
101
|
+
id: tabIdFor(index),
|
|
96
102
|
role: "tab",
|
|
97
103
|
"aria-selected": isActive,
|
|
104
|
+
"aria-controls": panelId,
|
|
98
105
|
tabIndex: isActive ? 0 : -1,
|
|
99
106
|
className: [
|
|
100
107
|
`${baseClass}__tab`,
|
|
@@ -110,15 +117,24 @@ const NotificationCenter = React.forwardRef(
|
|
|
110
117
|
tab.value
|
|
111
118
|
);
|
|
112
119
|
}) }),
|
|
113
|
-
/* @__PURE__ */ jsx(
|
|
114
|
-
|
|
120
|
+
/* @__PURE__ */ jsx(
|
|
121
|
+
"div",
|
|
115
122
|
{
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
className: `${baseClass}__list`,
|
|
124
|
+
role: hasTabs ? "tabpanel" : void 0,
|
|
125
|
+
id: hasTabs ? panelId : void 0,
|
|
126
|
+
"aria-labelledby": hasTabs && activeTabIndex >= 0 ? tabIdFor(activeTabIndex) : void 0,
|
|
127
|
+
children: hasItems ? children : emptyState ?? /* @__PURE__ */ jsx(
|
|
128
|
+
EmptyState,
|
|
129
|
+
{
|
|
130
|
+
icon: "notifications",
|
|
131
|
+
title: "Nothing new",
|
|
132
|
+
description: "Notifications will collect here as they arrive.",
|
|
133
|
+
size: "compact"
|
|
134
|
+
}
|
|
135
|
+
)
|
|
120
136
|
}
|
|
121
|
-
)
|
|
137
|
+
)
|
|
122
138
|
] });
|
|
123
139
|
}
|
|
124
140
|
);
|
|
@@ -152,3 +152,12 @@
|
|
|
152
152
|
.ds-numberinput--compact .ds-numberinput__stepper {
|
|
153
153
|
padding: 0 var(--padding-sm); /* 8px */
|
|
154
154
|
}
|
|
155
|
+
|
|
156
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
157
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
158
|
+
.material-symbols-rounded itself (a common global default) would
|
|
159
|
+
otherwise override inheritance and detach the icon from the state
|
|
160
|
+
colours this component sets on its parents. */
|
|
161
|
+
.ds-numberinput .material-symbols-rounded {
|
|
162
|
+
color: inherit;
|
|
163
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
PANEL COMPONENT
|
|
3
|
+
The plain dashboard surface
|
|
4
|
+
============================================ */
|
|
5
|
+
|
|
6
|
+
.ds-panel {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: column;
|
|
9
|
+
gap: var(--gap-md);
|
|
10
|
+
min-width: 0;
|
|
11
|
+
background-color: var(--color-bg-container-primary);
|
|
12
|
+
border-radius: var(--radius-xl);
|
|
13
|
+
padding: var(--padding-lg);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* ============================================
|
|
17
|
+
PADDING VARIANTS
|
|
18
|
+
============================================ */
|
|
19
|
+
|
|
20
|
+
.ds-panel--compact {
|
|
21
|
+
padding: var(--padding-md);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.ds-panel--flush {
|
|
25
|
+
padding: 0;
|
|
26
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
/** Props owned by Panel itself; everything else falls through to the <div>. */
|
|
3
|
+
type PanelOwnProps = {
|
|
4
|
+
/** Interior padding: 'default' uses --padding-lg, 'compact' uses --padding-md, 'none' removes it */
|
|
5
|
+
padding?: 'default' | 'compact' | 'none';
|
|
6
|
+
/** Additional CSS classes */
|
|
7
|
+
className?: string;
|
|
8
|
+
/** Panel content */
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
export interface PanelProps extends PanelOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof PanelOwnProps> {
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Panel component: the plain dashboard surface.
|
|
15
|
+
* A rounded container on the primary container background with no border and
|
|
16
|
+
* no shadow: just the surface, ready for whatever a dashboard region holds.
|
|
17
|
+
* Content stacks vertically with a medium gap.
|
|
18
|
+
*
|
|
19
|
+
* Forwards a ref to the `<div>` element and spreads unrecognised props onto it.
|
|
20
|
+
*/
|
|
21
|
+
export declare const Panel: React.ForwardRefExoticComponent<PanelProps & React.RefAttributes<HTMLDivElement>>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import "./Panel.css";
|
|
4
|
+
const Panel = React.forwardRef(
|
|
5
|
+
({ padding = "default", className = "", children, ...rest }, ref) => {
|
|
6
|
+
const baseClass = "ds-panel";
|
|
7
|
+
const classes = [
|
|
8
|
+
baseClass,
|
|
9
|
+
padding === "compact" ? `${baseClass}--compact` : "",
|
|
10
|
+
padding === "none" ? `${baseClass}--flush` : "",
|
|
11
|
+
className
|
|
12
|
+
].filter(Boolean).join(" ");
|
|
13
|
+
return /* @__PURE__ */ jsx("div", { ...rest, ref, className: classes, children });
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
Panel.displayName = "Panel";
|
|
17
|
+
export {
|
|
18
|
+
Panel
|
|
19
|
+
};
|
|
@@ -35,13 +35,15 @@
|
|
|
35
35
|
|
|
36
36
|
/* Hidden by default */
|
|
37
37
|
opacity: 0;
|
|
38
|
+
visibility: hidden; /* keeps panel content out of the tab order when closed */
|
|
38
39
|
pointer-events: none;
|
|
39
40
|
transform: scale(0.96);
|
|
40
|
-
transition: opacity var(--motion-duration-base) var(--motion-ease-standard), transform var(--motion-duration-base) var(--motion-ease-standard);
|
|
41
|
+
transition: opacity var(--motion-duration-base) var(--motion-ease-standard), transform var(--motion-duration-base) var(--motion-ease-standard), visibility var(--motion-duration-base) var(--motion-ease-standard);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
.ds-popover__panel--open {
|
|
44
45
|
opacity: 1;
|
|
46
|
+
visibility: visible;
|
|
45
47
|
pointer-events: auto;
|
|
46
48
|
transform: scale(1);
|
|
47
49
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
3
|
import React, { useState, useRef, useCallback, useEffect } from "react";
|
|
4
|
+
import { MOTION_HOVER_HIDE_DELAY_MS } from "../../tokens/motion.js";
|
|
4
5
|
import "./Popover.css";
|
|
5
6
|
const INTERACTIVE_TAGS = /* @__PURE__ */ new Set(["button", "a", "input", "select", "textarea", "summary"]);
|
|
6
7
|
const canCarryPopoverSemantics = (el) => typeof el.type === "string" ? INTERACTIVE_TAGS.has(el.type) : true;
|
|
@@ -59,7 +60,7 @@ const Popover = ({
|
|
|
59
60
|
};
|
|
60
61
|
const handleMouseLeave = () => {
|
|
61
62
|
if (trigger === "hover") {
|
|
62
|
-
hoverTimeoutRef.current = setTimeout(() => setOpen(false),
|
|
63
|
+
hoverTimeoutRef.current = setTimeout(() => setOpen(false), MOTION_HOVER_HIDE_DELAY_MS);
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
const baseClass = "ds-popover";
|
|
@@ -100,3 +100,12 @@
|
|
|
100
100
|
outline: 2px solid var(--color-action-primary-bg);
|
|
101
101
|
outline-offset: 2px;
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
105
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
106
|
+
.material-symbols-rounded itself (a common global default) would
|
|
107
|
+
otherwise override inheritance and detach the icon from the state
|
|
108
|
+
colours this component sets on its parents. */
|
|
109
|
+
.ds-source-chip .material-symbols-rounded {
|
|
110
|
+
color: inherit;
|
|
111
|
+
}
|
package/components/Stat/Stat.css
CHANGED
|
@@ -65,14 +65,56 @@
|
|
|
65
65
|
line-height: 1;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/* The trend tokens are theme-split for contrast: deep status inks on
|
|
69
|
+
light surfaces, the mint/coral accents on dark ones. */
|
|
68
70
|
.ds-stat__delta--up {
|
|
69
|
-
color: var(--color-
|
|
71
|
+
color: var(--color-trend-up);
|
|
70
72
|
}
|
|
71
73
|
|
|
72
74
|
.ds-stat__delta--down {
|
|
73
|
-
color: var(--color-
|
|
75
|
+
color: var(--color-trend-down);
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
.ds-stat__delta--neutral {
|
|
77
79
|
color: var(--color-text-tertiary);
|
|
78
80
|
}
|
|
81
|
+
|
|
82
|
+
/* ============================================
|
|
83
|
+
INLINE DELTA — delta to the right of the
|
|
84
|
+
value, bottom-aligned to its baseline
|
|
85
|
+
============================================ */
|
|
86
|
+
|
|
87
|
+
.ds-stat--delta-inline {
|
|
88
|
+
display: grid;
|
|
89
|
+
grid-template-columns: auto 1fr;
|
|
90
|
+
grid-template-areas:
|
|
91
|
+
'value delta'
|
|
92
|
+
'label label';
|
|
93
|
+
column-gap: var(--gap-sm);
|
|
94
|
+
row-gap: var(--gap-xxs);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.ds-stat--delta-inline .ds-stat__value {
|
|
98
|
+
grid-area: value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.ds-stat--delta-inline .ds-stat__label {
|
|
102
|
+
grid-area: label;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.ds-stat--delta-inline .ds-stat__delta {
|
|
106
|
+
grid-area: delta;
|
|
107
|
+
align-self: end;
|
|
108
|
+
justify-self: start;
|
|
109
|
+
/* Optical baseline: compensates the display value's half-leading. */
|
|
110
|
+
margin-bottom: var(--gap-xs);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
114
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
115
|
+
.material-symbols-rounded itself (a common global default) would
|
|
116
|
+
otherwise override inheritance and detach the icon from the state
|
|
117
|
+
colours this component sets on its parents. */
|
|
118
|
+
.ds-stat .material-symbols-rounded {
|
|
119
|
+
color: inherit;
|
|
120
|
+
}
|
|
@@ -7,6 +7,8 @@ export interface StatProps {
|
|
|
7
7
|
delta?: string;
|
|
8
8
|
/** Direction of the delta — colours it and adds an arrow */
|
|
9
9
|
trend?: 'up' | 'down' | 'neutral';
|
|
10
|
+
/** Where the delta sits: stacked below the label, or inline to the right of the value, bottom-aligned */
|
|
11
|
+
deltaPlacement?: 'stacked' | 'inline';
|
|
10
12
|
/** Stat size */
|
|
11
13
|
size?: 'default' | 'large';
|
|
12
14
|
/** Additional CSS classes */
|
|
@@ -16,4 +18,4 @@ export interface StatProps {
|
|
|
16
18
|
* Stat component — a single headline metric with a label and an
|
|
17
19
|
* optional trend delta. Compose several in a row for a metrics band.
|
|
18
20
|
*/
|
|
19
|
-
export declare const Stat: ({ value, label, delta, trend, size, className, }: StatProps) => import("react").JSX.Element;
|
|
21
|
+
export declare const Stat: ({ value, label, delta, trend, deltaPlacement, size, className, }: StatProps) => import("react").JSX.Element;
|
package/components/Stat/Stat.js
CHANGED
|
@@ -11,11 +11,17 @@ const Stat = ({
|
|
|
11
11
|
label,
|
|
12
12
|
delta,
|
|
13
13
|
trend = "neutral",
|
|
14
|
+
deltaPlacement = "stacked",
|
|
14
15
|
size = "default",
|
|
15
16
|
className = ""
|
|
16
17
|
}) => {
|
|
17
18
|
const baseClass = "ds-stat";
|
|
18
|
-
const classes = [
|
|
19
|
+
const classes = [
|
|
20
|
+
baseClass,
|
|
21
|
+
`${baseClass}--${size}`,
|
|
22
|
+
deltaPlacement === "inline" ? `${baseClass}--delta-inline` : "",
|
|
23
|
+
className
|
|
24
|
+
].filter(Boolean).join(" ");
|
|
19
25
|
return /* @__PURE__ */ jsxs("div", { className: classes, children: [
|
|
20
26
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__value`, children: value }),
|
|
21
27
|
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: label }),
|
|
@@ -205,3 +205,12 @@ button.ds-stepper__content:hover .ds-stepper__label {
|
|
|
205
205
|
height: auto;
|
|
206
206
|
transform: translateX(-50%);
|
|
207
207
|
}
|
|
208
|
+
|
|
209
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
210
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
211
|
+
.material-symbols-rounded itself (a common global default) would
|
|
212
|
+
otherwise override inheritance and detach the icon from the state
|
|
213
|
+
colours this component sets on its parents. */
|
|
214
|
+
.ds-stepper .material-symbols-rounded {
|
|
215
|
+
color: inherit;
|
|
216
|
+
}
|
|
@@ -158,3 +158,12 @@
|
|
|
158
158
|
line-height: var(--font-paragraph-sm-line-height);
|
|
159
159
|
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
160
160
|
}
|
|
161
|
+
|
|
162
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
163
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
164
|
+
.material-symbols-rounded itself (a common global default) would
|
|
165
|
+
otherwise override inheritance and detach the icon from the state
|
|
166
|
+
colours this component sets on its parents. */
|
|
167
|
+
.ds-taginput .material-symbols-rounded {
|
|
168
|
+
color: inherit;
|
|
169
|
+
}
|
|
@@ -158,6 +158,7 @@ const TimePicker = React.forwardRef(
|
|
|
158
158
|
focusedEl?.scrollIntoView({ block: "nearest" });
|
|
159
159
|
}
|
|
160
160
|
}, [focusedIndex, isOpen]);
|
|
161
|
+
const activeOptionId = isOpen && focusedIndex >= 0 && timeOptions[focusedIndex] ? `${inputId}-option-${focusedIndex}` : void 0;
|
|
161
162
|
return /* @__PURE__ */ jsxs(
|
|
162
163
|
Field,
|
|
163
164
|
{
|
|
@@ -181,7 +182,8 @@ const TimePicker = React.forwardRef(
|
|
|
181
182
|
className: `${baseClass}__trigger`,
|
|
182
183
|
"aria-expanded": isOpen,
|
|
183
184
|
"aria-haspopup": "listbox",
|
|
184
|
-
"aria-controls": `${inputId}-listbox
|
|
185
|
+
"aria-controls": isOpen ? `${inputId}-listbox` : void 0,
|
|
186
|
+
"aria-activedescendant": activeOptionId,
|
|
185
187
|
"aria-describedby": helperText ? `${inputId}-helper` : rest["aria-describedby"],
|
|
186
188
|
"aria-invalid": error || void 0,
|
|
187
189
|
disabled,
|
|
@@ -211,6 +213,7 @@ const TimePicker = React.forwardRef(
|
|
|
211
213
|
children: timeOptions.map((option, index) => /* @__PURE__ */ jsxs(
|
|
212
214
|
"li",
|
|
213
215
|
{
|
|
216
|
+
id: `${inputId}-option-${index}`,
|
|
214
217
|
className: [
|
|
215
218
|
`${baseClass}__option`,
|
|
216
219
|
option.value === selectedValue ? `${baseClass}__option--selected` : "",
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
/* ============================================
|
|
2
2
|
TOAST CONTAINER
|
|
3
3
|
Fixed position stack for notifications
|
|
4
|
+
|
|
5
|
+
Consumer hooks (custom properties with fallbacks, so the defaults hold
|
|
6
|
+
until a consumer sets them): a page that keeps its own fixed chrome in a
|
|
7
|
+
corner (a chat launcher, a cookie bar, a docked panel) sets the matching
|
|
8
|
+
inset so toasts stack clear of it rather than on top of it, and raises
|
|
9
|
+
--ds-toast-z above its own overlay layers. Toasts are transient feedback
|
|
10
|
+
and must be seen; a launcher can be covered for five seconds.
|
|
11
|
+
--ds-toast-z stacking order (default 200, the library's top)
|
|
12
|
+
--ds-toast-inset-top gap from the top edge for top-* placements
|
|
13
|
+
--ds-toast-inset-bottom gap from the bottom edge for bottom-* placements
|
|
14
|
+
--ds-toast-inset-left gap from the left edge for *-left placements
|
|
15
|
+
--ds-toast-inset-right gap from the right edge for *-right placements
|
|
4
16
|
============================================ */
|
|
5
17
|
|
|
6
18
|
.ds-toast-container {
|
|
7
19
|
position: fixed;
|
|
8
|
-
z-index: 200;
|
|
20
|
+
z-index: var(--ds-toast-z, 200);
|
|
9
21
|
display: flex;
|
|
10
22
|
flex-direction: column;
|
|
11
23
|
gap: var(--gap-sm); /* 8px */
|
|
@@ -14,38 +26,38 @@
|
|
|
14
26
|
}
|
|
15
27
|
|
|
16
28
|
.ds-toast-container--top-right {
|
|
17
|
-
top: 0;
|
|
18
|
-
right: 0;
|
|
29
|
+
top: var(--ds-toast-inset-top, 0);
|
|
30
|
+
right: var(--ds-toast-inset-right, 0);
|
|
19
31
|
align-items: flex-end;
|
|
20
32
|
}
|
|
21
33
|
|
|
22
34
|
.ds-toast-container--top-left {
|
|
23
|
-
top: 0;
|
|
24
|
-
left: 0;
|
|
35
|
+
top: var(--ds-toast-inset-top, 0);
|
|
36
|
+
left: var(--ds-toast-inset-left, 0);
|
|
25
37
|
align-items: flex-start;
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
.ds-toast-container--bottom-right {
|
|
29
|
-
bottom: 0;
|
|
30
|
-
right: 0;
|
|
41
|
+
bottom: var(--ds-toast-inset-bottom, 0);
|
|
42
|
+
right: var(--ds-toast-inset-right, 0);
|
|
31
43
|
align-items: flex-end;
|
|
32
44
|
}
|
|
33
45
|
|
|
34
46
|
.ds-toast-container--bottom-left {
|
|
35
|
-
bottom: 0;
|
|
36
|
-
left: 0;
|
|
47
|
+
bottom: var(--ds-toast-inset-bottom, 0);
|
|
48
|
+
left: var(--ds-toast-inset-left, 0);
|
|
37
49
|
align-items: flex-start;
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
.ds-toast-container--top-center {
|
|
41
|
-
top: 0;
|
|
53
|
+
top: var(--ds-toast-inset-top, 0);
|
|
42
54
|
left: 50%;
|
|
43
55
|
transform: translateX(-50%);
|
|
44
56
|
align-items: center;
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
.ds-toast-container--bottom-center {
|
|
48
|
-
bottom: 0;
|
|
60
|
+
bottom: var(--ds-toast-inset-bottom, 0);
|
|
49
61
|
left: 50%;
|
|
50
62
|
transform: translateX(-50%);
|
|
51
63
|
align-items: center;
|
|
@@ -340,3 +352,12 @@
|
|
|
340
352
|
transform: scaleX(0);
|
|
341
353
|
}
|
|
342
354
|
}
|
|
355
|
+
|
|
356
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
357
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
358
|
+
.material-symbols-rounded itself (a common global default) would
|
|
359
|
+
otherwise override inheritance and detach the icon from the state
|
|
360
|
+
colours this component sets on its parents. */
|
|
361
|
+
.ds-toast .material-symbols-rounded {
|
|
362
|
+
color: inherit;
|
|
363
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useSyncExternalStore, useCallback, useContext, createContext, useRef, useEffect } from "react";
|
|
4
|
+
import { MOTION_AUTO_DISMISS_MS } from "../../tokens/motion.js";
|
|
4
5
|
import ReactDOM from "react-dom";
|
|
5
6
|
import "./Toast.css";
|
|
6
7
|
import "../../fonts/material-symbols.css";
|
|
@@ -62,8 +63,7 @@ const ToastItem = ({
|
|
|
62
63
|
"div",
|
|
63
64
|
{
|
|
64
65
|
className: classes,
|
|
65
|
-
role: "
|
|
66
|
-
"aria-live": variant === "error" || variant === "warning" ? "assertive" : "polite",
|
|
66
|
+
role: variant === "error" || variant === "warning" ? "alert" : void 0,
|
|
67
67
|
onMouseEnter: () => setPauseTimer(true),
|
|
68
68
|
onMouseLeave: () => setPauseTimer(false),
|
|
69
69
|
onFocus: () => setPauseTimer(true),
|
|
@@ -119,7 +119,7 @@ const ToastProvider = ({
|
|
|
119
119
|
...data,
|
|
120
120
|
id,
|
|
121
121
|
variant: data.variant || "info",
|
|
122
|
-
duration: data.duration ??
|
|
122
|
+
duration: data.duration ?? MOTION_AUTO_DISMISS_MS,
|
|
123
123
|
dismissible: data.dismissible ?? true
|
|
124
124
|
};
|
|
125
125
|
setToasts((prev) => {
|
|
@@ -150,6 +150,7 @@ const ToastProvider = ({
|
|
|
150
150
|
className: containerClasses,
|
|
151
151
|
role: "region",
|
|
152
152
|
"aria-label": "Notifications",
|
|
153
|
+
"aria-live": "polite",
|
|
153
154
|
children: toasts.map((t) => /* @__PURE__ */ jsx(
|
|
154
155
|
ToastItem,
|
|
155
156
|
{
|
|
@@ -159,7 +160,7 @@ const ToastProvider = ({
|
|
|
159
160
|
variant: t.variant || "info",
|
|
160
161
|
dismissible: t.dismissible ?? true,
|
|
161
162
|
icon: t.icon,
|
|
162
|
-
duration: t.duration ??
|
|
163
|
+
duration: t.duration ?? MOTION_AUTO_DISMISS_MS,
|
|
163
164
|
onDismiss: dismiss
|
|
164
165
|
},
|
|
165
166
|
t.id
|
|
@@ -82,3 +82,12 @@
|
|
|
82
82
|
opacity: 0.4;
|
|
83
83
|
pointer-events: none;
|
|
84
84
|
}
|
|
85
|
+
|
|
86
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
87
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
88
|
+
.material-symbols-rounded itself (a common global default) would
|
|
89
|
+
otherwise override inheritance and detach the icon from the state
|
|
90
|
+
colours this component sets on its parents. */
|
|
91
|
+
.ds-toggle-group .material-symbols-rounded {
|
|
92
|
+
color: inherit;
|
|
93
|
+
}
|
|
@@ -20,7 +20,10 @@
|
|
|
20
20
|
width: 100%;
|
|
21
21
|
background-color: var(--color-bg-container-primary);
|
|
22
22
|
border: var(--border-xs) solid var(--color-bg-container-border);
|
|
23
|
-
|
|
23
|
+
/* The chat furniture shares one 24px shell with MessageCard and the
|
|
24
|
+
bubbles; a closed row rounds to a capsule the way a one-line bubble
|
|
25
|
+
does, echoing the system's pill buttons. */
|
|
26
|
+
border-radius: var(--radius-xl);
|
|
24
27
|
overflow: hidden;
|
|
25
28
|
}
|
|
26
29
|
|
|
@@ -33,7 +36,8 @@
|
|
|
33
36
|
align-items: center;
|
|
34
37
|
gap: var(--gap-sm);
|
|
35
38
|
width: 100%;
|
|
36
|
-
|
|
39
|
+
/* 20px sides — the card family's shared content inset. */
|
|
40
|
+
padding: var(--padding-sm) var(--padding-lg);
|
|
37
41
|
background: none;
|
|
38
42
|
border: none;
|
|
39
43
|
text-align: left;
|
|
@@ -181,7 +185,7 @@
|
|
|
181
185
|
}
|
|
182
186
|
|
|
183
187
|
.ds-tool-call--open .ds-tool-call__content {
|
|
184
|
-
padding: var(--padding-md);
|
|
188
|
+
padding: var(--padding-md) var(--padding-lg);
|
|
185
189
|
border-top: var(--border-xs) solid var(--color-divider);
|
|
186
190
|
}
|
|
187
191
|
|
|
@@ -202,8 +206,16 @@
|
|
|
202
206
|
.ds-tool-call__actions {
|
|
203
207
|
display: flex;
|
|
204
208
|
align-items: center;
|
|
205
|
-
justify-content: flex-
|
|
209
|
+
justify-content: flex-start;
|
|
206
210
|
gap: var(--gap-sm);
|
|
207
|
-
padding: var(--padding-sm-
|
|
208
|
-
|
|
211
|
+
padding: var(--padding-sm) var(--padding-lg) var(--padding-md);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Icons take the colour of the text around them. Explicit, not just
|
|
215
|
+
inherited by default: a consumer stylesheet that sets a colour on
|
|
216
|
+
.material-symbols-rounded itself (a common global default) would
|
|
217
|
+
otherwise override inheritance and detach the icon from the state
|
|
218
|
+
colours this component sets on its parents. */
|
|
219
|
+
.ds-tool-call .material-symbols-rounded {
|
|
220
|
+
color: inherit;
|
|
209
221
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useRef, useId, isValidElement, cloneElement } from "react";
|
|
3
|
+
import { useState, useRef, useId, useEffect, isValidElement, cloneElement } from "react";
|
|
4
4
|
import "./Tooltip.css";
|
|
5
|
+
import { MOTION_HOVER_SHOW_DELAY_MS, MOTION_HOVER_HIDE_DELAY_MS } from "../../tokens/motion.js";
|
|
5
6
|
const Tooltip = ({
|
|
6
7
|
children,
|
|
7
8
|
content,
|
|
8
9
|
position = "top",
|
|
9
|
-
showDelay =
|
|
10
|
-
hideDelay =
|
|
10
|
+
showDelay = MOTION_HOVER_SHOW_DELAY_MS,
|
|
11
|
+
hideDelay = MOTION_HOVER_HIDE_DELAY_MS,
|
|
11
12
|
className = ""
|
|
12
13
|
}) => {
|
|
13
14
|
const [visible, setVisible] = useState(false);
|
|
@@ -23,6 +24,18 @@ const Tooltip = ({
|
|
|
23
24
|
clearTimeout(showTimeoutRef.current);
|
|
24
25
|
hideTimeoutRef.current = setTimeout(() => setVisible(false), hideDelay);
|
|
25
26
|
};
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (!visible) return;
|
|
29
|
+
const onKeyDown = (e) => {
|
|
30
|
+
if (e.key === "Escape") {
|
|
31
|
+
clearTimeout(showTimeoutRef.current);
|
|
32
|
+
clearTimeout(hideTimeoutRef.current);
|
|
33
|
+
setVisible(false);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
document.addEventListener("keydown", onKeyDown);
|
|
37
|
+
return () => document.removeEventListener("keydown", onKeyDown);
|
|
38
|
+
}, [visible]);
|
|
26
39
|
const trigger = isValidElement(children) ? cloneElement(children, {
|
|
27
40
|
"aria-describedby": tooltipId
|
|
28
41
|
}) : children;
|
|
@@ -42,19 +55,10 @@ const Tooltip = ({
|
|
|
42
55
|
onBlur: hide,
|
|
43
56
|
children: [
|
|
44
57
|
trigger,
|
|
45
|
-
/* @__PURE__ */ jsxs(
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
role: "tooltip",
|
|
50
|
-
id: tooltipId,
|
|
51
|
-
"aria-hidden": !visible,
|
|
52
|
-
children: [
|
|
53
|
-
content,
|
|
54
|
-
/* @__PURE__ */ jsx("span", { className: `${baseClass}__arrow` })
|
|
55
|
-
]
|
|
56
|
-
}
|
|
57
|
-
)
|
|
58
|
+
/* @__PURE__ */ jsxs("span", { className: panelClasses, role: "tooltip", id: tooltipId, children: [
|
|
59
|
+
content,
|
|
60
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__arrow` })
|
|
61
|
+
] })
|
|
58
62
|
]
|
|
59
63
|
}
|
|
60
64
|
);
|