@robr0/design-system 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/components/Accordion/Accordion.js +1 -0
- package/components/AgentPlan/AgentPlan.css +231 -0
- package/components/AgentPlan/AgentPlan.d.ts +41 -0
- package/components/AgentPlan/AgentPlan.js +100 -0
- package/components/AgentStatus/AgentStatus.js +1 -0
- package/components/AiButton/AiButton.js +1 -0
- package/components/AlertDialog/AlertDialog.js +1 -0
- package/components/AnchorNav/AnchorNav.css +63 -0
- package/components/AnchorNav/AnchorNav.d.ts +33 -0
- package/components/AnchorNav/AnchorNav.js +82 -0
- package/components/AppLayout/AppLayout.js +1 -0
- package/components/AppSidebar/AppSidebar.js +1 -0
- package/components/Avatar/Avatar.js +1 -0
- package/components/Button/Button.js +1 -0
- package/components/Card/Card.js +1 -0
- package/components/Carousel/Carousel.js +1 -0
- package/components/ChatThread/ChatThread.js +1 -0
- package/components/Checkbox/Checkbox.js +1 -0
- package/components/CodeBlock/CodeBlock.js +1 -0
- package/components/CodeDiff/CodeDiff.css +175 -0
- package/components/CodeDiff/CodeDiff.d.ts +58 -0
- package/components/CodeDiff/CodeDiff.js +114 -0
- package/components/ColorPicker/ColorPicker.js +1 -0
- package/components/Combobox/Combobox.js +1 -0
- package/components/CommandPalette/CommandPalette.js +1 -0
- package/components/Composer/Composer.js +1 -0
- package/components/ContactCard/ContactCard.js +1 -0
- package/components/ContextMenu/ContextMenu.js +1 -0
- package/components/DataTable/DataTable.css +105 -0
- package/components/DataTable/DataTable.d.ts +81 -0
- package/components/DataTable/DataTable.js +236 -0
- package/components/DateInput/DateInput.js +1 -0
- package/components/DatePicker/DatePicker.js +1 -0
- package/components/Dialog/Dialog.js +1 -0
- package/components/Drawer/Drawer.js +1 -0
- package/components/Dropdown/Dropdown.js +1 -0
- package/components/DropdownMenu/DropdownMenu.css +1 -1
- package/components/DropdownMenu/DropdownMenu.js +1 -0
- package/components/EventCalendar/EventCalendar.css +328 -0
- package/components/EventCalendar/EventCalendar.d.ts +51 -0
- package/components/EventCalendar/EventCalendar.js +214 -0
- package/components/Field/Field.js +1 -0
- package/components/Field/FieldContext.js +1 -0
- package/components/FileInput/FileInput.js +1 -0
- package/components/Input/Input.js +1 -0
- package/components/InterruptCard/InterruptCard.css +11 -21
- package/components/InterruptCard/InterruptCard.d.ts +5 -6
- package/components/MessageCard/MessageCard.css +1 -2
- package/components/ModelPicker/ModelPicker.css +240 -0
- package/components/ModelPicker/ModelPicker.d.ts +60 -0
- package/components/ModelPicker/ModelPicker.js +218 -0
- package/components/NavList/NavList.js +1 -0
- package/components/NotificationCenter/NotificationCenter.css +262 -0
- package/components/NotificationCenter/NotificationCenter.d.ts +72 -0
- package/components/NotificationCenter/NotificationCenter.js +129 -0
- package/components/NumberInput/NumberInput.css +154 -0
- package/components/NumberInput/NumberInput.d.ts +44 -0
- package/components/NumberInput/NumberInput.js +147 -0
- package/components/Pagination/Pagination.js +1 -0
- package/components/PinInput/PinInput.css +92 -0
- package/components/PinInput/PinInput.d.ts +46 -0
- package/components/PinInput/PinInput.js +161 -0
- package/components/Popover/Popover.css +5 -6
- package/components/Popover/Popover.js +1 -0
- package/components/RadioButton/RadioButton.js +1 -0
- package/components/Reasoning/Reasoning.js +1 -0
- package/components/SegmentedControl/SegmentedControl.js +1 -0
- package/components/SelectionCard/SelectionCard.js +1 -0
- package/components/ShaderField/ShaderField.js +1 -0
- package/components/ShaderField/field.glsl.d.ts +11 -5
- package/components/ShaderField/field.glsl.js +4 -3
- package/components/ShaderField/useShaderField.d.ts +19 -2
- package/components/ShaderField/useShaderField.js +18 -3
- package/components/Slider/Slider.js +1 -0
- package/components/Sparkline/Sparkline.css +52 -0
- package/components/Sparkline/Sparkline.d.ts +49 -0
- package/components/Sparkline/Sparkline.js +86 -0
- package/components/Stepper/Stepper.css +207 -0
- package/components/Stepper/Stepper.d.ts +41 -0
- package/components/Stepper/Stepper.js +61 -0
- package/components/Tabs/Tabs.js +1 -0
- package/components/TagInput/TagInput.css +160 -0
- package/components/TagInput/TagInput.d.ts +43 -0
- package/components/TagInput/TagInput.js +137 -0
- package/components/Textarea/Textarea.js +1 -0
- package/components/TimePicker/TimePicker.css +230 -0
- package/components/TimePicker/TimePicker.d.ts +46 -0
- package/components/TimePicker/TimePicker.js +246 -0
- package/components/Timeline/Timeline.css +17 -0
- package/components/Timeline/Timeline.d.ts +2 -0
- package/components/Timeline/Timeline.js +1 -0
- package/components/Toast/Toast.js +1 -0
- package/components/ToggleGroup/ToggleGroup.js +1 -0
- package/components/ToggleSwitch/ToggleSwitch.js +1 -0
- package/components/ToolCall/ToolCall.css +7 -11
- package/components/ToolCall/ToolCall.js +1 -0
- package/components/Tooltip/Tooltip.js +1 -0
- package/components/TreeView/TreeView.css +119 -0
- package/components/TreeView/TreeView.d.ts +45 -0
- package/components/TreeView/TreeView.js +232 -0
- package/components/registry.d.ts +22 -6
- package/components/registry.js +3 -1
- package/components/registry.json +246 -20
- package/components/registry.json.d.ts +246 -20
- package/components/registry.json.js +2 -2
- package/index.d.ts +16 -2
- package/index.js +32 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ The **live site** is the portfolio built on the design system. **Storybook** is
|
|
|
18
18
|
| Part | Description |
|
|
19
19
|
|---|---|
|
|
20
20
|
| **Portfolio website** (`/website`) | Next.js app with case studies, work history, writing, and about pages, all built exclusively with the design system components below. **[Live site →](https://robertritacca.com/)** |
|
|
21
|
-
| **Design system** (`/src`) | <!-- component-count -->
|
|
21
|
+
| **Design system** (`/src`) | <!-- component-count -->101<!-- /component-count --> React components, a three-tier token architecture, dark mode, a WebGL2 ambient background that themes itself from your tokens, and a full documentation site. Built to production standards. **[Storybook →](https://design-system-iota-one.vercel.app/?path=/docs/robr0-ds--docs)** |
|
|
22
22
|
| **AI layer** (`ai` components in `/src`, chat in `/website`, `/evals`) | A site-wide chat that answers questions about the work: built from the library's own `ai` components, grounded in a corpus generated from the site's published content, and scored by a golden-set eval. |
|
|
23
23
|
|
|
24
24
|
---
|
|
@@ -28,7 +28,7 @@ The **live site** is the portfolio built on the design system. **Storybook** is
|
|
|
28
28
|
### Components
|
|
29
29
|
|
|
30
30
|
<!-- component-list:start -->
|
|
31
|
-
Accordion · Agent status · AI button · Alert · Alert dialog · App layout · App sidebar · Avatar · Badge · Breadcrumb · Button · Button group · Card · Carousel ·
|
|
31
|
+
Accordion · Agent plan · Agent status · AI button · Alert · Alert dialog · Anchor nav · App layout · App sidebar · Area chart · Avatar · Badge · Bar chart · Breadcrumb · Button · Button group · Card · Carousel · Chat header · Chat marker · Chat message · Chat thread · Checkbox · Chip · Circular button · Code block · Code diff · Colour picker · Combobox · Command palette · Composer · Contact card · Context menu · Contribution graph · Data table · Date input · Date picker · Dialog · Divider · Document chip · Drawer · Dropdown · Dropdown menu · Empty state · Entity card · Event calendar · Field · Figure · File input · Input · Instructions · Interrupt card · Kbd · Line chart · Link list · Message actions · Message card · Model picker · Nav · Nav list · Notification centre · Number input · Pagination · Pie chart · Pin input · Popover · Progress bar · Prompt suggestions · Prose · Quote · Radar chart · Radial chart · Radio button · Reasoning · Scatter chart · Section title · Segmented control · Selection card · Shader field · Skeleton · Slider · Source chip · Sparkline · Spinner · Stacked bar chart · Stat · Stepper · Swatch · Table · Tabs · Tag input · Textarea · Time picker · Timeline · Toast · Toggle group · Toggle switch · Tool call · Tooltip · Tree view · Treemap
|
|
32
32
|
<!-- component-list:end -->
|
|
33
33
|
|
|
34
34
|
### Ambient background
|
|
@@ -46,7 +46,7 @@ const [status, setStatus] = useState<ShaderFieldStatus>('pending');
|
|
|
46
46
|
</div>
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Eight parameters describe the look, and a composition is a table of token names with positions and drift periods, so a negative weight cuts a shadow through the field instead of adding light to it.
|
|
50
50
|
|
|
51
51
|
It asks two things of you, both deliberate. It fills a positioned ancestor you provide, because where a background sits is a layout decision rather than a rendering one. And it never decides what to paint instead of itself: it reports `pending`, `active` or `unavailable`, and one fallback covers every way it can fail (no WebGL2, a blocked or lost GPU context, a renderer that stalls before its first frame, or `enabled={false}` as a kill switch). `pending` is the state worth handling. Paint neither layer while the context comes up, or the swap a frame later reads as two backgrounds loading in sequence.
|
|
52
52
|
|
|
@@ -71,7 +71,7 @@ import '@robr0/design-system/tokens/tokens.css';
|
|
|
71
71
|
import { Button, Card, Badge } from '@robr0/design-system';
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
Deep imports work too (`@robr0/design-system/components/Button/Button`).
|
|
74
|
+
Deep imports work too (`@robr0/design-system/components/Button/Button`). The Recharts-backed charts live behind a separate entry so the optional `recharts` peer dependency is only needed if you use them; Sparkline and ContributionGraph are dependency-free and export from the main barrel:
|
|
75
75
|
|
|
76
76
|
```tsx
|
|
77
77
|
import { BarChart, LineChart } from '@robr0/design-system/charts';
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
AGENT PLAN COMPONENT
|
|
3
|
+
A collapsible checklist of an agent's task:
|
|
4
|
+
a progress header and one row per step.
|
|
5
|
+
|
|
6
|
+
The container stays neutral, like ToolCall —
|
|
7
|
+
colour lives in each step's indicator, so a
|
|
8
|
+
long plan reads as a list rather than a wall
|
|
9
|
+
of tinted rows. A thin connector ties the
|
|
10
|
+
indicators into one path through the task.
|
|
11
|
+
============================================ */
|
|
12
|
+
|
|
13
|
+
.ds-agent-plan {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
width: 100%;
|
|
17
|
+
background-color: var(--color-bg-container-primary);
|
|
18
|
+
border: var(--border-xs) solid var(--color-bg-container-border);
|
|
19
|
+
border-radius: var(--radius-md);
|
|
20
|
+
overflow: hidden;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* ============================================
|
|
24
|
+
HEADER
|
|
25
|
+
============================================ */
|
|
26
|
+
|
|
27
|
+
.ds-agent-plan__header {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: var(--gap-sm);
|
|
31
|
+
width: 100%;
|
|
32
|
+
padding: var(--padding-sm) var(--padding-md);
|
|
33
|
+
background: none;
|
|
34
|
+
border: none;
|
|
35
|
+
text-align: left;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ds-agent-plan__header:hover {
|
|
41
|
+
background-color: var(--color-bg-container-secondary);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.ds-agent-plan__header:focus-visible {
|
|
45
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
46
|
+
outline-offset: -2px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ds-agent-plan__title {
|
|
50
|
+
flex: 1 1 auto;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
overflow: hidden;
|
|
53
|
+
text-overflow: ellipsis;
|
|
54
|
+
white-space: nowrap;
|
|
55
|
+
color: var(--color-text-primary);
|
|
56
|
+
font-family: var(--font-paragraph-sm-em-family);
|
|
57
|
+
font-size: var(--font-paragraph-sm-em-size);
|
|
58
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
59
|
+
line-height: var(--font-paragraph-sm-em-line-height);
|
|
60
|
+
letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-agent-plan__count {
|
|
64
|
+
flex: none;
|
|
65
|
+
color: var(--color-text-tertiary);
|
|
66
|
+
font-family: var(--font-paragraph-sm-family);
|
|
67
|
+
font-size: var(--font-paragraph-sm-size);
|
|
68
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
69
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
70
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
71
|
+
font-variant-numeric: tabular-nums;
|
|
72
|
+
white-space: nowrap;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.ds-agent-plan__chevron {
|
|
76
|
+
--icon-size: var(--icon-size-sm);
|
|
77
|
+
|
|
78
|
+
flex: none;
|
|
79
|
+
color: var(--color-icon-secondary);
|
|
80
|
+
transition: transform var(--motion-duration-slow) var(--motion-ease-standard);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.ds-agent-plan--open .ds-agent-plan__chevron {
|
|
84
|
+
transform: rotate(180deg);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* ============================================
|
|
88
|
+
PANEL
|
|
89
|
+
Same grid-rows collapse as ToolCall, so the
|
|
90
|
+
list opens and closes without measuring.
|
|
91
|
+
============================================ */
|
|
92
|
+
|
|
93
|
+
.ds-agent-plan__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-agent-plan--open .ds-agent-plan__panel {
|
|
103
|
+
grid-template-rows: 1fr;
|
|
104
|
+
visibility: visible;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ds-agent-plan__content {
|
|
108
|
+
overflow: hidden;
|
|
109
|
+
min-height: 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.ds-agent-plan--open .ds-agent-plan__content {
|
|
113
|
+
border-top: var(--border-xs) solid var(--color-divider);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* ============================================
|
|
117
|
+
STEPS
|
|
118
|
+
============================================ */
|
|
119
|
+
|
|
120
|
+
.ds-agent-plan__steps {
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
margin: 0;
|
|
124
|
+
padding: var(--padding-sm-md) var(--padding-md);
|
|
125
|
+
list-style: none;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.ds-agent-plan__step {
|
|
129
|
+
position: relative;
|
|
130
|
+
display: flex;
|
|
131
|
+
align-items: flex-start;
|
|
132
|
+
gap: var(--gap-sm);
|
|
133
|
+
padding: var(--padding-xxs) 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Connector — a thin line linking each indicator to the next */
|
|
137
|
+
.ds-agent-plan__step:not(:last-child)::before {
|
|
138
|
+
content: '';
|
|
139
|
+
position: absolute;
|
|
140
|
+
top: calc(var(--padding-xxs) + var(--icon-size-sm));
|
|
141
|
+
bottom: calc(-1 * var(--padding-xxs));
|
|
142
|
+
left: calc(var(--icon-size-sm) / 2);
|
|
143
|
+
width: var(--border-xs);
|
|
144
|
+
background-color: var(--color-divider);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.ds-agent-plan__indicator {
|
|
148
|
+
display: inline-flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
flex: none;
|
|
152
|
+
color: var(--color-icon-secondary);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.ds-agent-plan__indicator .material-symbols-rounded {
|
|
156
|
+
--icon-size: var(--icon-size-sm);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.ds-agent-plan__step-body {
|
|
160
|
+
display: flex;
|
|
161
|
+
flex-direction: column;
|
|
162
|
+
min-width: 0;
|
|
163
|
+
/* Align the first text line with the indicator's optical centre */
|
|
164
|
+
padding-top: calc((var(--icon-size-sm) - var(--font-paragraph-sm-line-height)) / 2);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.ds-agent-plan__label {
|
|
168
|
+
color: var(--color-text-primary);
|
|
169
|
+
font-family: var(--font-paragraph-sm-family);
|
|
170
|
+
font-size: var(--font-paragraph-sm-size);
|
|
171
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
172
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
173
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.ds-agent-plan__detail {
|
|
177
|
+
color: var(--color-text-tertiary);
|
|
178
|
+
font-family: var(--font-paragraph-sm-family);
|
|
179
|
+
font-size: var(--font-paragraph-sm-size);
|
|
180
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
181
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
182
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* ============================================
|
|
186
|
+
STEP STATES
|
|
187
|
+
============================================ */
|
|
188
|
+
|
|
189
|
+
.ds-agent-plan__step--completed .ds-agent-plan__indicator {
|
|
190
|
+
color: var(--color-status-positive-text);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.ds-agent-plan__step--completed .ds-agent-plan__label {
|
|
194
|
+
color: var(--color-text-tertiary);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.ds-agent-plan__step--active .ds-agent-plan__indicator {
|
|
198
|
+
color: var(--color-status-info-text);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.ds-agent-plan__step--active .ds-agent-plan__label {
|
|
202
|
+
font-family: var(--font-paragraph-sm-em-family);
|
|
203
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
204
|
+
letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.ds-agent-plan__step--failed .ds-agent-plan__indicator {
|
|
208
|
+
color: var(--color-status-error-text);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.ds-agent-plan__step--failed .ds-agent-plan__label {
|
|
212
|
+
color: var(--color-status-error-text);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* ============================================
|
|
216
|
+
SCREEN READER TEXT
|
|
217
|
+
Status is colour + glyph for sighted users;
|
|
218
|
+
this span announces it.
|
|
219
|
+
============================================ */
|
|
220
|
+
|
|
221
|
+
.ds-agent-plan__sr {
|
|
222
|
+
position: absolute;
|
|
223
|
+
width: 1px;
|
|
224
|
+
height: 1px;
|
|
225
|
+
padding: 0;
|
|
226
|
+
margin: -1px;
|
|
227
|
+
overflow: hidden;
|
|
228
|
+
clip: rect(0, 0, 0, 0);
|
|
229
|
+
white-space: nowrap;
|
|
230
|
+
border: 0;
|
|
231
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export type AgentPlanStepStatus = 'pending' | 'active' | 'completed' | 'failed';
|
|
3
|
+
export interface AgentPlanStep {
|
|
4
|
+
/** What this step does, in one line. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Where the step has got to. Defaults to `pending`. */
|
|
7
|
+
status?: AgentPlanStepStatus;
|
|
8
|
+
/** Optional supporting line under the label, e.g. the file it touched. */
|
|
9
|
+
detail?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Props owned by AgentPlan itself — everything else falls through to the root element. */
|
|
12
|
+
type AgentPlanOwnProps = {
|
|
13
|
+
/** The plan, in order. Step status drives each row's indicator and colour. */
|
|
14
|
+
steps: AgentPlanStep[];
|
|
15
|
+
/**
|
|
16
|
+
* Header text. Left unset, it is computed from the steps —
|
|
17
|
+
* "3 steps left", or "All steps complete" once everything is done.
|
|
18
|
+
*/
|
|
19
|
+
title?: string;
|
|
20
|
+
/** Open state for controlled use. Pair with `onOpenChange`. */
|
|
21
|
+
open?: boolean;
|
|
22
|
+
/** Open state for uncontrolled use. */
|
|
23
|
+
defaultOpen?: boolean;
|
|
24
|
+
/** Fires whenever the step list opens or closes. */
|
|
25
|
+
onOpenChange?: (open: boolean) => void;
|
|
26
|
+
/** Additional CSS classes */
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
29
|
+
export interface AgentPlanProps extends AgentPlanOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof AgentPlanOwnProps> {
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* AgentPlan shows the steps an agent intends to take and where it has got to:
|
|
33
|
+
* a collapsible checklist with one row per step, a live progress readout in
|
|
34
|
+
* the header, and completed work ticked off as the run advances.
|
|
35
|
+
*
|
|
36
|
+
* It complements the other agent primitives — AgentStatus says what is
|
|
37
|
+
* happening right now, ToolCall records one action, AgentPlan holds the
|
|
38
|
+
* whole task.
|
|
39
|
+
*/
|
|
40
|
+
export declare const AgentPlan: React.ForwardRefExoticComponent<AgentPlanProps & React.RefAttributes<HTMLDivElement>>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useId, useState, useCallback } from "react";
|
|
4
|
+
import { Spinner } from "../Spinner/Spinner.js";
|
|
5
|
+
import "./AgentPlan.css";
|
|
6
|
+
import "../../fonts/material-symbols.css";
|
|
7
|
+
const STEP_ICONS = {
|
|
8
|
+
pending: "circle",
|
|
9
|
+
completed: "check_circle",
|
|
10
|
+
failed: "error"
|
|
11
|
+
};
|
|
12
|
+
const STEP_STATUS_TEXT = {
|
|
13
|
+
pending: "Not started",
|
|
14
|
+
active: "In progress",
|
|
15
|
+
completed: "Completed",
|
|
16
|
+
failed: "Failed"
|
|
17
|
+
};
|
|
18
|
+
const AgentPlan = React.forwardRef(
|
|
19
|
+
({
|
|
20
|
+
steps,
|
|
21
|
+
title,
|
|
22
|
+
open,
|
|
23
|
+
defaultOpen = true,
|
|
24
|
+
onOpenChange,
|
|
25
|
+
className = "",
|
|
26
|
+
...rest
|
|
27
|
+
}, ref) => {
|
|
28
|
+
const baseClass = "ds-agent-plan";
|
|
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 total = steps.length;
|
|
41
|
+
const completed = steps.filter((step) => step.status === "completed").length;
|
|
42
|
+
const remaining = total - completed;
|
|
43
|
+
const resolvedTitle = title ?? (total > 0 && remaining === 0 ? "All steps complete" : `${remaining} step${remaining === 1 ? "" : "s"} left`);
|
|
44
|
+
const classes = [baseClass, isOpen ? `${baseClass}--open` : "", className].filter(Boolean).join(" ");
|
|
45
|
+
return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, children: [
|
|
46
|
+
/* @__PURE__ */ jsxs(
|
|
47
|
+
"button",
|
|
48
|
+
{
|
|
49
|
+
type: "button",
|
|
50
|
+
id: triggerId,
|
|
51
|
+
className: `${baseClass}__header`,
|
|
52
|
+
"aria-expanded": isOpen,
|
|
53
|
+
"aria-controls": panelId,
|
|
54
|
+
onClick: toggle,
|
|
55
|
+
children: [
|
|
56
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__title`, children: resolvedTitle }),
|
|
57
|
+
total > 0 && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__count`, children: [
|
|
58
|
+
completed,
|
|
59
|
+
"/",
|
|
60
|
+
total
|
|
61
|
+
] }),
|
|
62
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__chevron material-symbols-rounded`, "aria-hidden": "true", children: "expand_more" })
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
/* @__PURE__ */ jsx(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
className: `${baseClass}__panel`,
|
|
70
|
+
id: panelId,
|
|
71
|
+
role: "region",
|
|
72
|
+
"aria-labelledby": triggerId,
|
|
73
|
+
children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children: /* @__PURE__ */ jsx("ol", { className: `${baseClass}__steps`, children: steps.map((step, index) => {
|
|
74
|
+
const status = step.status ?? "pending";
|
|
75
|
+
return /* @__PURE__ */ jsxs(
|
|
76
|
+
"li",
|
|
77
|
+
{
|
|
78
|
+
className: `${baseClass}__step ${baseClass}__step--${status}`,
|
|
79
|
+
"aria-current": status === "active" ? "step" : void 0,
|
|
80
|
+
children: [
|
|
81
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__indicator`, "aria-hidden": "true", children: status === "active" ? /* @__PURE__ */ jsx(Spinner, { size: "sm", variant: "inherit" }) : /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", children: STEP_ICONS[status] }) }),
|
|
82
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__step-body`, children: [
|
|
83
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: step.label }),
|
|
84
|
+
step.detail && /* @__PURE__ */ jsx("span", { className: `${baseClass}__detail`, children: step.detail })
|
|
85
|
+
] }),
|
|
86
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__sr`, children: STEP_STATUS_TEXT[status] })
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
index
|
|
90
|
+
);
|
|
91
|
+
}) }) })
|
|
92
|
+
}
|
|
93
|
+
)
|
|
94
|
+
] });
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
AgentPlan.displayName = "AgentPlan";
|
|
98
|
+
export {
|
|
99
|
+
AgentPlan
|
|
100
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
ANCHOR NAV
|
|
3
|
+
"On this page" list of anchor links with a
|
|
4
|
+
position indicator riding the left rail.
|
|
5
|
+
============================================ */
|
|
6
|
+
.ds-anchor-nav {
|
|
7
|
+
font-family: var(--font-family-primary);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.ds-anchor-nav__header {
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
gap: var(--gap-xs);
|
|
14
|
+
margin: 0 0 var(--gap-sm);
|
|
15
|
+
font-size: var(--font-paragraph-em-size);
|
|
16
|
+
font-weight: var(--font-paragraph-em-weight);
|
|
17
|
+
line-height: var(--font-paragraph-em-line-height);
|
|
18
|
+
color: var(--color-text-primary);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.ds-anchor-nav__icon {
|
|
22
|
+
--icon-size: var(--icon-size-sm);
|
|
23
|
+
color: var(--color-icon-primary);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.ds-anchor-nav__list {
|
|
27
|
+
list-style: none;
|
|
28
|
+
margin: 0;
|
|
29
|
+
padding: 0;
|
|
30
|
+
border-left: var(--border-xs) solid var(--color-divider);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.ds-anchor-nav__link {
|
|
34
|
+
display: block;
|
|
35
|
+
padding: var(--padding-xs) 0 var(--padding-xs) var(--padding-md);
|
|
36
|
+
/* Sits over the list rail; turns into the indicator when active */
|
|
37
|
+
margin-left: calc(var(--border-xs) * -1);
|
|
38
|
+
border-left: var(--border-md) solid transparent;
|
|
39
|
+
font-size: var(--font-paragraph-size);
|
|
40
|
+
font-weight: var(--font-paragraph-weight);
|
|
41
|
+
line-height: var(--font-paragraph-line-height);
|
|
42
|
+
color: var(--color-text-tertiary);
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
transition:
|
|
45
|
+
color var(--motion-duration-fast) var(--motion-ease-standard),
|
|
46
|
+
border-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ds-anchor-nav__link:hover {
|
|
50
|
+
color: var(--color-text-primary);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.ds-anchor-nav__link:focus-visible {
|
|
54
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
55
|
+
outline-offset: -2px;
|
|
56
|
+
border-radius: var(--radius-xxs);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ds-anchor-nav__link--active {
|
|
60
|
+
color: var(--color-text-primary);
|
|
61
|
+
font-weight: var(--font-paragraph-em-weight);
|
|
62
|
+
border-left-color: var(--color-text-primary);
|
|
63
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface AnchorNavItem {
|
|
3
|
+
/** The id of the element the item jumps to (rendered as `href="#id"`) */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Link text */
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
type AnchorNavOwnProps = {
|
|
9
|
+
/** The on-page sections to list, in document order */
|
|
10
|
+
items: AnchorNavItem[];
|
|
11
|
+
/** Header text above the list; pass an empty string to render no header */
|
|
12
|
+
title?: string;
|
|
13
|
+
/** Material Symbols icon name beside the header; pass an empty string for none */
|
|
14
|
+
icon?: string;
|
|
15
|
+
/** Controlled active item id — set it to drive the highlight yourself and skip scroll tracking */
|
|
16
|
+
activeId?: string;
|
|
17
|
+
/** Fires when the tracked (or clicked) active item changes */
|
|
18
|
+
onActiveChange?: (id: string) => void;
|
|
19
|
+
/** Distance in px from the viewport top at which a section counts as current, e.g. a sticky header's height */
|
|
20
|
+
offset?: number;
|
|
21
|
+
};
|
|
22
|
+
export interface AnchorNavProps extends AnchorNavOwnProps, Omit<React.ComponentPropsWithoutRef<'nav'>, keyof AnchorNavOwnProps> {
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* An "On this page" list of anchor links that tracks the reader's position.
|
|
26
|
+
*
|
|
27
|
+
* Uncontrolled by default: a scroll listener marks the last section whose top
|
|
28
|
+
* has passed `offset` as current. Pass `activeId` to control the highlight
|
|
29
|
+
* instead (no listener is attached). The active link carries
|
|
30
|
+
* `aria-current="location"`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const AnchorNav: React.ForwardRefExoticComponent<AnchorNavProps & React.RefAttributes<HTMLElement>>;
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
3
|
+
import React, { useRef, useImperativeHandle, useState, useCallback, useEffect } from "react";
|
|
4
|
+
import "./AnchorNav.css";
|
|
5
|
+
const AnchorNav = React.forwardRef(
|
|
6
|
+
({
|
|
7
|
+
items,
|
|
8
|
+
title = "On this page",
|
|
9
|
+
icon = "toc",
|
|
10
|
+
activeId,
|
|
11
|
+
onActiveChange,
|
|
12
|
+
offset = 96,
|
|
13
|
+
className,
|
|
14
|
+
...rest
|
|
15
|
+
}, ref) => {
|
|
16
|
+
const navRef = useRef(null);
|
|
17
|
+
useImperativeHandle(ref, () => navRef.current);
|
|
18
|
+
const isControlled = activeId !== void 0;
|
|
19
|
+
const [trackedId, setTrackedId] = useState(void 0);
|
|
20
|
+
const currentId = isControlled ? activeId : trackedId;
|
|
21
|
+
const onActiveChangeRef = useRef(onActiveChange);
|
|
22
|
+
onActiveChangeRef.current = onActiveChange;
|
|
23
|
+
const setActive = useCallback(
|
|
24
|
+
(id) => {
|
|
25
|
+
setTrackedId((prev) => {
|
|
26
|
+
if (id !== void 0 && id !== prev) onActiveChangeRef.current?.(id);
|
|
27
|
+
return id;
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
[]
|
|
31
|
+
);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (isControlled || items.length === 0) return;
|
|
34
|
+
let frame = 0;
|
|
35
|
+
const measure = () => {
|
|
36
|
+
frame = 0;
|
|
37
|
+
let current = items[0]?.id;
|
|
38
|
+
for (const item of items) {
|
|
39
|
+
const el = document.getElementById(item.id);
|
|
40
|
+
if (!el) continue;
|
|
41
|
+
if (el.getBoundingClientRect().top <= offset + 1) current = item.id;
|
|
42
|
+
}
|
|
43
|
+
setActive(current);
|
|
44
|
+
};
|
|
45
|
+
const schedule = () => {
|
|
46
|
+
if (frame === 0) frame = window.requestAnimationFrame(measure);
|
|
47
|
+
};
|
|
48
|
+
measure();
|
|
49
|
+
window.addEventListener("scroll", schedule, { passive: true });
|
|
50
|
+
window.addEventListener("resize", schedule);
|
|
51
|
+
return () => {
|
|
52
|
+
window.removeEventListener("scroll", schedule);
|
|
53
|
+
window.removeEventListener("resize", schedule);
|
|
54
|
+
if (frame !== 0) window.cancelAnimationFrame(frame);
|
|
55
|
+
};
|
|
56
|
+
}, [isControlled, items, offset, setActive]);
|
|
57
|
+
const classes = ["ds-anchor-nav", className].filter(Boolean).join(" ");
|
|
58
|
+
return /* @__PURE__ */ jsxs("nav", { ref: navRef, "aria-label": title || "On this page", className: classes, ...rest, children: [
|
|
59
|
+
title && /* @__PURE__ */ jsxs("p", { className: "ds-anchor-nav__header", children: [
|
|
60
|
+
icon && /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded ds-anchor-nav__icon", "aria-hidden": "true", children: icon }),
|
|
61
|
+
title
|
|
62
|
+
] }),
|
|
63
|
+
/* @__PURE__ */ jsx("ul", { className: "ds-anchor-nav__list", children: items.map((item) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
|
|
64
|
+
"a",
|
|
65
|
+
{
|
|
66
|
+
href: `#${item.id}`,
|
|
67
|
+
className: item.id === currentId ? "ds-anchor-nav__link ds-anchor-nav__link--active" : "ds-anchor-nav__link",
|
|
68
|
+
"aria-current": item.id === currentId ? "location" : void 0,
|
|
69
|
+
onClick: () => {
|
|
70
|
+
if (!isControlled) setActive(item.id);
|
|
71
|
+
else onActiveChangeRef.current?.(item.id);
|
|
72
|
+
},
|
|
73
|
+
children: item.label
|
|
74
|
+
}
|
|
75
|
+
) }, item.id)) })
|
|
76
|
+
] });
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
AnchorNav.displayName = "AnchorNav";
|
|
80
|
+
export {
|
|
81
|
+
AnchorNav
|
|
82
|
+
};
|
package/components/Card/Card.js
CHANGED