@corbits/react-ui 0.1.0 → 0.2.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/LICENSE +174 -499
- package/README.md +228 -85
- package/dist/blocks/login/auth-layout.d.ts +1 -1
- package/dist/blocks/login/auth-layout.js +3 -33
- package/dist/blocks/login/login-form.js +6 -119
- package/dist/hooks/use-command-palette-navigation.js +18 -17
- package/dist/hooks/use-controllable-state.d.ts +2 -2
- package/dist/hooks/use-controllable-state.js +23 -15
- package/dist/hooks/use-delayed-autofocus.js +10 -11
- package/dist/hooks/use-dismissable-popover.d.ts +2 -2
- package/dist/hooks/use-dismissable-popover.js +21 -29
- package/dist/hooks/use-list-selection.js +54 -85
- package/dist/hooks/use-prefers-reduced-motion.js +8 -4
- package/dist/hooks/use-scroll-current-into-view.js +5 -7
- package/dist/index.d.ts +0 -11
- package/dist/index.js +10 -19
- package/dist/lib/artifact.js +16 -35
- package/dist/lib/chart-geometry.js +33 -20
- package/dist/lib/chart-palette.js +17 -31
- package/dist/lib/chat-message.js +32 -13
- package/dist/lib/chat-parts.js +2 -1
- package/dist/lib/csv.js +42 -26
- package/dist/lib/metrics.js +30 -48
- package/dist/lib/now-item.js +26 -25
- package/dist/lib/relative-time.js +14 -29
- package/dist/lib/theme.js +32 -30
- package/dist/lib/url.js +9 -8
- package/dist/lib/workflow-display-flow.js +37 -33
- package/dist/lib/workflow-registry.d.ts +0 -41
- package/dist/lib/workflow-registry.js +13 -23
- package/dist/lib/workflow-run-error.js +16 -20
- package/dist/lib/workflow-run-progress.js +94 -52
- package/dist/lib/workflow-run.js +17 -13
- package/dist/styles.css +11 -11
- package/dist/test/render-hook.js +11 -12
- package/dist/theme.css +51 -14
- package/dist/ui/agent-turn.d.ts +1 -1
- package/dist/ui/agent-turn.js +4 -37
- package/dist/ui/animated-number.js +15 -28
- package/dist/ui/approval-card.js +5 -90
- package/dist/ui/artifact-body.js +47 -125
- package/dist/ui/artifact-notice.d.ts +1 -1
- package/dist/ui/artifact-notice.js +9 -16
- package/dist/ui/avatar.d.ts +1 -1
- package/dist/ui/avatar.js +11 -48
- package/dist/ui/badge.js +4 -12
- package/dist/ui/bar-chart.d.ts +1 -1
- package/dist/ui/bar-chart.js +22 -74
- package/dist/ui/block-card.js +7 -45
- package/dist/ui/boot-screen.d.ts +1 -1
- package/dist/ui/boot-screen.js +4 -33
- package/dist/ui/bulk-action-bar.d.ts +1 -1
- package/dist/ui/bulk-action-bar.js +14 -33
- package/dist/ui/button.js +10 -24
- package/dist/ui/card.js +5 -25
- package/dist/ui/category-bars.js +14 -59
- package/dist/ui/chart-frame.d.ts +2 -2
- package/dist/ui/chart-frame.js +6 -85
- package/dist/ui/chat-composer.js +4 -16
- package/dist/ui/chat-dock-timing.js +7 -3
- package/dist/ui/chat-input.js +20 -100
- package/dist/ui/chat-panel.d.ts +1 -1
- package/dist/ui/chat-panel.js +7 -41
- package/dist/ui/chat-thread.js +13 -31
- package/dist/ui/checkbox.js +10 -52
- package/dist/ui/command-palette.js +71 -246
- package/dist/ui/compare-body.d.ts +1 -1
- package/dist/ui/compare-body.js +28 -98
- package/dist/ui/confirm-button.js +8 -15
- package/dist/ui/corbits-mark.js +7 -16
- package/dist/ui/csv-table.d.ts +1 -1
- package/dist/ui/csv-table.js +8 -50
- package/dist/ui/dialog.d.ts +1 -1
- package/dist/ui/dialog.js +32 -62
- package/dist/ui/dictation-status-line.js +7 -25
- package/dist/ui/dither-canvas.d.ts +1 -1
- package/dist/ui/dither-canvas.js +31 -56
- package/dist/ui/embed-body.d.ts +1 -1
- package/dist/ui/embed-body.js +7 -56
- package/dist/ui/empty-state.d.ts +1 -1
- package/dist/ui/empty-state.js +3 -26
- package/dist/ui/file-input.js +17 -37
- package/dist/ui/filter-bar.d.ts +1 -1
- package/dist/ui/filter-bar.js +11 -71
- package/dist/ui/filter-chip.d.ts +1 -1
- package/dist/ui/filter-chip.js +7 -15
- package/dist/ui/gate-block.d.ts +2 -1
- package/dist/ui/gate-block.js +4 -29
- package/dist/ui/horizontal-stepper.d.ts +1 -1
- package/dist/ui/horizontal-stepper.js +18 -45
- package/dist/ui/input.js +1 -6
- package/dist/ui/inspector-shell.d.ts +5 -5
- package/dist/ui/inspector-shell.js +14 -81
- package/dist/ui/intake-form.d.ts +1 -1
- package/dist/ui/intake-form.js +21 -97
- package/dist/ui/kind-card-grid.js +9 -31
- package/dist/ui/library-page-header.js +4 -32
- package/dist/ui/list-detail.js +5 -35
- package/dist/ui/live-run-banner.d.ts +1 -1
- package/dist/ui/live-run-banner.js +5 -15
- package/dist/ui/live-status-line.js +6 -24
- package/dist/ui/menu.js +7 -24
- package/dist/ui/message-bubble.d.ts +3 -3
- package/dist/ui/message-bubble.js +5 -44
- package/dist/ui/mic-button.d.ts +1 -1
- package/dist/ui/mic-button.js +15 -21
- package/dist/ui/mic-permission-dialog.js +5 -41
- package/dist/ui/notifications-bell.js +9 -43
- package/dist/ui/now-cards.d.ts +2 -2
- package/dist/ui/now-cards.js +16 -94
- package/dist/ui/page-panel.js +11 -11
- package/dist/ui/page-shell.js +4 -11
- package/dist/ui/parts-renderer.js +51 -149
- package/dist/ui/profile-card.js +7 -111
- package/dist/ui/progress-checklist.js +11 -49
- package/dist/ui/provider-mark.d.ts +2 -2
- package/dist/ui/provider-mark.js +9 -16
- package/dist/ui/quick-reply-chips.js +6 -14
- package/dist/ui/quote-card.js +12 -32
- package/dist/ui/reasoning-block.d.ts +1 -1
- package/dist/ui/reasoning-block.js +14 -33
- package/dist/ui/research-body.js +32 -213
- package/dist/ui/rich-empty-state.js +6 -48
- package/dist/ui/run-now-button.js +14 -15
- package/dist/ui/section.d.ts +1 -1
- package/dist/ui/section.js +4 -40
- package/dist/ui/select.js +1 -15
- package/dist/ui/selection-checkbox.d.ts +1 -1
- package/dist/ui/selection-checkbox.js +11 -29
- package/dist/ui/settings-panel.js +7 -50
- package/dist/ui/shimmer-text.js +3 -6
- package/dist/ui/sidebar-item-row.d.ts +1 -1
- package/dist/ui/sidebar-item-row.js +9 -39
- package/dist/ui/sidebar-panel.js +15 -40
- package/dist/ui/sidebar.js +15 -76
- package/dist/ui/skeleton.js +3 -7
- package/dist/ui/sortable-table.js +29 -72
- package/dist/ui/sparkline.js +14 -38
- package/dist/ui/stat-grid.js +17 -52
- package/dist/ui/status-dot.d.ts +1 -1
- package/dist/ui/status-dot.js +8 -20
- package/dist/ui/step-list.d.ts +1 -0
- package/dist/ui/step-list.js +11 -50
- package/dist/ui/switch.js +4 -16
- package/dist/ui/table.js +7 -32
- package/dist/ui/tabs.js +39 -54
- package/dist/ui/textarea.js +10 -19
- package/dist/ui/theme-provider.js +54 -78
- package/dist/ui/theme-toggle.js +13 -16
- package/dist/ui/thinking-indicator.js +3 -15
- package/dist/ui/thinking-label.js +16 -35
- package/dist/ui/thinking-mark.d.ts +1 -1
- package/dist/ui/thinking-mark.js +4 -145
- package/dist/ui/time-series-chart.js +43 -174
- package/dist/ui/toast.js +12 -20
- package/dist/ui/token-mosaic.js +5 -43
- package/dist/ui/tool-block.js +18 -70
- package/dist/ui/tool-narrative.d.ts +1 -1
- package/dist/ui/tool-narrative.js +10 -57
- package/dist/ui/tool-picker.js +57 -145
- package/dist/ui/tooltip.d.ts +1 -1
- package/dist/ui/tooltip.js +4 -33
- package/dist/ui/top-bar.js +14 -72
- package/dist/ui/trace-waterfall.d.ts +1 -1
- package/dist/ui/trace-waterfall.js +21 -93
- package/dist/ui/typing-indicator.d.ts +1 -1
- package/dist/ui/typing-indicator.js +4 -18
- package/dist/ui/view-toggle.js +10 -29
- package/dist/ui/voice-waveform.js +3 -11
- package/package.json +94 -535
package/dist/ui/intake-form.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
3
|
import { useId } from "react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
4
5
|
import { Input } from "./input.js";
|
|
5
|
-
/** True when every required field has a value — for enabling a submit control. */
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/** True when every required field has a value — for enabling a submit control. */
|
|
7
|
+
export function intakeFieldsComplete(fields, values) {
|
|
8
|
+
return fields.every((field) => {
|
|
9
|
+
if (field.required !== true)
|
|
10
|
+
return true;
|
|
8
11
|
const value = values[field.name];
|
|
9
|
-
if (typeof value === "string")
|
|
12
|
+
if (typeof value === "string")
|
|
13
|
+
return value.trim().length > 0;
|
|
10
14
|
return value !== undefined && value !== null;
|
|
11
15
|
});
|
|
12
16
|
}
|
|
@@ -14,106 +18,26 @@ import { Input } from "./input.js";
|
|
|
14
18
|
* The inputs a run needs, rendered from a field list. Fully controlled: the
|
|
15
19
|
* host owns the values, so the same form backs a one-off run and a saved
|
|
16
20
|
* schedule without this file knowing which.
|
|
17
|
-
*/
|
|
21
|
+
*/
|
|
22
|
+
export function IntakeForm({ fields, values, onChange, idPrefix, disabled = false, className, }) {
|
|
18
23
|
const generatedPrefix = useId();
|
|
19
24
|
const prefix = idPrefix ?? generatedPrefix;
|
|
20
|
-
if (fields.length === 0)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
25
|
-
return /*#__PURE__*/ _jsx("div", {
|
|
26
|
-
className: cn("flex flex-col gap-4", className),
|
|
27
|
-
children: fields.map((field)=>{
|
|
25
|
+
if (fields.length === 0)
|
|
26
|
+
return null;
|
|
27
|
+
const set = (name, value) => onChange({ ...values, [name]: value });
|
|
28
|
+
return (_jsx("div", { className: cn("flex flex-col gap-4", className), children: fields.map((field) => {
|
|
28
29
|
const id = `${prefix}-${field.name}`;
|
|
29
30
|
const helpId = field.help === undefined ? undefined : `${id}-help`;
|
|
30
31
|
const value = values[field.name];
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
children: [
|
|
38
|
-
/*#__PURE__*/ _jsx("input", {
|
|
39
|
-
id: id,
|
|
40
|
-
type: "checkbox",
|
|
41
|
-
checked: value === true,
|
|
42
|
-
required: field.required,
|
|
43
|
-
disabled: disabled,
|
|
44
|
-
"aria-describedby": helpId,
|
|
45
|
-
onChange: (event)=>set(field.name, event.target.checked),
|
|
46
|
-
className: "size-4 rounded-sm border border-input accent-[var(--primary)]"
|
|
47
|
-
}),
|
|
48
|
-
field.label,
|
|
49
|
-
field.required === true ? /*#__PURE__*/ _jsx(RequiredMark, {}) : null
|
|
50
|
-
]
|
|
51
|
-
}) : /*#__PURE__*/ _jsxs(_Fragment, {
|
|
52
|
-
children: [
|
|
53
|
-
/*#__PURE__*/ _jsxs("label", {
|
|
54
|
-
htmlFor: id,
|
|
55
|
-
className: "text-sm font-medium",
|
|
56
|
-
children: [
|
|
57
|
-
field.label,
|
|
58
|
-
field.required === true ? /*#__PURE__*/ _jsx(RequiredMark, {}) : null
|
|
59
|
-
]
|
|
60
|
-
}),
|
|
61
|
-
field.type === "textarea" ? /*#__PURE__*/ _jsx("textarea", {
|
|
62
|
-
id: id,
|
|
63
|
-
value: typeof value === "string" ? value : "",
|
|
64
|
-
placeholder: field.placeholder,
|
|
65
|
-
required: field.required,
|
|
66
|
-
disabled: disabled,
|
|
67
|
-
"aria-describedby": helpId,
|
|
68
|
-
rows: 4,
|
|
69
|
-
onChange: (event)=>set(field.name, event.target.value),
|
|
70
|
-
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-50"
|
|
71
|
-
}) : field.type === "select" ? /*#__PURE__*/ _jsxs("select", {
|
|
72
|
-
id: id,
|
|
73
|
-
value: typeof value === "string" ? value : "",
|
|
74
|
-
required: field.required,
|
|
75
|
-
disabled: disabled,
|
|
76
|
-
"aria-describedby": helpId,
|
|
77
|
-
onChange: (event)=>set(field.name, event.target.value),
|
|
78
|
-
className: "h-9 w-full rounded-md border border-input bg-background px-3 text-sm disabled:opacity-50",
|
|
79
|
-
children: [
|
|
80
|
-
/*#__PURE__*/ _jsx("option", {
|
|
81
|
-
value: "",
|
|
82
|
-
children: "Choose…"
|
|
83
|
-
}),
|
|
84
|
-
(field.options ?? []).map((option)=>/*#__PURE__*/ _jsx("option", {
|
|
85
|
-
value: option.value,
|
|
86
|
-
children: option.label
|
|
87
|
-
}, option.value))
|
|
88
|
-
]
|
|
89
|
-
}) : /*#__PURE__*/ _jsx(Input, {
|
|
90
|
-
id: id,
|
|
91
|
-
type: field.type === "number" ? "number" : "text",
|
|
92
|
-
value: typeof value === "string" || typeof value === "number" ? String(value) : "",
|
|
93
|
-
placeholder: field.placeholder,
|
|
94
|
-
required: field.required,
|
|
95
|
-
disabled: disabled,
|
|
96
|
-
"aria-describedby": helpId,
|
|
97
|
-
onChange: (event)=>set(field.name, field.type === "number" ? event.target.valueAsNumber : event.target.value)
|
|
98
|
-
})
|
|
99
|
-
]
|
|
100
|
-
}),
|
|
101
|
-
field.help === undefined ? null : /*#__PURE__*/ _jsx("p", {
|
|
102
|
-
id: helpId,
|
|
103
|
-
className: "text-xs text-muted-foreground",
|
|
104
|
-
children: field.help
|
|
105
|
-
})
|
|
106
|
-
]
|
|
107
|
-
}, field.name);
|
|
108
|
-
})
|
|
109
|
-
});
|
|
32
|
+
return (_jsxs("div", { className: "flex flex-col gap-1.5", children: [field.type === "boolean" ? (_jsxs("label", { htmlFor: id, className: "flex items-center gap-2 text-sm", children: [_jsx("input", { id: id, type: "checkbox", checked: value === true, required: field.required, disabled: disabled, "aria-describedby": helpId, onChange: (event) => set(field.name, event.target.checked), className: "size-4 rounded-sm border border-input accent-[var(--primary)]" }), field.label, field.required === true ? _jsx(RequiredMark, {}) : null] })) : (_jsxs(_Fragment, { children: [_jsxs("label", { htmlFor: id, className: "text-sm font-medium", children: [field.label, field.required === true ? _jsx(RequiredMark, {}) : null] }), field.type === "textarea" ? (_jsx("textarea", { id: id, value: typeof value === "string" ? value : "", placeholder: field.placeholder, required: field.required, disabled: disabled, "aria-describedby": helpId, rows: 4, onChange: (event) => set(field.name, event.target.value), className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-50" })) : field.type === "select" ? (_jsxs("select", { id: id, value: typeof value === "string" ? value : "", required: field.required, disabled: disabled, "aria-describedby": helpId, onChange: (event) => set(field.name, event.target.value), className: "h-9 w-full rounded-md border border-input bg-background px-3 text-sm disabled:opacity-50", children: [_jsx("option", { value: "", children: "Choose\u2026" }), (field.options ?? []).map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value)))] })) : (_jsx(Input, { id: id, type: field.type === "number" ? "number" : "text", value: typeof value === "string" || typeof value === "number"
|
|
33
|
+
? String(value)
|
|
34
|
+
: "", placeholder: field.placeholder, required: field.required, disabled: disabled, "aria-describedby": helpId, onChange: (event) => set(field.name, field.type === "number"
|
|
35
|
+
? event.target.valueAsNumber
|
|
36
|
+
: event.target.value) }))] })), field.help === undefined ? null : (_jsx("p", { id: helpId, className: "text-xs text-muted-foreground", children: field.help }))] }, field.name));
|
|
37
|
+
}) }));
|
|
110
38
|
}
|
|
111
39
|
// The asterisk is decorative: `required` on the control is what actually tells
|
|
112
40
|
// assistive tech, and a screen reader announcing "asterisk" helps nobody.
|
|
113
41
|
function RequiredMark() {
|
|
114
|
-
return
|
|
115
|
-
"aria-hidden": true,
|
|
116
|
-
className: "ml-0.5 text-primary-emphasis",
|
|
117
|
-
children: "*"
|
|
118
|
-
});
|
|
42
|
+
return (_jsx("span", { "aria-hidden": true, className: "ml-0.5 text-primary-emphasis", children: "*" }));
|
|
119
43
|
}
|
|
@@ -1,43 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { cn } from "../lib/utils.js";
|
|
3
4
|
const COLUMNS = {
|
|
4
5
|
2: "grid-cols-2",
|
|
5
6
|
3: "grid-cols-3",
|
|
6
|
-
4: "grid-cols-4"
|
|
7
|
+
4: "grid-cols-4",
|
|
7
8
|
};
|
|
8
9
|
/**
|
|
9
10
|
* Selectable card grid for channel-kind, grant-effect, provider, and
|
|
10
11
|
* workbench-type pickers. Each card is a real button with `aria-pressed`;
|
|
11
12
|
* the group is labelled for assistive tech.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"aria-label": label,
|
|
16
|
-
className: cn("grid gap-2", COLUMNS[columns], className),
|
|
17
|
-
children: options.map((option)=>{
|
|
13
|
+
*/
|
|
14
|
+
export function KindCardGrid({ options, value, onChange, label, columns = 2, className, }) {
|
|
15
|
+
return (_jsx("div", { role: "group", "aria-label": label, className: cn("grid gap-2", COLUMNS[columns], className), children: options.map((option) => {
|
|
18
16
|
const selected = value === option.id;
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
onClick: ()=>onChange?.(option.id),
|
|
24
|
-
className: cn("flex flex-col gap-1 border px-3.5 py-3 text-left transition-colors ease-out", "hover:bg-muted active:brightness-95 disabled:pointer-events-none disabled:opacity-50", selected ? "border-primary-emphasis bg-primary/10" : "border-border bg-card"),
|
|
25
|
-
children: [
|
|
26
|
-
option.icon === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
27
|
-
className: "mb-0.5 text-muted-foreground",
|
|
28
|
-
"aria-hidden": true,
|
|
29
|
-
children: option.icon
|
|
30
|
-
}),
|
|
31
|
-
/*#__PURE__*/ _jsx("span", {
|
|
32
|
-
className: "text-sm font-semibold",
|
|
33
|
-
children: option.title
|
|
34
|
-
}),
|
|
35
|
-
option.description === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
36
|
-
className: "text-xs leading-snug text-muted-foreground",
|
|
37
|
-
children: option.description
|
|
38
|
-
})
|
|
39
|
-
]
|
|
40
|
-
}, option.id);
|
|
41
|
-
})
|
|
42
|
-
});
|
|
17
|
+
return (_jsxs("button", { type: "button", "aria-pressed": selected, disabled: option.disabled === true, onClick: () => onChange?.(option.id), className: cn("flex flex-col gap-1 border px-3.5 py-3 text-left transition-colors ease-out", "hover:bg-muted active:brightness-95 disabled:pointer-events-none disabled:opacity-50", selected
|
|
18
|
+
? "border-primary-emphasis bg-primary/10"
|
|
19
|
+
: "border-border bg-card"), children: [option.icon === undefined ? null : (_jsx("span", { className: "mb-0.5 text-muted-foreground", "aria-hidden": true, children: option.icon })), _jsx("span", { className: "text-sm font-semibold", children: option.title }), option.description === undefined ? null : (_jsx("span", { className: "text-xs leading-snug text-muted-foreground", children: option.description }))] }, option.id));
|
|
20
|
+
}) }));
|
|
43
21
|
}
|
|
@@ -2,42 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
3
|
const TITLE_CLASS = {
|
|
4
4
|
lg: "text-[21px] font-semibold tracking-[-0.02em]",
|
|
5
|
-
sm: "text-[17px] font-semibold tracking-[-0.01em]"
|
|
5
|
+
sm: "text-[17px] font-semibold tracking-[-0.01em]",
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
8
|
* The header row every library page shares: title, item count, then trailing
|
|
9
9
|
* controls after a flexible spacer. The spacer is a real element rather than
|
|
10
10
|
* `justify-between` so a `LibrarySearchInput` can expand leftward over it
|
|
11
11
|
* without shifting its neighbours.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
className: cn("flex min-w-0 flex-wrap items-center gap-[14px] px-4 pt-5 pb-[14px] sm:px-7", className),
|
|
16
|
-
children: [
|
|
17
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
18
|
-
className: "flex min-w-0 shrink-0 flex-col gap-0.5",
|
|
19
|
-
children: [
|
|
20
|
-
/*#__PURE__*/ _jsx("h1", {
|
|
21
|
-
className: TITLE_CLASS[titleSize],
|
|
22
|
-
children: title
|
|
23
|
-
}),
|
|
24
|
-
subtitle === undefined || subtitle === "" ? null : /*#__PURE__*/ _jsx("p", {
|
|
25
|
-
className: "truncate text-[12px] text-muted-foreground",
|
|
26
|
-
children: subtitle
|
|
27
|
-
})
|
|
28
|
-
]
|
|
29
|
-
}),
|
|
30
|
-
count === undefined ? null : /*#__PURE__*/ _jsxs("span", {
|
|
31
|
-
className: "shrink-0 rounded-md bg-muted px-[9px] py-[3px] font-mono text-[12px] text-muted-foreground",
|
|
32
|
-
children: [
|
|
33
|
-
count,
|
|
34
|
-
" items"
|
|
35
|
-
]
|
|
36
|
-
}),
|
|
37
|
-
/*#__PURE__*/ _jsx("div", {
|
|
38
|
-
className: "min-w-2 flex-1"
|
|
39
|
-
}),
|
|
40
|
-
children
|
|
41
|
-
]
|
|
42
|
-
});
|
|
12
|
+
*/
|
|
13
|
+
export function LibraryPageHeader({ title, titleSize = "lg", count, subtitle, children, className, }) {
|
|
14
|
+
return (_jsxs("div", { "data-slot": "library-page-header", className: cn("flex min-w-0 flex-wrap items-center gap-[14px] px-4 pt-5 pb-[14px] sm:px-7", className), children: [_jsxs("div", { className: "flex min-w-0 shrink-0 flex-col gap-0.5", children: [_jsx("h1", { className: TITLE_CLASS[titleSize], children: title }), subtitle === undefined || subtitle === "" ? null : (_jsx("p", { className: "truncate text-[12px] text-muted-foreground", children: subtitle }))] }), count === undefined ? null : (_jsxs("span", { className: "shrink-0 rounded-md bg-muted px-[9px] py-[3px] font-mono text-[12px] text-muted-foreground", children: [count, " items"] })), _jsx("div", { className: "min-w-2 flex-1" }), children] }));
|
|
43
15
|
}
|
package/dist/ui/list-detail.js
CHANGED
|
@@ -15,41 +15,11 @@ import { EmptyState } from "./empty-state.js";
|
|
|
15
15
|
*
|
|
16
16
|
* Both panes scroll independently, so reading a long detail does not scroll the
|
|
17
17
|
* list out from under the selection.
|
|
18
|
-
*/
|
|
18
|
+
*/
|
|
19
|
+
export function ListDetail({ list, detail, onCloseDetail, placeholder, detailLabel = "Details", className, }) {
|
|
19
20
|
const open = detail !== null;
|
|
20
|
-
return
|
|
21
|
-
|
|
22
|
-
children: [
|
|
23
|
-
/*#__PURE__*/ _jsx("div", {
|
|
24
|
-
className: cn("min-h-0 flex-1 overflow-y-auto lg:max-w-md lg:shrink-0 lg:border-r lg:border-border lg:pr-6", // Hidden, not merely visually stacked: leaving it in the tree on
|
|
21
|
+
return (_jsxs("div", { className: cn("flex min-h-0 flex-1 gap-6", className), children: [_jsx("div", { className: cn("min-h-0 flex-1 overflow-y-auto lg:max-w-md lg:shrink-0 lg:border-r lg:border-border lg:pr-6",
|
|
22
|
+
// Hidden, not merely visually stacked: leaving it in the tree on
|
|
25
23
|
// mobile would keep every row in the tab order behind the detail.
|
|
26
|
-
open && "hidden lg:block"),
|
|
27
|
-
children: list
|
|
28
|
-
}),
|
|
29
|
-
/*#__PURE__*/ _jsx("section", {
|
|
30
|
-
"aria-label": detailLabel,
|
|
31
|
-
className: cn("min-h-0 min-w-0 flex-1 overflow-y-auto", !open && "hidden lg:block"),
|
|
32
|
-
children: open ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
33
|
-
children: [
|
|
34
|
-
/*#__PURE__*/ _jsxs("button", {
|
|
35
|
-
type: "button",
|
|
36
|
-
onClick: onCloseDetail,
|
|
37
|
-
className: "mb-3 inline-flex items-center gap-1.5 rounded-md text-sm text-muted-foreground transition-colors hover:text-foreground lg:hidden",
|
|
38
|
-
children: [
|
|
39
|
-
/*#__PURE__*/ _jsx(ArrowLeft, {
|
|
40
|
-
className: "size-4",
|
|
41
|
-
"aria-hidden": true
|
|
42
|
-
}),
|
|
43
|
-
"Back to list"
|
|
44
|
-
]
|
|
45
|
-
}),
|
|
46
|
-
detail
|
|
47
|
-
]
|
|
48
|
-
}) : placeholder ?? /*#__PURE__*/ _jsx(EmptyState, {
|
|
49
|
-
title: "Nothing selected",
|
|
50
|
-
description: "Pick something from the list."
|
|
51
|
-
})
|
|
52
|
-
})
|
|
53
|
-
]
|
|
54
|
-
});
|
|
24
|
+
open && "hidden lg:block"), children: list }), _jsx("section", { "aria-label": detailLabel, className: cn("min-h-0 min-w-0 flex-1 overflow-y-auto", !open && "hidden lg:block"), children: open ? (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: onCloseDetail, className: "mb-3 inline-flex items-center gap-1.5 rounded-md text-sm text-muted-foreground transition-colors hover:text-foreground lg:hidden", children: [_jsx(ArrowLeft, { className: "size-4", "aria-hidden": true }), "Back to list"] }), detail] })) : ((placeholder ?? (_jsx(EmptyState, { title: "Nothing selected", description: "Pick something from the list." })))) })] }));
|
|
55
25
|
}
|
|
@@ -10,4 +10,4 @@ export type LiveRunBannerProps = {
|
|
|
10
10
|
* running gets the info tone. Standalone so a consumer building its own run
|
|
11
11
|
* surface can reuse just this strip.
|
|
12
12
|
*/
|
|
13
|
-
export declare function LiveRunBanner({ awaiting, message, elapsed, className }: LiveRunBannerProps): import("react").JSX.Element;
|
|
13
|
+
export declare function LiveRunBanner({ awaiting, message, elapsed, className, }: LiveRunBannerProps): import("react").JSX.Element;
|
|
@@ -5,19 +5,9 @@ import { cn } from "../lib/utils.js";
|
|
|
5
5
|
* accent tone that marks "this needs you" everywhere else in the registry,
|
|
6
6
|
* running gets the info tone. Standalone so a consumer building its own run
|
|
7
7
|
* surface can reuse just this strip.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/*#__PURE__*/ _jsx("span", {
|
|
14
|
-
className: "font-semibold",
|
|
15
|
-
children: message ?? (awaiting ? "Paused for your input" : "Running")
|
|
16
|
-
}),
|
|
17
|
-
elapsed === undefined ? null : /*#__PURE__*/ _jsx("span", {
|
|
18
|
-
className: "font-mono text-[11.5px] tabular-nums opacity-90",
|
|
19
|
-
children: elapsed
|
|
20
|
-
})
|
|
21
|
-
]
|
|
22
|
-
});
|
|
8
|
+
*/
|
|
9
|
+
export function LiveRunBanner({ awaiting = false, message, elapsed, className, }) {
|
|
10
|
+
return (_jsxs("div", { role: "status", className: cn("mb-3 flex flex-wrap items-center justify-between gap-2 rounded-lg border px-3 py-2 text-xs", awaiting
|
|
11
|
+
? "border-primary-emphasis/35 bg-primary/10 text-primary-emphasis"
|
|
12
|
+
: "border-accent bg-accent text-accent-foreground", className), children: [_jsx("span", { className: "font-semibold", children: message ?? (awaiting ? "Paused for your input" : "Running") }), elapsed === undefined ? null : (_jsx("span", { className: "font-mono text-[11.5px] tabular-nums opacity-90", children: elapsed }))] }));
|
|
23
13
|
}
|
|
@@ -3,20 +3,9 @@ import { cn } from "../lib/utils.js";
|
|
|
3
3
|
/** The single "what's happening now" line under a stepper. A spinning ring
|
|
4
4
|
* plus text, not colour alone — `motion-reduce:animate-none` stills the
|
|
5
5
|
* spinner without hiding the line, since the words already carry the
|
|
6
|
-
* meaning. */
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"aria-live": "polite",
|
|
10
|
-
className: cn("flex items-center gap-2 border-b border-border bg-card px-6 py-2.5 text-sm text-muted-foreground", className),
|
|
11
|
-
children: [
|
|
12
|
-
/*#__PURE__*/ _jsx("span", {
|
|
13
|
-
"aria-hidden": true,
|
|
14
|
-
className: "size-3 animate-spin rounded-full border-2 border-border border-t-primary-emphasis motion-reduce:animate-none"
|
|
15
|
-
}),
|
|
16
|
-
label,
|
|
17
|
-
"…"
|
|
18
|
-
]
|
|
19
|
-
});
|
|
6
|
+
* meaning. */
|
|
7
|
+
export function LiveStatusLine({ label, className }) {
|
|
8
|
+
return (_jsxs("div", { role: "status", "aria-live": "polite", className: cn("flex items-center gap-2 border-b border-border bg-card px-6 py-2.5 text-sm text-muted-foreground", className), children: [_jsx("span", { "aria-hidden": true, className: "size-3 animate-spin rounded-full border-2 border-border border-t-primary-emphasis motion-reduce:animate-none" }), label, "\u2026"] }));
|
|
20
9
|
}
|
|
21
10
|
/**
|
|
22
11
|
* Layout-stable wrapper for `LiveStatusLine`: a `null` label collapses the
|
|
@@ -24,14 +13,7 @@ import { cn } from "../lib/utils.js";
|
|
|
24
13
|
* below it doesn't jump at every gate-to-processing boundary. The transition
|
|
25
14
|
* is a plain CSS grid-rows trick — no animation library — and
|
|
26
15
|
* `prefers-reduced-motion` disables it globally via the theme's base layer.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
children: /*#__PURE__*/ _jsx("div", {
|
|
31
|
-
className: "overflow-hidden",
|
|
32
|
-
children: label === null ? null : /*#__PURE__*/ _jsx(LiveStatusLine, {
|
|
33
|
-
label: label
|
|
34
|
-
})
|
|
35
|
-
})
|
|
36
|
-
});
|
|
16
|
+
*/
|
|
17
|
+
export function LiveStatusSlot({ label, className }) {
|
|
18
|
+
return (_jsx("div", { className: cn("grid transition-[grid-template-rows] duration-200 ease-out", label === null ? "grid-rows-[0fr]" : "grid-rows-[1fr]", className), children: _jsx("div", { className: "overflow-hidden", children: label === null ? null : _jsx(LiveStatusLine, { label: label }) }) }));
|
|
37
19
|
}
|
package/dist/ui/menu.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
@@ -9,37 +10,19 @@ import { cn } from "../lib/utils.js";
|
|
|
9
10
|
* popover surface — a see-through menu over a busy page is the bug this
|
|
10
11
|
* primitive exists to prevent — and the same item hover, so a menu opened from
|
|
11
12
|
* a toolbar and one opened from a table row read as the same control.
|
|
12
|
-
*/
|
|
13
|
+
*/
|
|
14
|
+
export const Menu = DropdownMenuPrimitive.Root;
|
|
13
15
|
export const MenuTrigger = DropdownMenuPrimitive.Trigger;
|
|
14
16
|
export const MenuGroup = DropdownMenuPrimitive.Group;
|
|
15
17
|
export function MenuContent({ className, sideOffset = 4, ...props }) {
|
|
16
|
-
return
|
|
17
|
-
children: /*#__PURE__*/ _jsx(DropdownMenuPrimitive.Content, {
|
|
18
|
-
"data-slot": "menu-content",
|
|
19
|
-
sideOffset: sideOffset,
|
|
20
|
-
className: cn("z-50 min-w-32 overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg", className),
|
|
21
|
-
...props
|
|
22
|
-
})
|
|
23
|
-
});
|
|
18
|
+
return (_jsx(DropdownMenuPrimitive.Portal, { children: _jsx(DropdownMenuPrimitive.Content, { "data-slot": "menu-content", sideOffset: sideOffset, className: cn("z-50 min-w-32 overflow-hidden rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg", className), ...props }) }));
|
|
24
19
|
}
|
|
25
20
|
export function MenuItem({ className, ...props }) {
|
|
26
|
-
return
|
|
27
|
-
"data-slot": "menu-item",
|
|
28
|
-
className: cn("flex w-full cursor-pointer items-center gap-2 rounded-md px-2.5 py-2 text-left text-sm outline-none select-none transition-colors data-[highlighted]:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className),
|
|
29
|
-
...props
|
|
30
|
-
});
|
|
21
|
+
return (_jsx(DropdownMenuPrimitive.Item, { "data-slot": "menu-item", className: cn("flex w-full cursor-pointer items-center gap-2 rounded-md px-2.5 py-2 text-left text-sm outline-none select-none transition-colors data-[highlighted]:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50", className), ...props }));
|
|
31
22
|
}
|
|
32
23
|
export function MenuLabel({ className, ...props }) {
|
|
33
|
-
return
|
|
34
|
-
"data-slot": "menu-label",
|
|
35
|
-
className: cn("px-2.5 py-1.5 text-xs font-semibold text-muted-foreground", className),
|
|
36
|
-
...props
|
|
37
|
-
});
|
|
24
|
+
return (_jsx(DropdownMenuPrimitive.Label, { "data-slot": "menu-label", className: cn("px-2.5 py-1.5 text-xs font-semibold text-muted-foreground", className), ...props }));
|
|
38
25
|
}
|
|
39
26
|
export function MenuSeparator({ className, ...props }) {
|
|
40
|
-
return
|
|
41
|
-
"data-slot": "menu-separator",
|
|
42
|
-
className: cn("my-1 h-px bg-border", className),
|
|
43
|
-
...props
|
|
44
|
-
});
|
|
27
|
+
return (_jsx(DropdownMenuPrimitive.Separator, { "data-slot": "menu-separator", className: cn("my-1 h-px bg-border", className), ...props }));
|
|
45
28
|
}
|
|
@@ -3,8 +3,8 @@ import type { ChatMessage } from "../lib/chat-message.js";
|
|
|
3
3
|
export type MessageBubbleProps = {
|
|
4
4
|
readonly message: ChatMessage;
|
|
5
5
|
/** Retry affordance for a failed send. Omit and a failure is only reported. */
|
|
6
|
-
readonly onRetry?: () => void;
|
|
7
|
-
readonly now?: number;
|
|
6
|
+
readonly onRetry?: (() => void) | undefined;
|
|
7
|
+
readonly now?: number | undefined;
|
|
8
8
|
/** Rich body — a markdown renderer. Defaults to the message's plain text. */
|
|
9
9
|
readonly children?: ReactNode;
|
|
10
10
|
readonly className?: string;
|
|
@@ -21,4 +21,4 @@ export type MessageBubbleProps = {
|
|
|
21
21
|
* renderer is the host's decision to make, with the host's sanitiser — pass one
|
|
22
22
|
* as `children`.
|
|
23
23
|
*/
|
|
24
|
-
export declare function MessageBubble({ message, onRetry, now, children, className }: MessageBubbleProps): import("react").JSX.Element;
|
|
24
|
+
export declare function MessageBubble({ message, onRetry, now, children, className, }: MessageBubbleProps): import("react").JSX.Element;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { messageText } from "../lib/chat-message.js";
|
|
3
3
|
import { formatRelativeTime } from "../lib/relative-time.js";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
@@ -13,52 +13,13 @@ import { cn } from "../lib/utils.js";
|
|
|
13
13
|
* Text is rendered as text. Passing agent output through a markdown or HTML
|
|
14
14
|
* renderer is the host's decision to make, with the host's sanitiser — pass one
|
|
15
15
|
* as `children`.
|
|
16
|
-
*/
|
|
16
|
+
*/
|
|
17
|
+
export function MessageBubble({ message, onRetry, now, children, className, }) {
|
|
17
18
|
const isUser = message.role === "user";
|
|
18
19
|
const isSystem = message.role === "system";
|
|
19
20
|
const failed = message.status === "failed";
|
|
20
21
|
if (isSystem) {
|
|
21
|
-
return
|
|
22
|
-
"data-slot": "message-bubble",
|
|
23
|
-
className: cn("px-2 py-1 text-center text-xs text-muted-foreground", className),
|
|
24
|
-
children: children ?? messageText(message)
|
|
25
|
-
});
|
|
22
|
+
return (_jsx("p", { "data-slot": "message-bubble", className: cn("px-2 py-1 text-center text-xs text-muted-foreground", className), children: children ?? messageText(message) }));
|
|
26
23
|
}
|
|
27
|
-
return
|
|
28
|
-
"data-slot": "message-bubble",
|
|
29
|
-
className: cn("flex flex-col gap-1", isUser ? "items-end" : "items-start", className),
|
|
30
|
-
children: [
|
|
31
|
-
/*#__PURE__*/ _jsx("div", {
|
|
32
|
-
className: cn("max-w-[46rem] text-sm leading-relaxed break-words whitespace-pre-wrap", isUser && "rounded-lg bg-muted px-3 py-2", failed && "opacity-60"),
|
|
33
|
-
children: children ?? messageText(message)
|
|
34
|
-
}),
|
|
35
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
36
|
-
className: "flex items-center gap-2 text-[11px] text-muted-foreground",
|
|
37
|
-
children: [
|
|
38
|
-
/*#__PURE__*/ _jsx("time", {
|
|
39
|
-
dateTime: message.createdAt,
|
|
40
|
-
children: formatRelativeTime(message.createdAt, now)
|
|
41
|
-
}),
|
|
42
|
-
message.status === "sending" ? /*#__PURE__*/ _jsx("span", {
|
|
43
|
-
children: "Sending…"
|
|
44
|
-
}) : null,
|
|
45
|
-
failed ? /*#__PURE__*/ _jsxs(_Fragment, {
|
|
46
|
-
children: [
|
|
47
|
-
/*#__PURE__*/ _jsx("span", {
|
|
48
|
-
role: "alert",
|
|
49
|
-
className: "text-destructive",
|
|
50
|
-
children: "Not sent"
|
|
51
|
-
}),
|
|
52
|
-
onRetry === undefined ? null : /*#__PURE__*/ _jsx("button", {
|
|
53
|
-
type: "button",
|
|
54
|
-
onClick: onRetry,
|
|
55
|
-
className: "text-primary-emphasis hover:underline",
|
|
56
|
-
children: "Retry"
|
|
57
|
-
})
|
|
58
|
-
]
|
|
59
|
-
}) : null
|
|
60
|
-
]
|
|
61
|
-
})
|
|
62
|
-
]
|
|
63
|
-
});
|
|
24
|
+
return (_jsxs("div", { "data-slot": "message-bubble", className: cn("flex flex-col gap-1", isUser ? "items-end" : "items-start", className), children: [_jsx("div", { className: cn("max-w-[46rem] text-sm leading-relaxed break-words whitespace-pre-wrap", isUser && "rounded-lg bg-muted px-3 py-2", failed && "opacity-60"), children: children ?? messageText(message) }), _jsxs("div", { className: "flex items-center gap-2 text-[11px] text-muted-foreground", children: [_jsx("time", { dateTime: message.createdAt, children: formatRelativeTime(message.createdAt, now) }), message.status === "sending" ? _jsx("span", { children: "Sending\u2026" }) : null, failed ? (_jsxs(_Fragment, { children: [_jsx("span", { role: "alert", className: "text-destructive", children: "Not sent" }), onRetry === undefined ? null : (_jsx("button", { type: "button", onClick: onRetry, className: "text-primary-emphasis hover:underline", children: "Retry" }))] })) : null] })] }));
|
|
64
25
|
}
|
package/dist/ui/mic-button.d.ts
CHANGED
|
@@ -32,4 +32,4 @@ export type MicButtonProps = {
|
|
|
32
32
|
* `unsupported` is disabled. `denied` stays clickable so the host can open
|
|
33
33
|
* `MicPermissionDialog` from `onToggle`.
|
|
34
34
|
*/
|
|
35
|
-
export declare function MicButton({ state, onToggle, disabled, className }: MicButtonProps): import("react").JSX.Element;
|
|
35
|
+
export declare function MicButton({ state, onToggle, disabled, className, }: MicButtonProps): import("react").JSX.Element;
|
package/dist/ui/mic-button.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import { Mic, MicOff, Square } from "lucide-react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
4
5
|
function labelFor(state) {
|
|
5
|
-
if (state === "denied")
|
|
6
|
-
|
|
7
|
-
if (state === "
|
|
8
|
-
|
|
6
|
+
if (state === "denied")
|
|
7
|
+
return "Microphone blocked";
|
|
8
|
+
if (state === "unsupported")
|
|
9
|
+
return "Dictation unavailable";
|
|
10
|
+
if (state === "listening")
|
|
11
|
+
return "Stop dictating";
|
|
12
|
+
if (state === "starting")
|
|
13
|
+
return "Starting microphone";
|
|
9
14
|
return "Dictate instead of typing";
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
@@ -34,28 +39,17 @@ function labelFor(state) {
|
|
|
34
39
|
* stays the idle mic so it cannot be mistaken for a live capture.
|
|
35
40
|
* `unsupported` is disabled. `denied` stays clickable so the host can open
|
|
36
41
|
* `MicPermissionDialog` from `onToggle`.
|
|
37
|
-
*/
|
|
42
|
+
*/
|
|
43
|
+
export function MicButton({ state, onToggle, disabled = false, className, }) {
|
|
38
44
|
const listening = state === "listening";
|
|
39
45
|
const denied = state === "denied";
|
|
40
46
|
const unusable = disabled || state === "unsupported";
|
|
41
47
|
const label = labelFor(state);
|
|
42
48
|
const Glyph = listening ? Square : denied ? MicOff : Mic;
|
|
43
|
-
return
|
|
44
|
-
type: "button",
|
|
45
|
-
// Denied opens the permission dialog rather than toggling — declare the
|
|
46
|
-
// popup and drop the toggle semantic.
|
|
47
|
-
"aria-pressed": denied ? undefined : listening,
|
|
48
|
-
"aria-haspopup": denied ? "dialog" : undefined,
|
|
49
|
-
"aria-label": label,
|
|
50
|
-
disabled: unusable,
|
|
49
|
+
return (_jsx("button", { type: "button", "aria-pressed": denied ? undefined : listening, "aria-haspopup": denied ? "dialog" : undefined, "aria-label": label, disabled: unusable,
|
|
51
50
|
// Tapping the mic must not blur the field being dictated into — a field
|
|
52
51
|
// that commits on blur would lose the edit to its own microphone tap.
|
|
53
|
-
onMouseDown: (event)=>event.preventDefault(),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
children: /*#__PURE__*/ _jsx(Glyph, {
|
|
57
|
-
className: listening ? "size-3.5 fill-current" : "size-4",
|
|
58
|
-
"aria-hidden": true
|
|
59
|
-
})
|
|
60
|
-
});
|
|
52
|
+
onMouseDown: (event) => event.preventDefault(), onClick: onToggle, className: cn("grid size-9 shrink-0 place-items-center rounded-md transition-colors disabled:opacity-50", !unusable && "active:brightness-95 motion-safe:active:scale-[0.97]", listening
|
|
53
|
+
? "bg-success text-success-foreground hover:bg-success/90"
|
|
54
|
+
: "text-muted-foreground hover:bg-muted hover:text-foreground", className), children: _jsx(Glyph, { className: listening ? "size-3.5 fill-current" : "size-4", "aria-hidden": true }) }));
|
|
61
55
|
}
|
|
@@ -1,50 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
3
|
import { Button } from "./button.js";
|
|
3
|
-
import { Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "./dialog.js";
|
|
4
|
+
import { Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "./dialog.js";
|
|
4
5
|
/**
|
|
5
6
|
* A refusal that is a setting, put in front of the person with the button
|
|
6
7
|
* that opens the pane. Presentational: it does not know what "open settings"
|
|
7
8
|
* means for a given host (a native shell invoking an OS pane, a browser
|
|
8
9
|
* opening a help link) — the consumer's dictation hook supplies `onAction`
|
|
9
10
|
* and, if that action can itself fail, `failure`.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
onOpenChange: onOpenChange,
|
|
14
|
-
children: /*#__PURE__*/ _jsxs(DialogContent, {
|
|
15
|
-
children: [
|
|
16
|
-
/*#__PURE__*/ _jsxs(DialogHeader, {
|
|
17
|
-
children: [
|
|
18
|
-
/*#__PURE__*/ _jsx(DialogTitle, {
|
|
19
|
-
children: title
|
|
20
|
-
}),
|
|
21
|
-
/*#__PURE__*/ _jsx(DialogDescription, {
|
|
22
|
-
children: detail
|
|
23
|
-
})
|
|
24
|
-
]
|
|
25
|
-
}),
|
|
26
|
-
failure ? /*#__PURE__*/ _jsx(DialogBody, {
|
|
27
|
-
children: /*#__PURE__*/ _jsx("p", {
|
|
28
|
-
role: "alert",
|
|
29
|
-
className: "text-sm text-destructive",
|
|
30
|
-
children: failure
|
|
31
|
-
})
|
|
32
|
-
}) : null,
|
|
33
|
-
/*#__PURE__*/ _jsxs(DialogFooter, {
|
|
34
|
-
children: [
|
|
35
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
36
|
-
variant: "ghost",
|
|
37
|
-
onClick: ()=>onOpenChange(false),
|
|
38
|
-
children: dismissLabel
|
|
39
|
-
}),
|
|
40
|
-
/*#__PURE__*/ _jsx(Button, {
|
|
41
|
-
variant: "primary",
|
|
42
|
-
onClick: onAction,
|
|
43
|
-
children: actionLabel
|
|
44
|
-
})
|
|
45
|
-
]
|
|
46
|
-
})
|
|
47
|
-
]
|
|
48
|
-
})
|
|
49
|
-
});
|
|
11
|
+
*/
|
|
12
|
+
export function MicPermissionDialog({ open, onOpenChange, title, detail, actionLabel, onAction, failure = null, dismissLabel = "Not now", }) {
|
|
13
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), _jsx(DialogDescription, { children: detail })] }), failure ? (_jsx(DialogBody, { children: _jsx("p", { role: "alert", className: "text-sm text-destructive", children: failure }) })) : null, _jsxs(DialogFooter, { children: [_jsx(Button, { variant: "ghost", onClick: () => onOpenChange(false), children: dismissLabel }), _jsx(Button, { variant: "primary", onClick: onAction, children: actionLabel })] })] }) }));
|
|
50
14
|
}
|