@robr0/design-system 0.7.0 → 0.8.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 +3 -3
- package/components/AgentPlan/AgentPlan.css +231 -0
- package/components/AgentPlan/AgentPlan.d.ts +41 -0
- package/components/AgentPlan/AgentPlan.js +99 -0
- package/components/DataTable/DataTable.css +105 -0
- package/components/DataTable/DataTable.d.ts +81 -0
- package/components/DataTable/DataTable.js +235 -0
- package/components/EventCalendar/EventCalendar.css +328 -0
- package/components/EventCalendar/EventCalendar.d.ts +51 -0
- package/components/EventCalendar/EventCalendar.js +213 -0
- package/components/ModelPicker/ModelPicker.css +238 -0
- package/components/ModelPicker/ModelPicker.d.ts +60 -0
- package/components/ModelPicker/ModelPicker.js +217 -0
- package/components/NotificationCenter/NotificationCenter.css +262 -0
- package/components/NotificationCenter/NotificationCenter.d.ts +72 -0
- package/components/NotificationCenter/NotificationCenter.js +128 -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 +17 -3
- package/components/Timeline/Timeline.css +17 -0
- package/components/Timeline/Timeline.d.ts +2 -0
- package/components/Timeline/Timeline.js +1 -0
- package/components/registry.json +40 -0
- package/components/registry.json.d.ts +40 -0
- package/components/registry.json.js +1 -1
- package/index.d.ts +5 -0
- package/index.js +11 -0
- 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 -->84<!-- /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 · Chart · Chat header · Chat marker · Chat message · Chat thread · Checkbox · Chip · Circular button · Code block · Colour picker · Combobox · Command palette · Composer · Contact card · Context menu · Contribution graph · Date input · Date picker · Dialog · Divider · Document chip · Drawer · Dropdown · Dropdown menu · Empty state · Entity card · Field · Figure · File input · Input · Instructions · Interrupt card · Kbd · Link list · Message actions · Message card · Navigation · Nav list · Pagination · Popover · Progress bar · Prompt suggestions · Prose · Quote · Radio button · Reasoning · Section title · Segmented control · Selection card · Shader field · Skeleton · Slider · Source chip · Spinner · Stat · Swatch · Table · Tabs · Textarea · Timeline · Toast · Toggle group · Toggle switch · Tool call · Tooltip
|
|
31
|
+
Accordion · Agent plan · Agent status · AI button · Alert · Alert dialog · App layout · App sidebar · Avatar · Badge · Breadcrumb · Button · Button group · Card · Carousel · Chart · Chat header · Chat marker · Chat message · Chat thread · Checkbox · Chip · Circular button · Code block · 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 · Link list · Message actions · Message card · Model picker · Navigation · Nav list · Notification centre · Pagination · Popover · Progress bar · Prompt suggestions · Prose · Quote · Radio button · Reasoning · Section title · Segmented control · Selection card · Shader field · Skeleton · Slider · Source chip · Spinner · Stat · Swatch · Table · Tabs · Textarea · Timeline · Toast · Toggle group · Toggle switch · Tool call · Tooltip
|
|
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
|
|
|
@@ -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-xs) var(--padding-sm-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) var(--padding-sm-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,99 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import React, { useId, useState, useCallback } from "react";
|
|
3
|
+
import { Spinner } from "../Spinner/Spinner.js";
|
|
4
|
+
import "./AgentPlan.css";
|
|
5
|
+
import "../../fonts/material-symbols.css";
|
|
6
|
+
const STEP_ICONS = {
|
|
7
|
+
pending: "circle",
|
|
8
|
+
completed: "check_circle",
|
|
9
|
+
failed: "error"
|
|
10
|
+
};
|
|
11
|
+
const STEP_STATUS_TEXT = {
|
|
12
|
+
pending: "Not started",
|
|
13
|
+
active: "In progress",
|
|
14
|
+
completed: "Completed",
|
|
15
|
+
failed: "Failed"
|
|
16
|
+
};
|
|
17
|
+
const AgentPlan = React.forwardRef(
|
|
18
|
+
({
|
|
19
|
+
steps,
|
|
20
|
+
title,
|
|
21
|
+
open,
|
|
22
|
+
defaultOpen = true,
|
|
23
|
+
onOpenChange,
|
|
24
|
+
className = "",
|
|
25
|
+
...rest
|
|
26
|
+
}, ref) => {
|
|
27
|
+
const baseClass = "ds-agent-plan";
|
|
28
|
+
const id = useId();
|
|
29
|
+
const panelId = `${id}-panel`;
|
|
30
|
+
const triggerId = `${id}-trigger`;
|
|
31
|
+
const isControlled = open !== void 0;
|
|
32
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
33
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
34
|
+
const toggle = useCallback(() => {
|
|
35
|
+
const next = !isOpen;
|
|
36
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
37
|
+
onOpenChange?.(next);
|
|
38
|
+
}, [isOpen, isControlled, onOpenChange]);
|
|
39
|
+
const total = steps.length;
|
|
40
|
+
const completed = steps.filter((step) => step.status === "completed").length;
|
|
41
|
+
const remaining = total - completed;
|
|
42
|
+
const resolvedTitle = title ?? (total > 0 && remaining === 0 ? "All steps complete" : `${remaining} step${remaining === 1 ? "" : "s"} left`);
|
|
43
|
+
const classes = [baseClass, isOpen ? `${baseClass}--open` : "", className].filter(Boolean).join(" ");
|
|
44
|
+
return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, children: [
|
|
45
|
+
/* @__PURE__ */ jsxs(
|
|
46
|
+
"button",
|
|
47
|
+
{
|
|
48
|
+
type: "button",
|
|
49
|
+
id: triggerId,
|
|
50
|
+
className: `${baseClass}__header`,
|
|
51
|
+
"aria-expanded": isOpen,
|
|
52
|
+
"aria-controls": panelId,
|
|
53
|
+
onClick: toggle,
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__title`, children: resolvedTitle }),
|
|
56
|
+
total > 0 && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__count`, children: [
|
|
57
|
+
completed,
|
|
58
|
+
"/",
|
|
59
|
+
total
|
|
60
|
+
] }),
|
|
61
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__chevron material-symbols-rounded`, "aria-hidden": "true", children: "expand_more" })
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ jsx(
|
|
66
|
+
"div",
|
|
67
|
+
{
|
|
68
|
+
className: `${baseClass}__panel`,
|
|
69
|
+
id: panelId,
|
|
70
|
+
role: "region",
|
|
71
|
+
"aria-labelledby": triggerId,
|
|
72
|
+
children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children: /* @__PURE__ */ jsx("ol", { className: `${baseClass}__steps`, children: steps.map((step, index) => {
|
|
73
|
+
const status = step.status ?? "pending";
|
|
74
|
+
return /* @__PURE__ */ jsxs(
|
|
75
|
+
"li",
|
|
76
|
+
{
|
|
77
|
+
className: `${baseClass}__step ${baseClass}__step--${status}`,
|
|
78
|
+
"aria-current": status === "active" ? "step" : void 0,
|
|
79
|
+
children: [
|
|
80
|
+
/* @__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] }) }),
|
|
81
|
+
/* @__PURE__ */ jsxs("span", { className: `${baseClass}__step-body`, children: [
|
|
82
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__label`, children: step.label }),
|
|
83
|
+
step.detail && /* @__PURE__ */ jsx("span", { className: `${baseClass}__detail`, children: step.detail })
|
|
84
|
+
] }),
|
|
85
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__sr`, children: STEP_STATUS_TEXT[status] })
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
index
|
|
89
|
+
);
|
|
90
|
+
}) }) })
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
] });
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
AgentPlan.displayName = "AgentPlan";
|
|
97
|
+
export {
|
|
98
|
+
AgentPlan
|
|
99
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
DATA TABLE COMPONENT
|
|
3
|
+
The wired table block: toolbar with search
|
|
4
|
+
and filter slot, sortable headers, selection,
|
|
5
|
+
pagination footer. Row and cell styling all
|
|
6
|
+
comes from the underlying Table — this file
|
|
7
|
+
only styles the chrome around it.
|
|
8
|
+
============================================ */
|
|
9
|
+
|
|
10
|
+
.ds-data-table {
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
gap: var(--gap-sm);
|
|
14
|
+
width: 100%;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* ============================================
|
|
18
|
+
TOOLBAR
|
|
19
|
+
============================================ */
|
|
20
|
+
|
|
21
|
+
.ds-data-table__toolbar {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: space-between;
|
|
25
|
+
gap: var(--gap-sm);
|
|
26
|
+
flex-wrap: wrap;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.ds-data-table__filters {
|
|
30
|
+
display: flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
gap: var(--gap-sm);
|
|
33
|
+
flex-wrap: wrap;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* The search field sits at the end of the toolbar even with no filters */
|
|
37
|
+
.ds-data-table__search {
|
|
38
|
+
margin-left: auto;
|
|
39
|
+
max-width: 240px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* ============================================
|
|
43
|
+
SORTABLE HEADERS
|
|
44
|
+
The button fills the header cell so the whole
|
|
45
|
+
label is the click target.
|
|
46
|
+
============================================ */
|
|
47
|
+
|
|
48
|
+
.ds-data-table__sort {
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: var(--gap-xxs);
|
|
52
|
+
padding: 0;
|
|
53
|
+
background: none;
|
|
54
|
+
border: none;
|
|
55
|
+
cursor: pointer;
|
|
56
|
+
color: inherit;
|
|
57
|
+
font: inherit;
|
|
58
|
+
letter-spacing: inherit;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.ds-data-table__sort:focus-visible {
|
|
62
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
63
|
+
outline-offset: 2px;
|
|
64
|
+
border-radius: var(--radius-xxs);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ds-data-table__sort-icon {
|
|
68
|
+
--icon-size: var(--icon-size-sm);
|
|
69
|
+
|
|
70
|
+
color: var(--color-icon-secondary);
|
|
71
|
+
opacity: 0;
|
|
72
|
+
transition: opacity var(--motion-duration-fast) var(--motion-ease-standard);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.ds-data-table__sort:hover .ds-data-table__sort-icon,
|
|
76
|
+
.ds-data-table__sort:focus-visible .ds-data-table__sort-icon,
|
|
77
|
+
.ds-data-table__sort-icon--active {
|
|
78
|
+
opacity: 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.ds-data-table__sort-icon--active {
|
|
82
|
+
color: var(--color-text-primary);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* ============================================
|
|
86
|
+
FOOTER
|
|
87
|
+
============================================ */
|
|
88
|
+
|
|
89
|
+
.ds-data-table__footer {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: space-between;
|
|
93
|
+
gap: var(--gap-sm);
|
|
94
|
+
flex-wrap: wrap;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.ds-data-table__count {
|
|
98
|
+
color: var(--color-text-tertiary);
|
|
99
|
+
font-family: var(--font-paragraph-sm-family);
|
|
100
|
+
font-size: var(--font-paragraph-sm-size);
|
|
101
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
102
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
103
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
104
|
+
font-variant-numeric: tabular-nums;
|
|
105
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface DataTableColumn {
|
|
3
|
+
/** Unique column identifier, used as the key into each row's values. */
|
|
4
|
+
key: string;
|
|
5
|
+
/** Header label displayed in the column header. */
|
|
6
|
+
header: React.ReactNode;
|
|
7
|
+
/** Whether clicking this header sorts by the column. */
|
|
8
|
+
sortable?: boolean;
|
|
9
|
+
/** Optional column width (CSS value like '200px', '30%', 'auto'). */
|
|
10
|
+
width?: string;
|
|
11
|
+
/** Text alignment for cells in this column. */
|
|
12
|
+
align?: 'left' | 'center' | 'right';
|
|
13
|
+
/** Render the cell for a row; defaults to the row's raw value for this key. */
|
|
14
|
+
render?: (row: DataTableRow) => React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
export interface DataTableRow {
|
|
17
|
+
/** Unique row identifier. */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Raw values keyed by column key — used for sorting, searching, and default rendering. */
|
|
20
|
+
values: Record<string, string | number | null | undefined>;
|
|
21
|
+
}
|
|
22
|
+
export interface DataTableSort {
|
|
23
|
+
/** The column being sorted. */
|
|
24
|
+
key: string;
|
|
25
|
+
/** Sort direction. */
|
|
26
|
+
direction: 'asc' | 'desc';
|
|
27
|
+
}
|
|
28
|
+
/** Props owned by DataTable itself — everything else falls through to the root element. */
|
|
29
|
+
type DataTableOwnProps = {
|
|
30
|
+
/** Column definitions. */
|
|
31
|
+
columns: DataTableColumn[];
|
|
32
|
+
/** Row data, as raw values the table can sort and search. */
|
|
33
|
+
rows: DataTableRow[];
|
|
34
|
+
/** Rows per page. Setting this turns on the built-in pagination. */
|
|
35
|
+
pageSize?: number;
|
|
36
|
+
/** Adds a checkbox column with a select-all header. */
|
|
37
|
+
selectable?: boolean;
|
|
38
|
+
/** Selected row ids for controlled use. Pair with `onSelectionChange`. */
|
|
39
|
+
selectedIds?: string[];
|
|
40
|
+
/** Initially selected row ids for uncontrolled use. */
|
|
41
|
+
defaultSelectedIds?: string[];
|
|
42
|
+
/** Fires with the full list of selected row ids after every change. */
|
|
43
|
+
onSelectionChange?: (ids: string[]) => void;
|
|
44
|
+
/** Sort state for controlled use. Pair with `onSortChange`; `null` means unsorted. */
|
|
45
|
+
sort?: DataTableSort | null;
|
|
46
|
+
/** Initial sort state for uncontrolled use. */
|
|
47
|
+
defaultSort?: DataTableSort;
|
|
48
|
+
/** Fires with the new sort state — `null` when a third click clears the sort. */
|
|
49
|
+
onSortChange?: (sort: DataTableSort | null) => void;
|
|
50
|
+
/** Shows the built-in search field, matching against every column's raw value. */
|
|
51
|
+
searchable?: boolean;
|
|
52
|
+
/** Placeholder for the search field. */
|
|
53
|
+
searchPlaceholder?: string;
|
|
54
|
+
/** Slot beside the search field for consumer-owned filter controls. */
|
|
55
|
+
toolbar?: React.ReactNode;
|
|
56
|
+
/** Visual size, passed through to the underlying Table. */
|
|
57
|
+
size?: 'default' | 'compact';
|
|
58
|
+
/** Alternating row backgrounds, passed through to the underlying Table. */
|
|
59
|
+
striped?: boolean;
|
|
60
|
+
/** Accessible caption for the underlying table (visually hidden). */
|
|
61
|
+
caption?: string;
|
|
62
|
+
/** What to render when no rows match — defaults to a built-in empty state. */
|
|
63
|
+
emptyState?: React.ReactNode;
|
|
64
|
+
/** Additional CSS classes */
|
|
65
|
+
className?: string;
|
|
66
|
+
};
|
|
67
|
+
export interface DataTableProps extends DataTableOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof DataTableOwnProps> {
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* DataTable is the wired version of Table: sorting on header click, a search
|
|
71
|
+
* field, row selection with a select-all header, client-side pagination, and
|
|
72
|
+
* an empty state — assembled from Table, Pagination, Checkbox, Input and
|
|
73
|
+
* EmptyState so a working data view is one component, not an afternoon of
|
|
74
|
+
* plumbing.
|
|
75
|
+
*
|
|
76
|
+
* Rows carry raw values rather than rendered nodes; a column's `render`
|
|
77
|
+
* turns them into cells when text isn't enough. For server-driven data,
|
|
78
|
+
* control `sort` and slot your own filters into `toolbar`.
|
|
79
|
+
*/
|
|
80
|
+
export declare const DataTable: React.ForwardRefExoticComponent<DataTableProps & React.RefAttributes<HTMLDivElement>>;
|
|
81
|
+
export {};
|