@robr0/design-system 0.2.0 → 0.4.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 +33 -28
- package/components/Accordion/Accordion.js +0 -1
- package/components/AgentStatus/AgentStatus.css +436 -0
- package/components/AgentStatus/AgentStatus.d.ts +37 -0
- package/components/AgentStatus/AgentStatus.js +53 -0
- package/components/AgentStatus/AgentStatusPatterns.d.ts +17 -0
- package/components/AgentStatus/AgentStatusPatterns.js +20 -0
- package/components/AlertDialog/AlertDialog.css +5 -5
- package/components/Avatar/Avatar.js +1 -0
- package/components/Breadcrumb/Breadcrumb.d.ts +7 -1
- package/components/Breadcrumb/Breadcrumb.js +3 -2
- package/components/Button/Button.css +18 -0
- package/components/Button/Button.d.ts +20 -2
- package/components/Button/Button.js +13 -3
- package/components/ButtonGroup/ButtonGroup.js +2 -9
- package/components/Card/Card.css +6 -0
- package/components/Checkbox/Checkbox.d.ts +17 -3
- package/components/CircularButton/CircularButton.css +11 -0
- package/components/CircularButton/CircularButton.d.ts +15 -3
- package/components/CircularButton/CircularButton.js +19 -6
- package/components/CodeBlock/CodeBlock.js +10 -1
- package/components/ColorPicker/ColorPicker.css +278 -0
- package/components/ColorPicker/ColorPicker.d.ts +50 -0
- package/components/ColorPicker/ColorPicker.js +338 -0
- package/components/Combobox/Combobox.css +0 -36
- package/components/Combobox/Combobox.d.ts +10 -2
- package/components/Combobox/Combobox.js +90 -82
- package/components/CommandPalette/CommandPalette.css +1 -15
- package/components/CommandPalette/CommandPalette.js +6 -5
- package/components/ContextMenu/ContextMenu.css +258 -0
- package/components/ContextMenu/ContextMenu.d.ts +26 -0
- package/components/ContextMenu/ContextMenu.js +350 -0
- package/components/DateInput/DateInput.css +0 -36
- package/components/DateInput/DateInput.d.ts +5 -1
- package/components/DateInput/DateInput.js +37 -33
- package/components/DatePicker/DatePicker.js +45 -34
- package/components/Dialog/Dialog.css +5 -5
- package/components/Dialog/Dialog.js +5 -4
- package/components/Drawer/Drawer.js +7 -2
- package/components/Dropdown/Dropdown.css +2 -40
- package/components/Dropdown/Dropdown.d.ts +10 -2
- package/components/Dropdown/Dropdown.js +119 -109
- package/components/DropdownMenu/DropdownMenu.css +2 -4
- package/components/DropdownMenu/DropdownMenu.js +10 -7
- package/components/Field/Field.css +80 -0
- package/components/Field/Field.d.ts +50 -0
- package/components/Field/Field.js +58 -0
- package/components/Field/FieldContext.d.ts +42 -0
- package/components/Field/FieldContext.js +7 -0
- package/components/FileInput/FileInput.css +0 -36
- package/components/FileInput/FileInput.d.ts +5 -1
- package/components/FileInput/FileInput.js +111 -103
- package/components/Input/Input.css +0 -43
- package/components/Input/Input.d.ts +5 -1
- package/components/Input/Input.js +51 -46
- package/components/Kbd/Kbd.css +28 -0
- package/components/Kbd/Kbd.d.ts +19 -0
- package/components/Kbd/Kbd.js +14 -0
- package/components/LinkList/LinkList.d.ts +1 -0
- package/components/Popover/Popover.d.ts +0 -6
- package/components/Popover/Popover.js +22 -16
- package/components/ProgressBar/ProgressBar.js +1 -1
- package/components/RadioButton/RadioButton.d.ts +17 -3
- package/components/Reasoning/Reasoning.css +152 -0
- package/components/Reasoning/Reasoning.d.ts +36 -0
- package/components/Reasoning/Reasoning.js +69 -0
- package/components/SelectionCard/SelectionCard.css +6 -2
- package/components/SelectionCard/SelectionCard.d.ts +5 -1
- package/components/Skeleton/Skeleton.css +2 -0
- package/components/Slider/Slider.d.ts +5 -1
- package/components/Spinner/Spinner.css +11 -0
- package/components/Spinner/Spinner.d.ts +2 -2
- package/components/Swatch/Swatch.css +52 -0
- package/components/Swatch/Swatch.d.ts +34 -0
- package/components/Swatch/Swatch.js +44 -0
- package/components/Table/Table.css +19 -0
- package/components/Table/Table.js +1 -1
- package/components/Textarea/Textarea.css +0 -43
- package/components/Textarea/Textarea.d.ts +5 -1
- package/components/Textarea/Textarea.js +37 -35
- package/components/Timeline/Timeline.d.ts +2 -0
- package/components/ToggleGroup/ToggleGroup.d.ts +10 -2
- package/components/ToggleSwitch/ToggleSwitch.css +7 -2
- package/components/ToggleSwitch/ToggleSwitch.d.ts +10 -2
- package/components/ToolCall/ToolCall.css +213 -0
- package/components/ToolCall/ToolCall.d.ts +43 -0
- package/components/ToolCall/ToolCall.js +89 -0
- package/components/registry.d.ts +47 -10
- package/components/registry.js +5 -1
- package/components/registry.json +523 -56
- package/components/registry.json.d.ts +523 -56
- package/components/registry.json.js +4 -1
- package/index.d.ts +12 -1
- package/index.js +24 -1
- package/package.json +8 -4
- package/tokens/registry.json +1 -0
- package/tokens/registry.json.d.ts +1 -0
- package/tokens/registry.json.js +1 -1
- package/tokens/tokens-motion.css +3 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from "react";
|
|
3
|
+
import { Field } from "../Field/Field.js";
|
|
3
4
|
import "./Textarea.css";
|
|
4
5
|
const Textarea = React.forwardRef(
|
|
5
6
|
({
|
|
@@ -37,44 +38,45 @@ const Textarea = React.forwardRef(
|
|
|
37
38
|
};
|
|
38
39
|
const inputId = id || name || label?.toLowerCase().replace(/\s+/g, "-");
|
|
39
40
|
const charCount = value?.length || 0;
|
|
40
|
-
return /* @__PURE__ */
|
|
41
|
-
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
Field,
|
|
43
|
+
{
|
|
44
|
+
className: classes,
|
|
42
45
|
label,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
{
|
|
51
|
-
...rest,
|
|
52
|
-
ref,
|
|
53
|
-
className: `${baseClass}__field`,
|
|
54
|
-
id: inputId,
|
|
55
|
-
name,
|
|
56
|
-
value,
|
|
57
|
-
placeholder,
|
|
58
|
-
rows,
|
|
59
|
-
disabled,
|
|
60
|
-
required,
|
|
61
|
-
maxLength,
|
|
62
|
-
"aria-label": ariaLabel || rest["aria-label"] || label,
|
|
63
|
-
"aria-invalid": error,
|
|
64
|
-
"aria-describedby": helperText ? `${inputId}-helper` : rest["aria-describedby"],
|
|
65
|
-
onChange: handleChange,
|
|
66
|
-
style: { resize, ...style }
|
|
67
|
-
}
|
|
68
|
-
),
|
|
69
|
-
/* @__PURE__ */ jsxs("div", { className: `${baseClass}__footer`, children: [
|
|
70
|
-
helperText && /* @__PURE__ */ jsx("p", { className: `${baseClass}__helper`, id: `${inputId}-helper`, children: helperText }),
|
|
71
|
-
maxLength && /* @__PURE__ */ jsxs("span", { className: `${baseClass}__counter`, "aria-live": "polite", "aria-atomic": "true", children: [
|
|
46
|
+
helperText,
|
|
47
|
+
error,
|
|
48
|
+
required,
|
|
49
|
+
disabled,
|
|
50
|
+
size,
|
|
51
|
+
id: inputId,
|
|
52
|
+
aside: maxLength ? /* @__PURE__ */ jsxs("span", { className: `${baseClass}__counter`, "aria-live": "polite", "aria-atomic": "true", children: [
|
|
72
53
|
charCount,
|
|
73
54
|
"/",
|
|
74
55
|
maxLength
|
|
75
|
-
] })
|
|
76
|
-
|
|
77
|
-
|
|
56
|
+
] }) : void 0,
|
|
57
|
+
children: /* @__PURE__ */ jsx(
|
|
58
|
+
"textarea",
|
|
59
|
+
{
|
|
60
|
+
...rest,
|
|
61
|
+
ref,
|
|
62
|
+
className: `${baseClass}__field`,
|
|
63
|
+
id: inputId,
|
|
64
|
+
name,
|
|
65
|
+
value,
|
|
66
|
+
placeholder,
|
|
67
|
+
rows,
|
|
68
|
+
disabled,
|
|
69
|
+
required,
|
|
70
|
+
maxLength,
|
|
71
|
+
"aria-label": ariaLabel || rest["aria-label"] || label,
|
|
72
|
+
"aria-invalid": error,
|
|
73
|
+
"aria-describedby": helperText ? `${inputId}-helper` : rest["aria-describedby"],
|
|
74
|
+
onChange: handleChange,
|
|
75
|
+
style: { resize, ...style }
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
);
|
|
78
80
|
}
|
|
79
81
|
);
|
|
80
82
|
Textarea.displayName = "Textarea";
|
|
@@ -35,6 +35,7 @@ export interface TimelineCompany {
|
|
|
35
35
|
}
|
|
36
36
|
/** Default variant — a flat sequence of steps/events with dot, badge, or icon markers. */
|
|
37
37
|
export interface TimelineDefaultProps {
|
|
38
|
+
/** Selects the flat step/event layout — the default when omitted */
|
|
38
39
|
variant?: 'default';
|
|
39
40
|
/** Ordered list of steps/events */
|
|
40
41
|
items: TimelineItem[];
|
|
@@ -47,6 +48,7 @@ export interface TimelineDefaultProps {
|
|
|
47
48
|
}
|
|
48
49
|
/** Company variant — grouped roles under a logo, for résumé/pipeline histories. */
|
|
49
50
|
export interface TimelineCompanyProps {
|
|
51
|
+
/** Selects the grouped layout: roles nested under a company logo */
|
|
50
52
|
variant: 'company';
|
|
51
53
|
/** Ordered list of company/tool entries */
|
|
52
54
|
items: TimelineCompany[];
|
|
@@ -23,9 +23,17 @@ type ToggleGroupOwnProps = {
|
|
|
23
23
|
onValueChange?: (value: string | string[]) => void;
|
|
24
24
|
/** Additional CSS classes */
|
|
25
25
|
className?: string;
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Legacy change handler, kept for backwards compatibility.
|
|
28
|
+
*
|
|
29
|
+
* @deprecated Use `onValueChange` instead.
|
|
30
|
+
*/
|
|
27
31
|
onChange?: (value: string | string[]) => void;
|
|
28
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Legacy accessible-name prop.
|
|
34
|
+
*
|
|
35
|
+
* @deprecated Pass the native `aria-label` attribute instead.
|
|
36
|
+
*/
|
|
29
37
|
ariaLabel?: string;
|
|
30
38
|
};
|
|
31
39
|
export interface ToggleGroupProps extends ToggleGroupOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ToggleGroupOwnProps> {
|
|
@@ -59,7 +59,10 @@
|
|
|
59
59
|
Set via --icon-size (not font-size): .material-symbols-rounded derives
|
|
60
60
|
font-size, width, and height from it together. Overriding font-size
|
|
61
61
|
alone leaves the box at the 24px default, so the glyph hangs off-centre
|
|
62
|
-
inside the thumb.
|
|
62
|
+
inside the thumb.
|
|
63
|
+
|
|
64
|
+
ds-allow(icon-size): 14px glyph inside the 20px thumb — the smallest
|
|
65
|
+
scale step would fill it edge to edge. */
|
|
63
66
|
--icon-size: 14px;
|
|
64
67
|
color: var(--color-action-primary-bg);
|
|
65
68
|
}
|
|
@@ -123,7 +126,9 @@
|
|
|
123
126
|
|
|
124
127
|
.ds-toggle-switch--compact .ds-toggle-switch__thumb-icon {
|
|
125
128
|
/* Off-scale for the same reason as the default size — the compact thumb
|
|
126
|
-
is only 16x16.
|
|
129
|
+
is only 16x16.
|
|
130
|
+
|
|
131
|
+
ds-allow(icon-size): 12px glyph inside the 16px compact thumb. */
|
|
127
132
|
--icon-size: 12px;
|
|
128
133
|
}
|
|
129
134
|
|
|
@@ -13,9 +13,17 @@ type ToggleSwitchOwnProps = {
|
|
|
13
13
|
onCheckedChange?: (checked: boolean) => void;
|
|
14
14
|
/** Additional CSS classes */
|
|
15
15
|
className?: string;
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Legacy change handler, kept for backwards compatibility.
|
|
18
|
+
*
|
|
19
|
+
* @deprecated Use `onCheckedChange` instead.
|
|
20
|
+
*/
|
|
17
21
|
onChange?: (checked: boolean) => void;
|
|
18
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Legacy accessible-name prop.
|
|
24
|
+
*
|
|
25
|
+
* @deprecated Pass the native `aria-label` attribute instead.
|
|
26
|
+
*/
|
|
19
27
|
ariaLabel?: string;
|
|
20
28
|
};
|
|
21
29
|
export interface ToggleSwitchProps extends ToggleSwitchOwnProps, Omit<React.ComponentPropsWithoutRef<'button'>, keyof ToggleSwitchOwnProps | 'type'> {
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/* ============================================
|
|
2
|
+
TOOL CALL COMPONENT
|
|
3
|
+
One tool invocation: a skimmable header row
|
|
4
|
+
and, behind a disclosure, the arguments and
|
|
5
|
+
the result.
|
|
6
|
+
|
|
7
|
+
The container stays neutral — colour lives in
|
|
8
|
+
the indicator and the status word, so a long
|
|
9
|
+
run of calls reads as a list rather than a
|
|
10
|
+
wall of tinted cards. The two states a person
|
|
11
|
+
has to act on, pending and error, also take a
|
|
12
|
+
coloured border.
|
|
13
|
+
============================================ */
|
|
14
|
+
|
|
15
|
+
.ds-tool-call {
|
|
16
|
+
--ds-tool-call-color: var(--color-text-secondary);
|
|
17
|
+
--ds-tool-call-border: var(--color-bg-container-border);
|
|
18
|
+
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
width: 100%;
|
|
22
|
+
background-color: var(--color-bg-container-primary);
|
|
23
|
+
border: var(--border-xs) solid var(--ds-tool-call-border);
|
|
24
|
+
border-radius: var(--radius-md);
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* ============================================
|
|
29
|
+
HEADER
|
|
30
|
+
============================================ */
|
|
31
|
+
|
|
32
|
+
.ds-tool-call__header {
|
|
33
|
+
display: flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
gap: var(--gap-sm);
|
|
36
|
+
width: 100%;
|
|
37
|
+
padding: var(--padding-xs) var(--padding-sm-md);
|
|
38
|
+
background: none;
|
|
39
|
+
border: none;
|
|
40
|
+
text-align: left;
|
|
41
|
+
cursor: pointer;
|
|
42
|
+
transition: background-color var(--motion-duration-fast) var(--motion-ease-standard);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.ds-tool-call__header:hover {
|
|
46
|
+
background-color: var(--color-bg-container-secondary);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.ds-tool-call__header:focus-visible {
|
|
50
|
+
outline: 2px solid var(--color-action-primary-bg);
|
|
51
|
+
outline-offset: -2px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* No panel to open — the row is a plain div and must not look pressable */
|
|
55
|
+
.ds-tool-call__header--static {
|
|
56
|
+
cursor: default;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ds-tool-call__header--static:hover {
|
|
60
|
+
background-color: transparent;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-tool-call__indicator {
|
|
64
|
+
display: inline-flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
justify-content: center;
|
|
67
|
+
flex: none;
|
|
68
|
+
color: var(--ds-tool-call-color);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.ds-tool-call__indicator .material-symbols-rounded {
|
|
72
|
+
--icon-size: var(--icon-size-sm);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* The tool name is an identifier, so it takes the same monospace
|
|
76
|
+
context CodeBlock uses — the one place the system leaves Nunito Sans */
|
|
77
|
+
.ds-tool-call__name {
|
|
78
|
+
flex: none;
|
|
79
|
+
font-family: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;
|
|
80
|
+
font-size: var(--font-paragraph-sm-size);
|
|
81
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
82
|
+
color: var(--color-text-primary);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ds-tool-call__summary {
|
|
86
|
+
flex: 1 1 auto;
|
|
87
|
+
min-width: 0;
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
text-overflow: ellipsis;
|
|
90
|
+
white-space: nowrap;
|
|
91
|
+
color: var(--color-text-tertiary);
|
|
92
|
+
font-family: var(--font-paragraph-sm-family);
|
|
93
|
+
font-size: var(--font-paragraph-sm-size);
|
|
94
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
95
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
96
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.ds-tool-call__status {
|
|
100
|
+
flex: none;
|
|
101
|
+
margin-left: auto;
|
|
102
|
+
color: var(--ds-tool-call-color);
|
|
103
|
+
font-family: var(--font-paragraph-sm-em-family);
|
|
104
|
+
font-size: var(--font-paragraph-sm-em-size);
|
|
105
|
+
font-weight: var(--font-paragraph-sm-em-weight);
|
|
106
|
+
line-height: var(--font-paragraph-sm-em-line-height);
|
|
107
|
+
letter-spacing: var(--font-paragraph-sm-em-letter-spacing);
|
|
108
|
+
white-space: nowrap;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* A summary already claims the free space; without one the status still
|
|
112
|
+
needs pushing to the right, which the auto margin above handles */
|
|
113
|
+
.ds-tool-call__summary ~ .ds-tool-call__status {
|
|
114
|
+
margin-left: 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.ds-tool-call__duration {
|
|
118
|
+
flex: none;
|
|
119
|
+
color: var(--color-text-tertiary);
|
|
120
|
+
font-family: var(--font-paragraph-sm-family);
|
|
121
|
+
font-size: var(--font-paragraph-sm-size);
|
|
122
|
+
font-weight: var(--font-paragraph-sm-weight);
|
|
123
|
+
line-height: var(--font-paragraph-sm-line-height);
|
|
124
|
+
letter-spacing: var(--font-paragraph-sm-letter-spacing);
|
|
125
|
+
font-variant-numeric: tabular-nums;
|
|
126
|
+
white-space: nowrap;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.ds-tool-call__chevron {
|
|
130
|
+
--icon-size: var(--icon-size-sm);
|
|
131
|
+
|
|
132
|
+
flex: none;
|
|
133
|
+
color: var(--color-icon-secondary);
|
|
134
|
+
transition: transform var(--motion-duration-slow) var(--motion-ease-standard);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.ds-tool-call--open .ds-tool-call__chevron {
|
|
138
|
+
transform: rotate(180deg);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* ============================================
|
|
142
|
+
STATUSES
|
|
143
|
+
============================================ */
|
|
144
|
+
|
|
145
|
+
.ds-tool-call--pending {
|
|
146
|
+
--ds-tool-call-color: var(--color-status-warning-text);
|
|
147
|
+
--ds-tool-call-border: var(--color-status-warning-border);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.ds-tool-call--running {
|
|
151
|
+
--ds-tool-call-color: var(--color-status-info-text);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.ds-tool-call--success {
|
|
155
|
+
--ds-tool-call-color: var(--color-status-positive-text);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.ds-tool-call--error {
|
|
159
|
+
--ds-tool-call-color: var(--color-status-error-text);
|
|
160
|
+
--ds-tool-call-border: var(--color-status-error-border);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* ============================================
|
|
164
|
+
PANEL
|
|
165
|
+
============================================ */
|
|
166
|
+
|
|
167
|
+
.ds-tool-call__panel {
|
|
168
|
+
display: grid;
|
|
169
|
+
grid-template-rows: 0fr;
|
|
170
|
+
visibility: hidden;
|
|
171
|
+
transition:
|
|
172
|
+
grid-template-rows var(--motion-duration-slow) var(--motion-ease-standard),
|
|
173
|
+
visibility var(--motion-duration-slow) var(--motion-ease-standard);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.ds-tool-call--open .ds-tool-call__panel {
|
|
177
|
+
grid-template-rows: 1fr;
|
|
178
|
+
visibility: visible;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.ds-tool-call__content {
|
|
182
|
+
overflow: hidden;
|
|
183
|
+
min-height: 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.ds-tool-call--open .ds-tool-call__content {
|
|
187
|
+
padding: var(--padding-sm-md);
|
|
188
|
+
border-top: var(--border-xs) solid var(--color-divider);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.ds-tool-call__content > :first-child {
|
|
192
|
+
margin-top: 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.ds-tool-call__content > :last-child {
|
|
196
|
+
margin-bottom: 0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* ============================================
|
|
200
|
+
ACTIONS
|
|
201
|
+
Outside the panel, so a call awaiting approval
|
|
202
|
+
can be answered without expanding it first.
|
|
203
|
+
============================================ */
|
|
204
|
+
|
|
205
|
+
.ds-tool-call__actions {
|
|
206
|
+
display: flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: flex-end;
|
|
209
|
+
gap: var(--gap-sm);
|
|
210
|
+
padding: var(--padding-sm) var(--padding-sm-md);
|
|
211
|
+
border-top: var(--border-xs) solid var(--color-divider);
|
|
212
|
+
background-color: var(--color-bg-container-secondary);
|
|
213
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export type ToolCallStatus = 'pending' | 'running' | 'success' | 'error';
|
|
3
|
+
/** Props owned by ToolCall itself — everything else falls through to the root element. */
|
|
4
|
+
type ToolCallOwnProps = {
|
|
5
|
+
/** The tool that was invoked, shown in monospace. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** Where the call has got to. Drives the colour, the indicator, and the default status text. */
|
|
8
|
+
status?: ToolCallStatus;
|
|
9
|
+
/** One line describing this particular call, e.g. the target path or query. */
|
|
10
|
+
summary?: string;
|
|
11
|
+
/** How long the call took, e.g. "1.2s". Free text, so callers keep their own formatting. */
|
|
12
|
+
duration?: string;
|
|
13
|
+
/** Override the status text shown beside the indicator. */
|
|
14
|
+
statusLabel?: string;
|
|
15
|
+
/** Open state for controlled use. Pair with `onOpenChange`. */
|
|
16
|
+
open?: boolean;
|
|
17
|
+
/** Open state for uncontrolled use. */
|
|
18
|
+
defaultOpen?: boolean;
|
|
19
|
+
/** Fires whenever the panel opens or closes. */
|
|
20
|
+
onOpenChange?: (open: boolean) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Controls for a call awaiting a decision — allow, deny, always allow.
|
|
23
|
+
* Rendered outside the collapsible panel, so approving never requires
|
|
24
|
+
* expanding the call first.
|
|
25
|
+
*/
|
|
26
|
+
actions?: React.ReactNode;
|
|
27
|
+
/** Additional CSS classes */
|
|
28
|
+
className?: string;
|
|
29
|
+
/** The call's arguments and result. */
|
|
30
|
+
children?: React.ReactNode;
|
|
31
|
+
};
|
|
32
|
+
export interface ToolCallProps extends ToolCallOwnProps, Omit<React.ComponentPropsWithoutRef<'div'>, keyof ToolCallOwnProps> {
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* ToolCall is the record of one tool invocation: what ran, how it went, how
|
|
36
|
+
* long it took, and — behind a disclosure — the arguments it was given and
|
|
37
|
+
* what it returned.
|
|
38
|
+
*
|
|
39
|
+
* A run is mostly a list of these, so the collapsed header carries everything
|
|
40
|
+
* needed to skim it and the body holds everything needed to audit it.
|
|
41
|
+
*/
|
|
42
|
+
export declare const ToolCall: React.ForwardRefExoticComponent<ToolCallProps & React.RefAttributes<HTMLDivElement>>;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useId, useState, useCallback } from "react";
|
|
3
|
+
import { Spinner } from "../Spinner/Spinner.js";
|
|
4
|
+
import "./ToolCall.css";
|
|
5
|
+
import "../../fonts/material-symbols.css";
|
|
6
|
+
const DEFAULT_STATUS_LABELS = {
|
|
7
|
+
pending: "Needs approval",
|
|
8
|
+
running: "Running",
|
|
9
|
+
success: "Done",
|
|
10
|
+
error: "Failed"
|
|
11
|
+
};
|
|
12
|
+
const STATUS_ICONS = {
|
|
13
|
+
pending: "pause_circle",
|
|
14
|
+
success: "check_circle",
|
|
15
|
+
error: "error"
|
|
16
|
+
};
|
|
17
|
+
const ToolCall = React.forwardRef(
|
|
18
|
+
({
|
|
19
|
+
name,
|
|
20
|
+
status = "success",
|
|
21
|
+
summary,
|
|
22
|
+
duration,
|
|
23
|
+
statusLabel,
|
|
24
|
+
open,
|
|
25
|
+
defaultOpen = false,
|
|
26
|
+
onOpenChange,
|
|
27
|
+
actions,
|
|
28
|
+
className = "",
|
|
29
|
+
children,
|
|
30
|
+
...rest
|
|
31
|
+
}, ref) => {
|
|
32
|
+
const baseClass = "ds-tool-call";
|
|
33
|
+
const id = useId();
|
|
34
|
+
const panelId = `${id}-panel`;
|
|
35
|
+
const triggerId = `${id}-trigger`;
|
|
36
|
+
const isControlled = open !== void 0;
|
|
37
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
|
|
38
|
+
const isOpen = isControlled ? open : uncontrolledOpen;
|
|
39
|
+
const hasPanel = Boolean(children);
|
|
40
|
+
const toggle = useCallback(() => {
|
|
41
|
+
const next = !isOpen;
|
|
42
|
+
if (!isControlled) setUncontrolledOpen(next);
|
|
43
|
+
onOpenChange?.(next);
|
|
44
|
+
}, [isOpen, isControlled, onOpenChange]);
|
|
45
|
+
const classes = [
|
|
46
|
+
baseClass,
|
|
47
|
+
`${baseClass}--${status}`,
|
|
48
|
+
isOpen ? `${baseClass}--open` : "",
|
|
49
|
+
className
|
|
50
|
+
].filter(Boolean).join(" ");
|
|
51
|
+
const header = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
52
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__indicator`, "aria-hidden": "true", children: status === "running" ? /* @__PURE__ */ jsx(Spinner, { size: "sm", variant: "inherit" }) : /* @__PURE__ */ jsx("span", { className: "material-symbols-rounded", children: STATUS_ICONS[status] }) }),
|
|
53
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__name`, children: name }),
|
|
54
|
+
summary && /* @__PURE__ */ jsx("span", { className: `${baseClass}__summary`, children: summary }),
|
|
55
|
+
/* @__PURE__ */ jsx("span", { className: `${baseClass}__status`, children: statusLabel ?? DEFAULT_STATUS_LABELS[status] }),
|
|
56
|
+
duration && /* @__PURE__ */ jsx("span", { className: `${baseClass}__duration`, children: duration }),
|
|
57
|
+
hasPanel && /* @__PURE__ */ jsx("span", { className: `${baseClass}__chevron material-symbols-rounded`, "aria-hidden": "true", children: "expand_more" })
|
|
58
|
+
] });
|
|
59
|
+
return /* @__PURE__ */ jsxs("div", { ...rest, ref, className: classes, children: [
|
|
60
|
+
hasPanel ? /* @__PURE__ */ jsx(
|
|
61
|
+
"button",
|
|
62
|
+
{
|
|
63
|
+
type: "button",
|
|
64
|
+
id: triggerId,
|
|
65
|
+
className: `${baseClass}__header`,
|
|
66
|
+
"aria-expanded": isOpen,
|
|
67
|
+
"aria-controls": panelId,
|
|
68
|
+
onClick: toggle,
|
|
69
|
+
children: header
|
|
70
|
+
}
|
|
71
|
+
) : /* @__PURE__ */ jsx("div", { className: `${baseClass}__header ${baseClass}__header--static`, children: header }),
|
|
72
|
+
hasPanel && /* @__PURE__ */ jsx(
|
|
73
|
+
"div",
|
|
74
|
+
{
|
|
75
|
+
className: `${baseClass}__panel`,
|
|
76
|
+
id: panelId,
|
|
77
|
+
role: "region",
|
|
78
|
+
"aria-labelledby": triggerId,
|
|
79
|
+
children: /* @__PURE__ */ jsx("div", { className: `${baseClass}__content`, children })
|
|
80
|
+
}
|
|
81
|
+
),
|
|
82
|
+
actions && /* @__PURE__ */ jsx("div", { className: `${baseClass}__actions`, children: actions })
|
|
83
|
+
] });
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
ToolCall.displayName = "ToolCall";
|
|
87
|
+
export {
|
|
88
|
+
ToolCall
|
|
89
|
+
};
|
package/components/registry.d.ts
CHANGED
|
@@ -1,19 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* COMPONENT REGISTRY — the single source of truth for the public
|
|
3
|
-
* component
|
|
2
|
+
* COMPONENT REGISTRY — the single source of truth for the public component
|
|
3
|
+
* list, count, and per-component metadata.
|
|
4
|
+
*
|
|
5
|
+
* The data lives in registry.json. Each entry in `components` carries:
|
|
6
|
+
*
|
|
7
|
+
* name the folder under src/components (also the exported name)
|
|
8
|
+
* label the display name — "Navigation" for the Nav folder
|
|
9
|
+
* slug the website route segment — stored, not derived, so the
|
|
10
|
+
* Nav → navigation exception is plain data rather than a
|
|
11
|
+
* special case duplicated across validators
|
|
12
|
+
* description one line, used for the page title, the sidebar search index,
|
|
13
|
+
* and anywhere the component is summarised
|
|
14
|
+
* category one of `componentCategories`
|
|
15
|
+
* client whether the component declares 'use client' — i.e. whether it
|
|
16
|
+
* uses hooks or defines handlers. Presentational components are
|
|
17
|
+
* deliberately false so consumers can render them from a React
|
|
18
|
+
* Server Component.
|
|
4
19
|
*
|
|
5
|
-
* The data lives in registry.json: `components` is the official list of
|
|
6
|
-
* public components (one entry per folder in src/components), and
|
|
7
20
|
* `docOnlyHelpers` names the internal documentation helpers that are
|
|
8
21
|
* deliberately excluded from the public count.
|
|
9
22
|
*
|
|
10
|
-
* scripts/validate-component-registry.mjs compares the registry against
|
|
11
|
-
*
|
|
12
|
-
*
|
|
23
|
+
* scripts/validate-component-registry.mjs compares the registry against the
|
|
24
|
+
* filesystem on every build (library, Storybook, and website), so it cannot
|
|
25
|
+
* silently drift from reality.
|
|
26
|
+
*
|
|
27
|
+
* Anywhere a component count is displayed — the Storybook overview, the
|
|
28
|
+
* website mega-nav, case studies — import COMPONENT_COUNT from here. Never
|
|
29
|
+
* hardcode the number.
|
|
30
|
+
*/
|
|
31
|
+
export interface ComponentMeta {
|
|
32
|
+
/** Folder under src/components, and the exported component name */
|
|
33
|
+
name: string;
|
|
34
|
+
/** Display name — may differ from `name` (Nav → "Navigation") */
|
|
35
|
+
label: string;
|
|
36
|
+
/** Website route segment under /components */
|
|
37
|
+
slug: string;
|
|
38
|
+
/** One-line summary, used for page titles and search */
|
|
39
|
+
description: string;
|
|
40
|
+
/** Grouping — one of `componentCategories` */
|
|
41
|
+
category: string;
|
|
42
|
+
/** Whether the component declares 'use client' */
|
|
43
|
+
client: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** Full metadata for every public component, alphabetical by name. */
|
|
46
|
+
export declare const componentMetadata: readonly ComponentMeta[];
|
|
47
|
+
/** The categories a component may belong to. */
|
|
48
|
+
export declare const componentCategories: readonly string[];
|
|
49
|
+
/**
|
|
50
|
+
* The official public component list, names only.
|
|
13
51
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* here. Never hardcode the number.
|
|
52
|
+
* Unchanged in shape from before the metadata migration, so every existing
|
|
53
|
+
* consumer keeps working without an edit.
|
|
17
54
|
*/
|
|
18
55
|
export declare const componentRegistry: readonly string[];
|
|
19
56
|
/** The official public component count. */
|
package/components/registry.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import registry from "./registry.json.js";
|
|
2
|
-
const
|
|
2
|
+
const componentMetadata = registry.components;
|
|
3
|
+
const componentCategories = registry.categories;
|
|
4
|
+
const componentRegistry = registry.components.map((c) => c.name);
|
|
3
5
|
const COMPONENT_COUNT = registry.components.length;
|
|
4
6
|
export {
|
|
5
7
|
COMPONENT_COUNT,
|
|
8
|
+
componentCategories,
|
|
9
|
+
componentMetadata,
|
|
6
10
|
componentRegistry
|
|
7
11
|
};
|