@robr0/design-system 0.14.0 → 0.15.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 +8 -5
- package/charts.d.ts +1 -0
- package/charts.js +2 -0
- package/components/AnchorNav/AnchorNav.css +74 -0
- package/components/AnchorNav/AnchorNav.d.ts +7 -0
- package/components/AnchorNav/AnchorNav.js +74 -21
- package/components/Button/Button.css +51 -0
- package/components/Button/Button.d.ts +2 -2
- package/components/Chart/Chart.css +4 -1
- package/components/CircularButton/CircularButton.css +46 -0
- package/components/CircularButton/CircularButton.d.ts +13 -2
- package/components/CircularButton/CircularButton.js +19 -16
- package/components/CommandPalette/CommandPalette.css +26 -1
- package/components/CommandPalette/CommandPalette.js +11 -7
- package/components/Composer/Composer.css +18 -0
- package/components/Composer/Composer.d.ts +4 -2
- package/components/Composer/Composer.js +1 -0
- package/components/ContributionGraph/ContributionGraph.css +21 -0
- package/components/ContributionGraph/ContributionGraph.js +18 -10
- package/components/Figure/Figure.css +14 -4
- package/components/Figure/Figure.js +11 -20
- package/components/FunnelChart/FunnelChart.css +11 -36
- package/components/FunnelChart/FunnelChart.d.ts +19 -16
- package/components/FunnelChart/FunnelChart.js +67 -39
- package/components/Gauge/Gauge.css +11 -1
- package/components/Meter/Meter.css +10 -1
- package/components/ProgressBar/ProgressBar.css +1 -1
- package/components/SegmentedControl/SegmentedControl.css +23 -0
- package/components/SegmentedControl/SegmentedControl.d.ts +3 -1
- package/components/SegmentedControl/SegmentedControl.js +3 -1
- package/components/Slider/Slider.css +1 -1
- package/components/Slider/Slider.js +1 -1
- package/components/SourceTrail/SourceTrail.css +209 -0
- package/components/SourceTrail/SourceTrail.d.ts +49 -0
- package/components/SourceTrail/SourceTrail.js +108 -0
- package/components/Sparkline/Sparkline.css +26 -2
- package/components/Sparkline/Sparkline.js +2 -1
- package/components/Spinner/Spinner.css +1 -1
- package/components/SplitButton/SplitButton.d.ts +1 -1
- package/components/SplitButton/SplitButton.js +1 -0
- package/components/ToggleGroup/ToggleGroup.css +17 -0
- package/components/ToggleGroup/ToggleGroup.d.ts +2 -0
- package/components/ToggleGroup/ToggleGroup.js +2 -0
- package/components/ToolCall/ToolCall.css +7 -2
- package/components/Tooltip/Tooltip.css +24 -7
- package/components/Tooltip/Tooltip.d.ts +2 -1
- package/components/UsageCard/UsageCard.css +30 -0
- package/components/UsageCard/UsageCard.d.ts +48 -0
- package/components/UsageCard/UsageCard.js +54 -0
- package/components/registry.d.ts +8 -2
- package/components/registry.json +41 -14
- package/components/registry.json.d.ts +41 -14
- package/components/registry.json.js +1 -1
- package/index.d.ts +2 -1
- package/index.js +4 -2
- package/package.json +1 -1
- package/tokens/registry.json +4 -0
- package/tokens/registry.json.d.ts +4 -0
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-dark.css +11 -2
- package/tokens/tokens-light.css +25 -11
- package/tokens/tokens-primitives.css +3 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
SOURCE TRAIL COMPONENT
|
|
3
|
+
The research trail under an agent's answer:
|
|
4
|
+
a count header with a disclosure over the
|
|
5
|
+
sources it opened, in order.
|
|
6
|
+
|
|
7
|
+
Shares the chat furniture's 24px shell with
|
|
8
|
+
ToolCall — a collapsed trail reads as one
|
|
9
|
+
more row in the run, not a different species.
|
|
10
|
+
============================================ */
|
|
11
|
+
|
|
12
|
+
.ds-source-trail {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
width: 100%;
|
|
16
|
+
background-color: var(--color-bg-container-primary);
|
|
17
|
+
border: var(--border-xs) solid var(--color-bg-container-border);
|
|
18
|
+
border-radius: var(--radius-xl);
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* ============================================
|
|
23
|
+
HEADER
|
|
24
|
+
============================================ */
|
|
25
|
+
|
|
26
|
+
.ds-source-trail__header {
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
gap: var(--gap-sm);
|
|
30
|
+
width: 100%;
|
|
31
|
+
padding: var(--padding-sm) var(--padding-lg);
|
|
32
|
+
background: none;
|
|
33
|
+
border: none;
|
|
34
|
+
/* Buttons default to the UA's buttontext, not the inherited colour, so
|
|
35
|
+
anything in the header that inherits would read black in both themes. */
|
|
36
|
+
color: var(--color-text-primary);
|
|
37
|
+
text-align: left;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.ds-source-trail__header:hover {
|
|
43
|
+
background-color: var(--color-bg-container-secondary);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.ds-source-trail__header:focus-visible {
|
|
47
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
48
|
+
outline-offset: -2px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.ds-source-trail__indicator {
|
|
52
|
+
display: inline-flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
flex: none;
|
|
56
|
+
color: var(--color-text-secondary);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ds-source-trail__indicator .material-symbols-rounded {
|
|
60
|
+
--icon-size: var(--icon-size-sm);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-source-trail__heading {
|
|
64
|
+
flex: 1 1 auto;
|
|
65
|
+
min-width: 0;
|
|
66
|
+
overflow: hidden;
|
|
67
|
+
text-overflow: ellipsis;
|
|
68
|
+
white-space: nowrap;
|
|
69
|
+
color: var(--color-text-primary);
|
|
70
|
+
font-family: var(--font-paragraph-sm-em-family);
|
|
71
|
+
font-size: var(--font-paragraph-sm-em-size);
|
|
72
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
73
|
+
line-height: var(--font-paragraph-sm-em-line-height);
|
|
74
|
+
letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.ds-source-trail__chevron {
|
|
78
|
+
--icon-size: var(--icon-size-sm);
|
|
79
|
+
|
|
80
|
+
flex: none;
|
|
81
|
+
color: var(--color-icon-secondary);
|
|
82
|
+
transition: transform var(--motion-duration-slow) var(--motion-ease-standard);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ds-source-trail--open .ds-source-trail__chevron {
|
|
86
|
+
transform: rotate(180deg);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ============================================
|
|
90
|
+
PANEL
|
|
91
|
+
============================================ */
|
|
92
|
+
|
|
93
|
+
.ds-source-trail__panel {
|
|
94
|
+
display: grid;
|
|
95
|
+
grid-template-rows: 0fr;
|
|
96
|
+
visibility: hidden;
|
|
97
|
+
transition:
|
|
98
|
+
grid-template-rows var(--motion-duration-slow) var(--motion-ease-standard),
|
|
99
|
+
visibility var(--motion-duration-slow) var(--motion-ease-standard);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.ds-source-trail--open .ds-source-trail__panel {
|
|
103
|
+
grid-template-rows: 1fr;
|
|
104
|
+
visibility: visible;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ds-source-trail__list {
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
min-height: 0;
|
|
110
|
+
margin: 0;
|
|
111
|
+
padding: 0;
|
|
112
|
+
list-style: none;
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.ds-source-trail--open .ds-source-trail__list {
|
|
118
|
+
padding: var(--padding-sm) var(--padding-lg) var(--padding-md);
|
|
119
|
+
border-top: var(--border-xs) solid var(--color-divider);
|
|
120
|
+
gap: var(--gap-sm);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ============================================
|
|
124
|
+
ROWS
|
|
125
|
+
============================================ */
|
|
126
|
+
|
|
127
|
+
.ds-source-trail__row {
|
|
128
|
+
display: flex;
|
|
129
|
+
align-items: center;
|
|
130
|
+
gap: var(--gap-sm);
|
|
131
|
+
min-width: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Streaming: an appended row eases in. Pure CSS, so the global
|
|
135
|
+
reduced-motion guard collapses the duration tokens. */
|
|
136
|
+
.ds-source-trail--streaming .ds-source-trail__row {
|
|
137
|
+
animation: ds-source-trail-enter var(--motion-duration-slow) var(--motion-ease-standard);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@keyframes ds-source-trail-enter {
|
|
141
|
+
from {
|
|
142
|
+
opacity: 0;
|
|
143
|
+
transform: translateY(4px);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.ds-source-trail__row-indicator {
|
|
148
|
+
display: inline-flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
flex: none;
|
|
152
|
+
color: var(--color-text-secondary);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.ds-source-trail__row-indicator .material-symbols-rounded {
|
|
156
|
+
--icon-size: var(--icon-size-sm);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.ds-source-trail__row--pending .ds-source-trail__row-indicator {
|
|
160
|
+
color: var(--color-text-tertiary);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.ds-source-trail__row--active .ds-source-trail__row-indicator {
|
|
164
|
+
color: var(--color-status-info-text);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.ds-source-trail__row--done .ds-source-trail__row-indicator {
|
|
168
|
+
color: var(--color-status-positive-text);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* A pending source has not been opened yet, so its chip sits quieter */
|
|
172
|
+
.ds-source-trail__row--pending {
|
|
173
|
+
opacity: 0.6;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.ds-source-trail__detail {
|
|
177
|
+
flex: 1 1 auto;
|
|
178
|
+
min-width: 0;
|
|
179
|
+
overflow: hidden;
|
|
180
|
+
text-overflow: ellipsis;
|
|
181
|
+
white-space: nowrap;
|
|
182
|
+
color: var(--color-text-tertiary);
|
|
183
|
+
font-family: var(--font-paragraph-sm-family);
|
|
184
|
+
font-size: var(--font-paragraph-sm-size);
|
|
185
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
186
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
187
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* Screen-reader-only status text, matching AgentPlan's row announcement */
|
|
191
|
+
.ds-source-trail__sr {
|
|
192
|
+
position: absolute;
|
|
193
|
+
width: 1px;
|
|
194
|
+
height: 1px;
|
|
195
|
+
padding: 0;
|
|
196
|
+
margin: -1px;
|
|
197
|
+
overflow: hidden;
|
|
198
|
+
clip: rect(0, 0, 0, 0);
|
|
199
|
+
white-space: nowrap;
|
|
200
|
+
border: 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/* Icons follow the state colour set on their parents, even against a
|
|
204
|
+
consumer stylesheet that colours .material-symbols-rounded globally.
|
|
205
|
+
The chevron is excluded — it carries its own colour rule, which this
|
|
206
|
+
higher-specificity rule would otherwise silently override. */
|
|
207
|
+
.ds-source-trail .material-symbols-rounded:not(.ds-source-trail__chevron) {
|
|
208
|
+
color: inherit;
|
|
209
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export type SourceTrailStatus = 'pending' | 'active' | 'done';
|
|
3
|
+
/** One source the agent opened while answering. */
|
|
4
|
+
export interface SourceTrailItem {
|
|
5
|
+
/** The source name, passed through to the row's SourceChip. */
|
|
6
|
+
title: string;
|
|
7
|
+
/** Optional link to the source — the chip renders as an anchor. */
|
|
8
|
+
href?: string;
|
|
9
|
+
/** Leading icon for the chip — a Material Symbol name (string) or custom element (ReactNode). */
|
|
10
|
+
icon?: string | React.ReactNode;
|
|
11
|
+
/** Where the visit has got to. Drives the row's indicator; defaults to done. */
|
|
12
|
+
status?: SourceTrailStatus;
|
|
13
|
+
/** Supporting line, e.g. what the source contributed to the answer. */
|
|
14
|
+
detail?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Props owned by SourceTrail itself — everything else falls through to the root element. */
|
|
17
|
+
type SourceTrailOwnProps = {
|
|
18
|
+
/** The sources, in the order the agent opened them. */
|
|
19
|
+
items: SourceTrailItem[];
|
|
20
|
+
/**
|
|
21
|
+
* Header text. Left unset, it is computed from the items —
|
|
22
|
+
* "Reading 3 sources" while any is still pending or active,
|
|
23
|
+
* "Read 3 sources" once every visit has settled.
|
|
24
|
+
*/
|
|
25
|
+
title?: string;
|
|
26
|
+
/** Still researching: newly appended rows animate in. */
|
|
27
|
+
streaming?: boolean;
|
|
28
|
+
/** Open state for controlled use. Pair with `onOpenChange`. */
|
|
29
|
+
open?: boolean;
|
|
30
|
+
/** Open state for uncontrolled use. */
|
|
31
|
+
defaultOpen?: boolean;
|
|
32
|
+
/** Fires whenever the panel opens or closes. */
|
|
33
|
+
onOpenChange?: (open: boolean) => void;
|
|
34
|
+
/** Additional CSS classes */
|
|
35
|
+
className?: string;
|
|
36
|
+
};
|
|
37
|
+
export interface SourceTrailProps extends SourceTrailOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof SourceTrailOwnProps> {
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* SourceTrail is the research trail under an agent's answer: the sources it
|
|
41
|
+
* opened, in order, each with a status and an optional note on what it
|
|
42
|
+
* contributed. SourceChip is the atom; this is the list — a count header
|
|
43
|
+
* with a disclosure, so a long trail collapses to one line.
|
|
44
|
+
*
|
|
45
|
+
* While `streaming`, appended rows animate in (pure CSS, so the global
|
|
46
|
+
* reduced-motion guard covers it) and the active row carries a spinner.
|
|
47
|
+
*/
|
|
48
|
+
export declare const SourceTrail: React.ForwardRefExoticComponent<SourceTrailProps & React.RefAttributes<HTMLDivElement>>;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useId, useState, useCallback } from "react";
|
|
4
|
+
import { SourceChip } from "../SourceChip/SourceChip.js";
|
|
5
|
+
import { Spinner } from "../Spinner/Spinner.js";
|
|
6
|
+
import "./SourceTrail.css";
|
|
7
|
+
import "../../fonts/material-symbols.css";
|
|
8
|
+
const STATUS_ICONS = {
|
|
9
|
+
pending: "circle",
|
|
10
|
+
done: "check_circle"
|
|
11
|
+
};
|
|
12
|
+
const STATUS_TEXT = {
|
|
13
|
+
pending: "Not opened yet",
|
|
14
|
+
active: "Reading now",
|
|
15
|
+
done: "Read"
|
|
16
|
+
};
|
|
17
|
+
const SourceTrail = React.forwardRef(
|
|
18
|
+
({
|
|
19
|
+
items,
|
|
20
|
+
title,
|
|
21
|
+
streaming = false,
|
|
22
|
+
open,
|
|
23
|
+
defaultOpen = true,
|
|
24
|
+
onOpenChange,
|
|
25
|
+
className = "",
|
|
26
|
+
...rest
|
|
27
|
+
}, ref) => {
|
|
28
|
+
const baseClass = "ds-source-trail";
|
|
29
|
+
const id = useId();
|
|
30
|
+
const panelId = `${id}-panel`;
|
|
31
|
+
const triggerId = `${id}-trigger`;
|
|
32
|
+
const isControlled = open !== void 0;
|
|
33
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
34
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
35
|
+
const toggle = useCallback(() => {
|
|
36
|
+
const next = !isOpen;
|
|
37
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
38
|
+
onOpenChange?.(next);
|
|
39
|
+
}, [isOpen, isControlled, onOpenChange]);
|
|
40
|
+
const unsettled = items.some(
|
|
41
|
+
(item) => item.status === "pending" || item.status === "active"
|
|
42
|
+
);
|
|
43
|
+
const count = items.length;
|
|
44
|
+
const heading = title ?? (unsettled || streaming ? `Reading ${count} source${count === 1 ? "" : "s"}` : `Read ${count} source${count === 1 ? "" : "s"}`);
|
|
45
|
+
const classes = [
|
|
46
|
+
baseClass,
|
|
47
|
+
isOpen ? `${baseClass}--open` : "",
|
|
48
|
+
streaming ? `${baseClass}--streaming` : "",
|
|
49
|
+
className
|
|
50
|
+
].filter(Boolean).join(" ");
|
|
51
|
+
return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, children: [
|
|
52
|
+
/* @__PURE__ */ jsxs(
|
|
53
|
+
"button",
|
|
54
|
+
{
|
|
55
|
+
type: "button",
|
|
56
|
+
id: triggerId,
|
|
57
|
+
className: `${baseClass}__header`,
|
|
58
|
+
"aria-expanded": isOpen,
|
|
59
|
+
"aria-controls": panelId,
|
|
60
|
+
onClick: toggle,
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__indicator`, "aria-hidden": "true", children: unsettled || streaming ? /* @__PURE__ */ jsx(Spinner, { size: "sm", variant: "inherit" }) : /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", children: "travel_explore" }) }),
|
|
63
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__heading`, children: heading }),
|
|
64
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__chevron material-symbols-rounded`, "aria-hidden": "true", children: "expand_more" })
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
),
|
|
68
|
+
/* @__PURE__ */ jsx(
|
|
69
|
+
"div",
|
|
70
|
+
{
|
|
71
|
+
className: `${baseClass}__panel`,
|
|
72
|
+
id: panelId,
|
|
73
|
+
role: "region",
|
|
74
|
+
"aria-labelledby": triggerId,
|
|
75
|
+
children: /* @__PURE__ */ jsx("ol", { className: `${baseClass}__list`, children: items.map((item, index) => {
|
|
76
|
+
const status = item.status ?? "done";
|
|
77
|
+
return /* @__PURE__ */ jsxs(
|
|
78
|
+
"li",
|
|
79
|
+
{
|
|
80
|
+
className: `${baseClass}__row ${baseClass}__row--${status}`,
|
|
81
|
+
children: [
|
|
82
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__row-indicator`, "aria-hidden": "true", children: status === "active" ? /* @__PURE__ */ jsx(Spinner, { size: "sm", variant: "inherit" }) : /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", children: STATUS_ICONS[status] }) }),
|
|
83
|
+
/* @__PURE__ */ jsx(
|
|
84
|
+
SourceChip,
|
|
85
|
+
{
|
|
86
|
+
title: item.title,
|
|
87
|
+
href: item.href,
|
|
88
|
+
icon: item.icon,
|
|
89
|
+
target: item.href ? "_blank" : void 0,
|
|
90
|
+
rel: item.href ? "noopener noreferrer" : void 0
|
|
91
|
+
}
|
|
92
|
+
),
|
|
93
|
+
item.detail && /* @__PURE__ */ jsx("span", { className: `${baseClass}__detail`, children: item.detail }),
|
|
94
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__sr`, children: STATUS_TEXT[status] })
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
`${item.title}-${index}`
|
|
98
|
+
);
|
|
99
|
+
}) })
|
|
100
|
+
}
|
|
101
|
+
)
|
|
102
|
+
] });
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
SourceTrail.displayName = "SourceTrail";
|
|
106
|
+
export {
|
|
107
|
+
SourceTrail
|
|
108
|
+
};
|
|
@@ -17,20 +17,44 @@
|
|
|
17
17
|
|
|
18
18
|
/* Parts */
|
|
19
19
|
|
|
20
|
+
/* The line draws itself on mount, the way the recharts lines do: the path is
|
|
21
|
+
normalised to 100 dash units (pathLength on the SVG side), and the offset
|
|
22
|
+
retreats from fully hidden to zero. The fill and end dot fade in behind
|
|
23
|
+
and after it. All durations are tokens, so reduced motion collapses the
|
|
24
|
+
whole sequence to the finished state for free. */
|
|
25
|
+
|
|
20
26
|
.ds-sparkline__line {
|
|
21
27
|
fill: none;
|
|
22
28
|
stroke: currentColor;
|
|
23
29
|
stroke-linecap: round;
|
|
24
30
|
stroke-linejoin: round;
|
|
31
|
+
stroke-dasharray: 100;
|
|
32
|
+
animation: ds-sparkline-draw var(--motion-duration-slower) var(--motion-ease-emphasized);
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
.ds-sparkline__fill {
|
|
28
36
|
fill: currentColor;
|
|
29
37
|
opacity: 0.15;
|
|
38
|
+
animation: ds-sparkline-fade var(--motion-duration-slower) var(--motion-ease-standard);
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
.ds-sparkline__dot {
|
|
33
42
|
fill: currentColor;
|
|
43
|
+
/* Waits out the draw, then pops in where the line ends. */
|
|
44
|
+
animation: ds-sparkline-fade var(--motion-duration-slow) var(--motion-ease-standard)
|
|
45
|
+
var(--motion-duration-slower) backwards;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@keyframes ds-sparkline-draw {
|
|
49
|
+
from {
|
|
50
|
+
stroke-dashoffset: 100;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@keyframes ds-sparkline-fade {
|
|
55
|
+
from {
|
|
56
|
+
opacity: 0;
|
|
57
|
+
}
|
|
34
58
|
}
|
|
35
59
|
|
|
36
60
|
/* Tones */
|
|
@@ -40,11 +64,11 @@
|
|
|
40
64
|
}
|
|
41
65
|
|
|
42
66
|
.ds-sparkline--positive {
|
|
43
|
-
color: var(--color-
|
|
67
|
+
color: var(--color-trend-up);
|
|
44
68
|
}
|
|
45
69
|
|
|
46
70
|
.ds-sparkline--negative {
|
|
47
|
-
color: var(--color-
|
|
71
|
+
color: var(--color-trend-down);
|
|
48
72
|
}
|
|
49
73
|
|
|
50
74
|
.ds-sparkline--neutral {
|
|
@@ -10,7 +10,7 @@ type SplitButtonOwnProps = {
|
|
|
10
10
|
/** Menu entries for the alternative actions */
|
|
11
11
|
items: DropdownMenuEntry[];
|
|
12
12
|
/** Visual treatment, shared by both segments */
|
|
13
|
-
variant?: 'primary' | 'secondary';
|
|
13
|
+
variant?: 'primary' | 'secondary' | 'neutral';
|
|
14
14
|
/** Component size */
|
|
15
15
|
size?: 'default' | 'compact';
|
|
16
16
|
/** Disables both segments */
|
|
@@ -62,6 +62,23 @@
|
|
|
62
62
|
color: var(--color-action-primary-text);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/* ============================================
|
|
66
|
+
NEUTRAL VARIANT
|
|
67
|
+
Active items fill grey instead of the action
|
|
68
|
+
teal — for sets where the selection should
|
|
69
|
+
not carry the action colour's weight.
|
|
70
|
+
============================================ */
|
|
71
|
+
|
|
72
|
+
.ds-toggle-group--neutral .ds-toggle-group__item--active {
|
|
73
|
+
background-color: var(--color-action-neutral-bg);
|
|
74
|
+
color: var(--color-action-neutral-text);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.ds-toggle-group--neutral .ds-toggle-group__item--active:hover {
|
|
78
|
+
background-color: var(--color-action-neutral-bg-hover);
|
|
79
|
+
color: var(--color-action-neutral-text);
|
|
80
|
+
}
|
|
81
|
+
|
|
65
82
|
/* ============================================
|
|
66
83
|
COMPACT
|
|
67
84
|
============================================ */
|
|
@@ -17,6 +17,8 @@ type ToggleGroupOwnProps = {
|
|
|
17
17
|
multiple?: boolean;
|
|
18
18
|
/** Component size */
|
|
19
19
|
size?: 'default' | 'compact';
|
|
20
|
+
/** Visual treatment of active items — teal by default, `neutral` fills them grey */
|
|
21
|
+
variant?: 'primary' | 'neutral';
|
|
20
22
|
/** Whether the whole group is disabled */
|
|
21
23
|
disabled?: boolean;
|
|
22
24
|
/** Called with the next selection — a string when single, an array when `multiple` */
|
|
@@ -8,6 +8,7 @@ const ToggleGroup = React.forwardRef(
|
|
|
8
8
|
value = [],
|
|
9
9
|
multiple = false,
|
|
10
10
|
size = "default",
|
|
11
|
+
variant = "primary",
|
|
11
12
|
disabled = false,
|
|
12
13
|
onValueChange,
|
|
13
14
|
onChange,
|
|
@@ -19,6 +20,7 @@ const ToggleGroup = React.forwardRef(
|
|
|
19
20
|
const classes = [
|
|
20
21
|
baseClass,
|
|
21
22
|
`${baseClass}--${size}`,
|
|
23
|
+
`${baseClass}--${variant}`,
|
|
22
24
|
disabled ? `${baseClass}--disabled` : "",
|
|
23
25
|
className
|
|
24
26
|
].filter(Boolean).join(" ");
|
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
padding: var(--padding-sm) var(--padding-lg);
|
|
41
41
|
background: none;
|
|
42
42
|
border: none;
|
|
43
|
+
/* Buttons default to the UA's buttontext, not the inherited colour, so
|
|
44
|
+
anything in the header that inherits would read black in both themes. */
|
|
45
|
+
color: var(--color-text-primary);
|
|
43
46
|
text-align: left;
|
|
44
47
|
cursor: pointer;
|
|
45
48
|
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
@@ -215,7 +218,9 @@
|
|
|
215
218
|
inherited by default: a consumer stylesheet that sets a colour on
|
|
216
219
|
.material-symbols-rounded itself (a common global default) would
|
|
217
220
|
otherwise override inheritance and detach the icon from the state
|
|
218
|
-
colours this component sets on its parents.
|
|
219
|
-
|
|
221
|
+
colours this component sets on its parents. The chevron is excluded —
|
|
222
|
+
it is the one icon that carries its own colour rule, which this
|
|
223
|
+
higher-specificity rule would otherwise silently override. */
|
|
224
|
+
.ds-tool-call .material-symbols-rounded:not(.ds-tool-call__chevron) {
|
|
220
225
|
color: inherit;
|
|
221
226
|
}
|
|
@@ -17,8 +17,14 @@
|
|
|
17
17
|
z-index: 50;
|
|
18
18
|
padding: var(--padding-xs) var(--padding-sm); /* 6px 8px */
|
|
19
19
|
border-radius: var(--radius-xs); /* 4px */
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
/* The floating surface, same recipe as Popover: page background (the
|
|
21
|
+
container fill is semi-transparent), hairline border, floating shadow.
|
|
22
|
+
Same-polarity in both themes — light bubble on light, dark on dark —
|
|
23
|
+
softer than the old inverse fill. */
|
|
24
|
+
border: var(--border-xs) solid var(--color-bg-container-border);
|
|
25
|
+
background-color: var(--color-bg-page-primary);
|
|
26
|
+
color: var(--color-text-primary);
|
|
27
|
+
box-shadow: var(--shadow-floating);
|
|
22
28
|
font-family: var(--font-paragraph-sm-family);
|
|
23
29
|
font-size: var(--font-paragraph-sm-size);
|
|
24
30
|
font-weight: var(--font-paragraph-sm-weight);
|
|
@@ -85,38 +91,49 @@
|
|
|
85
91
|
ARROW
|
|
86
92
|
============================================ */
|
|
87
93
|
|
|
94
|
+
/* The arrow is a rotated square in the panel's fill. It overlaps the panel
|
|
95
|
+
by a pixel more than before so its opaque fill covers the panel border
|
|
96
|
+
behind it, and draws the hairline itself on its two outward edges only. */
|
|
88
97
|
.ds-tooltip__arrow {
|
|
89
98
|
position: absolute;
|
|
90
99
|
width: 8px;
|
|
91
100
|
height: 8px;
|
|
92
|
-
background-color: var(--color-bg-
|
|
101
|
+
background-color: var(--color-bg-page-primary);
|
|
93
102
|
transform: rotate(45deg);
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
/* Arrow — top position (arrow points down) */
|
|
97
106
|
.ds-tooltip__panel--top .ds-tooltip__arrow {
|
|
98
|
-
bottom: -
|
|
107
|
+
bottom: -5px;
|
|
99
108
|
left: 50%;
|
|
100
109
|
margin-left: -4px;
|
|
110
|
+
border-right: var(--border-xs) solid var(--color-bg-container-border);
|
|
111
|
+
border-bottom: var(--border-xs) solid var(--color-bg-container-border);
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
/* Arrow — bottom position (arrow points up) */
|
|
104
115
|
.ds-tooltip__panel--bottom .ds-tooltip__arrow {
|
|
105
|
-
top: -
|
|
116
|
+
top: -5px;
|
|
106
117
|
left: 50%;
|
|
107
118
|
margin-left: -4px;
|
|
119
|
+
border-top: var(--border-xs) solid var(--color-bg-container-border);
|
|
120
|
+
border-left: var(--border-xs) solid var(--color-bg-container-border);
|
|
108
121
|
}
|
|
109
122
|
|
|
110
123
|
/* Arrow — left position (arrow points right) */
|
|
111
124
|
.ds-tooltip__panel--left .ds-tooltip__arrow {
|
|
112
|
-
right: -
|
|
125
|
+
right: -5px;
|
|
113
126
|
top: 50%;
|
|
114
127
|
margin-top: -4px;
|
|
128
|
+
border-top: var(--border-xs) solid var(--color-bg-container-border);
|
|
129
|
+
border-right: var(--border-xs) solid var(--color-bg-container-border);
|
|
115
130
|
}
|
|
116
131
|
|
|
117
132
|
/* Arrow — right position (arrow points left) */
|
|
118
133
|
.ds-tooltip__panel--right .ds-tooltip__arrow {
|
|
119
|
-
left: -
|
|
134
|
+
left: -5px;
|
|
120
135
|
top: 50%;
|
|
121
136
|
margin-top: -4px;
|
|
137
|
+
border-bottom: var(--border-xs) solid var(--color-bg-container-border);
|
|
138
|
+
border-left: var(--border-xs) solid var(--color-bg-container-border);
|
|
122
139
|
}
|
|
@@ -16,6 +16,7 @@ export interface TooltipProps {
|
|
|
16
16
|
/**
|
|
17
17
|
* Tooltip component for contextual text labels.
|
|
18
18
|
* Appears on hover or focus with a short delay.
|
|
19
|
-
*
|
|
19
|
+
* Rides the system's floating surface — page background, hairline border,
|
|
20
|
+
* floating shadow — so the bubble stays light in light theme and dark in dark.
|
|
20
21
|
*/
|
|
21
22
|
export declare const Tooltip: ({ children, content, position, showDelay, hideDelay, className, }: TooltipProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
USAGE CARD COMPONENT
|
|
3
|
+
An agent's budgets at a glance — meter rows
|
|
4
|
+
with reset captions, in the chart card chrome
|
|
5
|
+
============================================ */
|
|
6
|
+
|
|
7
|
+
/* Base — the card chrome itself comes from ds-chart */
|
|
8
|
+
|
|
9
|
+
.ds-usage-card__items {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
gap: var(--gap-lg);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.ds-usage-card__item {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: var(--gap-xxs);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Reset caption — sits under the bar's trailing edge */
|
|
22
|
+
|
|
23
|
+
.ds-usage-card__reset {
|
|
24
|
+
align-self: flex-end;
|
|
25
|
+
font-family: var(--font-caption-family);
|
|
26
|
+
font-size: var(--font-caption-size);
|
|
27
|
+
font-weight: var(--font-caption-weight);
|
|
28
|
+
line-height: var(--font-caption-line-height);
|
|
29
|
+
color: var(--color-text-secondary);
|
|
30
|
+
}
|