@ctrl-ui/react 0.9.6 → 0.9.9
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 +38 -2
- package/dist/activity.d.ts +3 -1
- package/dist/activity.js +2 -1
- package/dist/blocks/agent-run-sidebar.js +11 -10
- package/dist/blocks/agent-run.d.ts +3 -1
- package/dist/blocks/agent-run.js +21 -13
- package/dist/blocks/coding-agent.js +50 -69
- package/dist/blocks/design-canvas-inspector.js +1 -1
- package/dist/blocks/design-canvas.js +41 -34
- package/dist/blocks/discussion.js +1 -1
- package/dist/blocks/file-explorer.js +66 -47
- package/dist/blocks/settings.js +37 -41
- package/dist/blocks/team-chat.js +2 -1
- package/dist/blocks/theme-toggle.d.ts +2 -1
- package/dist/blocks/theme-toggle.js +13 -4
- package/dist/hooks/use-mobile.d.ts +1 -1
- package/dist/hooks/use-mobile.js +1 -1
- package/dist/knob-contracts/badge-knobs.d.ts +1 -1
- package/dist/knob-contracts/badge-knobs.js +3 -1
- package/dist/knob-contracts/button-knobs.d.ts +1 -1
- package/dist/knob-contracts/button-knobs.js +1 -0
- package/dist/knob-contracts/calendar-knobs.d.ts +1 -1
- package/dist/knob-contracts/calendar-knobs.js +9 -1
- package/dist/knob-contracts/card-knobs.d.ts +1 -1
- package/dist/knob-contracts/card-knobs.js +5 -1
- package/dist/knob-contracts/choice-knobs.d.ts +1 -1
- package/dist/knob-contracts/choice-knobs.js +1 -0
- package/dist/knob-contracts/collapsible-knobs.d.ts +1 -1
- package/dist/knob-contracts/collapsible-knobs.js +5 -1
- package/dist/knob-contracts/emoji-picker-knobs.d.ts +1 -1
- package/dist/knob-contracts/emoji-picker-knobs.js +3 -1
- package/dist/knob-contracts/field-knobs.d.ts +1 -1
- package/dist/knob-contracts/field-knobs.js +17 -1
- package/dist/knob-contracts/item-knobs.d.ts +1 -1
- package/dist/knob-contracts/item-knobs.js +6 -1
- package/dist/knob-contracts/kbd-knobs.d.ts +1 -1
- package/dist/knob-contracts/kbd-knobs.js +4 -1
- package/dist/knob-contracts/page-layout-knobs.d.ts +1 -1
- package/dist/knob-contracts/page-layout-knobs.js +1 -0
- package/dist/knob-contracts/pagination-knobs.d.ts +1 -1
- package/dist/knob-contracts/pagination-knobs.js +2 -1
- package/dist/knob-contracts/popup-knobs.d.ts +1 -1
- package/dist/knob-contracts/popup-knobs.js +9 -0
- package/dist/knob-contracts/range-knobs.d.ts +1 -1
- package/dist/knob-contracts/range-knobs.js +2 -0
- package/dist/knob-contracts/sidebar-knobs.d.ts +1 -1
- package/dist/knob-contracts/sidebar-knobs.js +2 -0
- package/dist/knob-contracts/tabs-knobs.d.ts +1 -1
- package/dist/knob-contracts/tabs-knobs.js +3 -0
- package/dist/knob-contracts/timeline-knobs.d.ts +1 -1
- package/dist/knob-contracts/timeline-knobs.js +4 -1
- package/dist/knob-contracts/tree-knobs.d.ts +1 -1
- package/dist/knob-contracts/tree-knobs.js +3 -1
- package/dist/skin.d.ts +2 -0
- package/dist/styles/index.css +2 -3
- package/dist/styles/recipes/activity.css +4 -0
- package/dist/styles/recipes/avatar.css +1 -1
- package/dist/styles/recipes/badge.css +17 -0
- package/dist/styles/recipes/button.css +8 -1
- package/dist/styles/recipes/calendar.css +82 -6
- package/dist/styles/recipes/card.css +40 -5
- package/dist/styles/recipes/choice.css +9 -2
- package/dist/styles/recipes/collapsible.css +8 -1
- package/dist/styles/recipes/color-picker-values.css +4 -0
- package/dist/styles/recipes/emoji-picker.css +29 -8
- package/dist/styles/recipes/empty.css +5 -0
- package/dist/styles/recipes/field-parts.css +80 -5
- package/dist/styles/recipes/field.css +113 -40
- package/dist/styles/recipes/item.css +44 -5
- package/dist/styles/recipes/kbd.css +26 -6
- package/dist/styles/recipes/morphing-panel.css +1 -1
- package/dist/styles/recipes/page-layout.css +18 -2
- package/dist/styles/recipes/pagination.css +8 -0
- package/dist/styles/recipes/popup-controls.css +41 -0
- package/dist/styles/recipes/popup-drawer.css +1 -0
- package/dist/styles/recipes/popup-lists.css +55 -6
- package/dist/styles/recipes/popup-motion.css +7 -1
- package/dist/styles/recipes/popup.css +10 -0
- package/dist/styles/recipes/range.css +16 -2
- package/dist/styles/recipes/sidebar-mobile.css +1 -1
- package/dist/styles/recipes/sidebar-parts.css +17 -1
- package/dist/styles/recipes/sidebar.css +11 -0
- package/dist/styles/recipes/skeleton.css +8 -0
- package/dist/styles/recipes/tabs.css +41 -8
- package/dist/styles/recipes/timeline.css +25 -2
- package/dist/styles/recipes/tree.css +33 -0
- package/dist/styles/theme.css +11 -1
- package/dist/surface-variants.d.ts +2 -0
- package/dist/surface-variants.js +2 -1
- package/dist/ui/alert-dialog.js +1 -1
- package/dist/ui/badge.js +1 -1
- package/dist/ui/calendar.js +9 -4
- package/dist/ui/card.d.ts +3 -1
- package/dist/ui/card.js +2 -1
- package/dist/ui/context-menu.d.ts +3 -1
- package/dist/ui/context-menu.js +2 -1
- package/dist/ui/dialog.js +1 -1
- package/dist/ui/dropdown-menu.d.ts +6 -3
- package/dist/ui/dropdown-menu.js +25 -7
- package/dist/ui/dropzone.js +10 -11
- package/dist/ui/empty.d.ts +4 -1
- package/dist/ui/empty.js +4 -2
- package/dist/ui/field.d.ts +6 -2
- package/dist/ui/field.js +4 -2
- package/dist/ui/menubar.d.ts +3 -1
- package/dist/ui/menubar.js +2 -1
- package/dist/ui/morphing-panel.d.ts +5 -1
- package/dist/ui/morphing-panel.js +4 -2
- package/dist/ui/select.js +2 -2
- package/dist/ui/sheet.d.ts +9 -0
- package/dist/ui/sheet.js +23 -1
- package/dist/ui/sidebar-mobile.js +1 -1
- package/dist/ui/sidebar-provider.d.ts +3 -1
- package/dist/ui/sidebar-provider.js +3 -2
- package/dist/ui/sidebar-resize-rail.js +1 -1
- package/dist/ui/sidebar.d.ts +6 -5
- package/dist/ui/sidebar.js +10 -9
- package/dist/ui/skeleton.d.ts +4 -1
- package/dist/ui/skeleton.js +8 -2
- package/dist/ui/tabs.d.ts +1 -1
- package/dist/ui/tabs.js +2 -13
- package/dist/ui/timeline.js +1 -1
- package/dist/ui/typography.d.ts +11 -5
- package/dist/ui/typography.js +18 -6
- package/lint/biome-preset.json +3 -0
- package/lint/class-policy.mjs +17 -0
- package/lint/eslint-plugin.mjs +87 -0
- package/lint/grit-rules.mjs +40 -0
- package/lint/no-component-style-classes.grit +16 -0
- package/lint/no-raw-type-classes.grit +2 -3
- package/lint/write-grit-rules.mjs +19 -0
- package/package.json +11 -2
- package/dist/styles/type-scale.css +0 -72
package/README.md
CHANGED
|
@@ -47,10 +47,46 @@ const twMerge = extendTailwindMerge({ extend: { classGroups: { "font-size": [{ t
|
|
|
47
47
|
|
|
48
48
|
Controls size their own text: pick the control's `size`, or set its `--cui-*-font-size` knob in your theme, rather than wrapping the label in a `text-*` span.
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
## Lint rules
|
|
51
|
+
|
|
52
|
+
Two rules keep call sites honest, shipped for Biome, ESLint, and oxlint from one policy (`lint/class-policy.mjs`):
|
|
53
|
+
|
|
54
|
+
- `no-component-style-classes` errors when `className` on a component imported from `@ctrl-ui/react` (or a `components/control-ui` directory) sets what the component owns: colors, type, padding, borders, radius, shadows, state styles such as `hover:` and `data-[…]:`, or `!important`. Layout classes (`flex`, `gap-*`, widths, heights, margins, placement) stay allowed. Restyle through the component's props or its `--cui-*` knobs instead.
|
|
55
|
+
- `no-raw-type-classes` errors on text sizes in any `className`: the type rungs, Tailwind's `text-xs`…`text-9xl`, and arbitrary `text-[13px]`. It reaches beyond Control UI, so adopt it folder by folder while you migrate.
|
|
56
|
+
|
|
57
|
+
Biome, extending the shipped preset so rules added later arrive with the package update:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"extends": ["@ctrl-ui/react/biome"],
|
|
62
|
+
"overrides": [{ "includes": ["src/features/**"], "plugins": ["./node_modules/@ctrl-ui/react/lint/no-raw-type-classes.grit"] }]
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
ESLint flat config:
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
import controlUi from "@ctrl-ui/react/eslint-plugin";
|
|
70
|
+
|
|
71
|
+
export default [{ plugins: { "control-ui": controlUi }, rules: { "control-ui/no-component-style-classes": "error" } }];
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
oxlint, through its JS plugin support:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{ "jsPlugins": ["@ctrl-ui/react/eslint-plugin"], "rules": { "control-ui/no-component-style-classes": "error" } }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
When your app imports components through its own wrapper package or folder, declare that path so the rule follows those imports too:
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
rules: { "control-ui/no-component-style-classes": ["error", { importSources: ["@acme/ui/components/"] }] }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Biome's Grit plugins take no options, so the package ships `control-ui-grit` to write the rules with your paths. Run it on install so a package update regenerates them, gitignore `.control-ui`, and list `./.control-ui/no-component-style-classes.grit` under `plugins` in place of the preset:
|
|
51
87
|
|
|
52
88
|
```json
|
|
53
|
-
{ "
|
|
89
|
+
{ "scripts": { "postinstall": "control-ui-grit --import-source=@acme/ui/components/ --out=.control-ui" } }
|
|
54
90
|
```
|
|
55
91
|
|
|
56
92
|
## Customize
|
package/dist/activity.d.ts
CHANGED
|
@@ -45,8 +45,10 @@ export type ActivityDetailProps = ComponentProps<"div"> & {
|
|
|
45
45
|
export declare function ActivityDetail({ className, ...props }: ActivityDetailProps): import("react").JSX.Element;
|
|
46
46
|
export type ActivityDetailLabelProps = ActivityStyleProps<ComponentProps<"div">, ActivityKnobStyle>;
|
|
47
47
|
export declare function ActivityDetailLabel({ className, ...props }: ActivityDetailLabelProps): import("react").JSX.Element;
|
|
48
|
+
export type ActivityDetailTone = "default" | "destructive";
|
|
48
49
|
export type ActivityDetailContentProps = ActivityStyleProps<ComponentProps<"div">, ActivityKnobStyle> & {
|
|
49
50
|
format?: ActivityDetailFormat;
|
|
51
|
+
tone?: ActivityDetailTone;
|
|
50
52
|
};
|
|
51
|
-
export declare function ActivityDetailContent({ format, className, ...props }: ActivityDetailContentProps): import("react").JSX.Element;
|
|
53
|
+
export declare function ActivityDetailContent({ format, tone, className, ...props }: ActivityDetailContentProps): import("react").JSX.Element;
|
|
52
54
|
//#endregion
|
package/dist/activity.js
CHANGED
|
@@ -168,12 +168,13 @@ function ActivityDetailLabel({ className, ...props }) {
|
|
|
168
168
|
className: cn("uppercase", className)
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
|
-
function ActivityDetailContent({ format = "text", className, ...props }) {
|
|
171
|
+
function ActivityDetailContent({ format = "text", tone = "default", className, ...props }) {
|
|
172
172
|
return /* @__PURE__ */ jsx("div", {
|
|
173
173
|
"data-control-ui": "activity",
|
|
174
174
|
"data-control-family": "activity",
|
|
175
175
|
"data-slot": "detail-content",
|
|
176
176
|
"data-format": format,
|
|
177
|
+
"data-tone": tone,
|
|
177
178
|
...props,
|
|
178
179
|
className: cn("min-w-0 whitespace-pre-wrap wrap-anywhere", format === "code" && "w-fit max-w-full", className)
|
|
179
180
|
});
|
|
@@ -5,30 +5,30 @@ import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, Sideba
|
|
|
5
5
|
import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarRail } from "../ui/sidebar.js";
|
|
6
6
|
import { agentRunStatusLabels } from "./agent-run-status.js";
|
|
7
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
-
import { BotIcon,
|
|
8
|
+
import { BotIcon, CheckIcon, CircleAlertIcon, CircleDashedIcon, CirclePauseIcon, CircleSlashIcon, LoaderCircleIcon, PlusIcon } from "lucide-react";
|
|
9
9
|
//#region src/blocks/agent-run-sidebar.tsx
|
|
10
10
|
const runStatusIcons = {
|
|
11
|
-
running: /* @__PURE__ */ jsx(
|
|
11
|
+
running: /* @__PURE__ */ jsx(LoaderCircleIcon, {
|
|
12
12
|
className: "size-3.5 shrink-0 motion-safe:animate-spin",
|
|
13
13
|
"aria-hidden": "true"
|
|
14
14
|
}),
|
|
15
|
-
waiting: /* @__PURE__ */ jsx(
|
|
15
|
+
waiting: /* @__PURE__ */ jsx(CirclePauseIcon, {
|
|
16
16
|
className: "size-3.5 shrink-0 text-warning-text",
|
|
17
17
|
"aria-hidden": "true"
|
|
18
18
|
}),
|
|
19
|
-
success: /* @__PURE__ */ jsx(
|
|
19
|
+
success: /* @__PURE__ */ jsx(CheckIcon, {
|
|
20
20
|
className: "size-3.5 shrink-0 text-success-text",
|
|
21
21
|
"aria-hidden": "true"
|
|
22
22
|
}),
|
|
23
|
-
error: /* @__PURE__ */ jsx(
|
|
23
|
+
error: /* @__PURE__ */ jsx(CircleAlertIcon, {
|
|
24
24
|
className: "size-3.5 shrink-0 text-destructive-text",
|
|
25
25
|
"aria-hidden": "true"
|
|
26
26
|
}),
|
|
27
|
-
cancelled: /* @__PURE__ */ jsx(
|
|
27
|
+
cancelled: /* @__PURE__ */ jsx(CircleSlashIcon, {
|
|
28
28
|
className: "size-3.5 shrink-0 text-muted-foreground",
|
|
29
29
|
"aria-hidden": "true"
|
|
30
30
|
}),
|
|
31
|
-
pending: /* @__PURE__ */ jsx(
|
|
31
|
+
pending: /* @__PURE__ */ jsx(CircleDashedIcon, {
|
|
32
32
|
className: "size-3.5 shrink-0 text-muted-foreground",
|
|
33
33
|
"aria-hidden": "true"
|
|
34
34
|
})
|
|
@@ -39,7 +39,8 @@ function AgentRunSidebar({ appName, brand, runs, activeRunId, sidebarFooter, onR
|
|
|
39
39
|
collapsible: "offcanvas",
|
|
40
40
|
children: [
|
|
41
41
|
/* @__PURE__ */ jsxs(SidebarHeader, {
|
|
42
|
-
|
|
42
|
+
divider: true,
|
|
43
|
+
className: "gap-1.5",
|
|
43
44
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
44
45
|
className: "flex min-w-0 items-center gap-2 px-1 py-1",
|
|
45
46
|
children: [brand ?? /* @__PURE__ */ jsx("span", {
|
|
@@ -65,11 +66,11 @@ function AgentRunSidebar({ appName, brand, runs, activeRunId, sidebarFooter, onR
|
|
|
65
66
|
}) }) }) : null]
|
|
66
67
|
}),
|
|
67
68
|
/* @__PURE__ */ jsx(SidebarContent, { children: /* @__PURE__ */ jsxs(SidebarGroup, {
|
|
68
|
-
className: "gap-1
|
|
69
|
+
className: "gap-1",
|
|
69
70
|
children: [/* @__PURE__ */ jsx(SidebarGroupLabel, { children: "Runs" }), runs.length === 0 ? /* @__PURE__ */ jsx(Text, {
|
|
70
71
|
size: "caption",
|
|
71
72
|
tone: "muted",
|
|
72
|
-
className: "
|
|
73
|
+
className: "mx-2",
|
|
73
74
|
children: "No runs yet"
|
|
74
75
|
}) : /* @__PURE__ */ jsx(SidebarMenu, { children: runs.map((run) => /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
|
|
75
76
|
size: "sm",
|
|
@@ -4,6 +4,7 @@ import { Card } from "../ui/card.js";
|
|
|
4
4
|
import { SidebarProviderProps } from "../ui/sidebar-provider.js";
|
|
5
5
|
import "../ui/sidebar.js";
|
|
6
6
|
import { TimelineItemProps } from "../ui/timeline.js";
|
|
7
|
+
import { TypeSize } from "../ui/typography.js";
|
|
7
8
|
import { ComponentProps, ReactNode } from "react";
|
|
8
9
|
//#region src/blocks/agent-run.d.ts
|
|
9
10
|
type AgentRunLayout = "viewport" | "contained";
|
|
@@ -22,8 +23,9 @@ export declare function AgentRunBlock({ appName, brand, runs, activeRunId, onRun
|
|
|
22
23
|
export type AgentRunElapsedProps = Omit<ComponentProps<"time">, "dateTime" | "children"> & {
|
|
23
24
|
startedAt: number;
|
|
24
25
|
endedAt?: number;
|
|
26
|
+
size?: TypeSize;
|
|
25
27
|
};
|
|
26
|
-
export declare function AgentRunElapsed({ startedAt, endedAt, className, ...props }: AgentRunElapsedProps): import("react").JSX.Element;
|
|
28
|
+
export declare function AgentRunElapsed({ startedAt, endedAt, size, className, ...props }: AgentRunElapsedProps): import("react").JSX.Element;
|
|
27
29
|
export type AgentRunHeaderProps = Omit<ComponentProps<"header">, "title"> & {
|
|
28
30
|
title: string;
|
|
29
31
|
status: AgentRunStatus;
|
package/dist/blocks/agent-run.js
CHANGED
|
@@ -32,7 +32,8 @@ function AgentRunBlock({ appName = "Agents", brand, runs, activeRunId, onRunSele
|
|
|
32
32
|
};
|
|
33
33
|
return /* @__PURE__ */ jsxs(SidebarProvider, {
|
|
34
34
|
layout,
|
|
35
|
-
|
|
35
|
+
surface: "background",
|
|
36
|
+
className: cn(layout === "viewport" && "h-svh overflow-hidden", className),
|
|
36
37
|
style: providerStyle,
|
|
37
38
|
...props,
|
|
38
39
|
children: [/* @__PURE__ */ jsx(AgentRunSidebar, {
|
|
@@ -52,15 +53,20 @@ function AgentRunBlock({ appName = "Agents", brand, runs, activeRunId, onRunSele
|
|
|
52
53
|
})]
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
|
-
function AgentRunElapsed({ startedAt, endedAt, className, ...props }) {
|
|
56
|
+
function AgentRunElapsed({ startedAt, endedAt, size = "label", className, ...props }) {
|
|
56
57
|
const now = useRunClock(endedAt === void 0);
|
|
57
58
|
const end = endedAt ?? now;
|
|
58
59
|
const ms = end === null ? null : Math.max(0, end - startedAt);
|
|
59
|
-
return /* @__PURE__ */ jsx(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
61
|
+
size,
|
|
62
|
+
tone: "muted",
|
|
63
|
+
numeric: true,
|
|
64
|
+
className,
|
|
65
|
+
children: /* @__PURE__ */ jsx("time", {
|
|
66
|
+
dateTime: ms === null ? void 0 : elapsedIsoDuration(ms),
|
|
67
|
+
...props,
|
|
68
|
+
children: ms === null ? "" : formatElapsed(ms)
|
|
69
|
+
})
|
|
64
70
|
});
|
|
65
71
|
}
|
|
66
72
|
function AgentRunHeader({ title, status, startedAt, endedAt, actions, className, ...props }) {
|
|
@@ -89,7 +95,7 @@ function AgentRunHeader({ title, status, startedAt, endedAt, actions, className,
|
|
|
89
95
|
startedAt === void 0 ? null : /* @__PURE__ */ jsx(AgentRunElapsed, {
|
|
90
96
|
startedAt,
|
|
91
97
|
endedAt,
|
|
92
|
-
|
|
98
|
+
size: "body"
|
|
93
99
|
}),
|
|
94
100
|
/* @__PURE__ */ jsx("div", {
|
|
95
101
|
className: "ms-auto flex shrink-0 items-center gap-1",
|
|
@@ -205,7 +211,7 @@ function AgentRunToolCall({ name, summary, icon, input, output, errorText, start
|
|
|
205
211
|
children: formatToolValue(output)
|
|
206
212
|
})] }),
|
|
207
213
|
errorText === void 0 ? null : /* @__PURE__ */ jsxs(ActivityDetail, { children: [/* @__PURE__ */ jsx(ActivityDetailLabel, { children: "Error" }), /* @__PURE__ */ jsx(ActivityDetailContent, {
|
|
208
|
-
|
|
214
|
+
tone: "destructive",
|
|
209
215
|
children: errorText
|
|
210
216
|
})] })
|
|
211
217
|
] }) : null]
|
|
@@ -236,13 +242,15 @@ function AgentRunDetails({ title = "Details", items, ...props }) {
|
|
|
236
242
|
title,
|
|
237
243
|
...props,
|
|
238
244
|
children: /* @__PURE__ */ jsx("dl", {
|
|
239
|
-
className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-4 gap-y-2
|
|
245
|
+
className: "grid grid-cols-[auto_minmax(0,1fr)] gap-x-4 gap-y-2",
|
|
240
246
|
children: items.map((item) => /* @__PURE__ */ jsxs("div", {
|
|
241
247
|
className: "contents",
|
|
242
|
-
children: [/* @__PURE__ */ jsx(
|
|
243
|
-
|
|
248
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
249
|
+
as: "dt",
|
|
250
|
+
tone: "muted",
|
|
244
251
|
children: item.label
|
|
245
|
-
}), /* @__PURE__ */ jsx(
|
|
252
|
+
}), /* @__PURE__ */ jsx(Text, {
|
|
253
|
+
as: "dd",
|
|
246
254
|
className: "min-w-0 break-words",
|
|
247
255
|
children: item.value
|
|
248
256
|
})]
|
|
@@ -5,8 +5,9 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../ui/colla
|
|
|
5
5
|
import { Heading, Text } from "../ui/typography.js";
|
|
6
6
|
import { ChatLayout, ChatThread } from "../chat-layout.js";
|
|
7
7
|
import { SidebarProvider, useSidebar } from "../ui/sidebar-provider.js";
|
|
8
|
-
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "../ui/sidebar-menu.js";
|
|
8
|
+
import { SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSub } from "../ui/sidebar-menu.js";
|
|
9
9
|
import { Sidebar, SidebarContent, SidebarFooter, SidebarHeader, SidebarInset, SidebarRail, SidebarTrigger } from "../ui/sidebar.js";
|
|
10
|
+
import { Item, ItemContent, ItemDescription, ItemMedia, ItemTitle } from "../ui/item.js";
|
|
10
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
12
|
import { BotIcon, ChevronRightIcon, CircleIcon, FolderIcon, PlusIcon, SearchIcon } from "lucide-react";
|
|
12
13
|
//#region src/blocks/coding-agent.tsx
|
|
@@ -17,7 +18,8 @@ function CodingAgentBlock({ appName = "Agent", brand, sidebarTop, navigation = [
|
|
|
17
18
|
};
|
|
18
19
|
return /* @__PURE__ */ jsxs(SidebarProvider, {
|
|
19
20
|
layout,
|
|
20
|
-
|
|
21
|
+
surface: "background",
|
|
22
|
+
className: cn(layout === "viewport" && "h-svh overflow-hidden", className),
|
|
21
23
|
style: providerStyle,
|
|
22
24
|
...props,
|
|
23
25
|
children: [/* @__PURE__ */ jsx(CodingAgentSidebar, {
|
|
@@ -78,7 +80,8 @@ function CodingAgentSidebar({ appName, brand, sidebarTop, navigation, projects,
|
|
|
78
80
|
collapsible: "offcanvas",
|
|
79
81
|
children: [
|
|
80
82
|
/* @__PURE__ */ jsxs(SidebarHeader, {
|
|
81
|
-
|
|
83
|
+
divider: true,
|
|
84
|
+
className: "gap-1.5",
|
|
82
85
|
children: [
|
|
83
86
|
sidebarTop,
|
|
84
87
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -117,25 +120,22 @@ function CodingAgentSidebar({ appName, brand, sidebarTop, navigation, projects,
|
|
|
117
120
|
}) }) })
|
|
118
121
|
]
|
|
119
122
|
}),
|
|
120
|
-
/* @__PURE__ */ jsxs(SidebarContent, { children: [navigation.length > 0 ? /* @__PURE__ */ jsx(SidebarGroup, {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
children:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
item.trailing
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}) }, item.id)) })
|
|
137
|
-
}) : null, /* @__PURE__ */ jsxs(SidebarGroup, {
|
|
138
|
-
className: "gap-1 pt-1",
|
|
123
|
+
/* @__PURE__ */ jsxs(SidebarContent, { children: [navigation.length > 0 ? /* @__PURE__ */ jsx(SidebarGroup, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: navigation.map((item) => /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
|
|
124
|
+
size: "sm",
|
|
125
|
+
onClick: () => {
|
|
126
|
+
onNavigationSelect?.(item);
|
|
127
|
+
finishMobileNavigation();
|
|
128
|
+
},
|
|
129
|
+
children: [
|
|
130
|
+
item.icon,
|
|
131
|
+
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
132
|
+
item.trailing ? /* @__PURE__ */ jsx("span", {
|
|
133
|
+
className: "ms-auto shrink-0",
|
|
134
|
+
children: item.trailing
|
|
135
|
+
}) : null
|
|
136
|
+
]
|
|
137
|
+
}) }, item.id)) }) }) : null, /* @__PURE__ */ jsxs(SidebarGroup, {
|
|
138
|
+
className: "gap-1",
|
|
139
139
|
children: [/* @__PURE__ */ jsx(SidebarGroupLabel, { children: "Projects" }), /* @__PURE__ */ jsx("div", {
|
|
140
140
|
className: "grid gap-1",
|
|
141
141
|
children: projects.map((project) => /* @__PURE__ */ jsxs(Collapsible, {
|
|
@@ -157,28 +157,25 @@ function CodingAgentSidebar({ appName, brand, sidebarTop, navigation, projects,
|
|
|
157
157
|
className: "truncate",
|
|
158
158
|
children: project.name
|
|
159
159
|
})
|
|
160
|
-
] }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
task.trailing
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
]
|
|
180
|
-
}) }, task.id))
|
|
181
|
-
}) })]
|
|
160
|
+
] }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx(SidebarMenuSub, { children: project.tasks.map((task) => /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
|
|
161
|
+
size: "sm",
|
|
162
|
+
isActive: task.id === activeTaskId,
|
|
163
|
+
onClick: () => {
|
|
164
|
+
onTaskSelect?.(task, project);
|
|
165
|
+
finishMobileNavigation();
|
|
166
|
+
},
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ jsx(CircleIcon, {
|
|
169
|
+
className: "size-1.5 fill-current opacity-35",
|
|
170
|
+
"aria-hidden": "true"
|
|
171
|
+
}),
|
|
172
|
+
/* @__PURE__ */ jsx("span", { children: task.title }),
|
|
173
|
+
task.trailing ? /* @__PURE__ */ jsx("span", {
|
|
174
|
+
className: "ms-auto shrink-0",
|
|
175
|
+
children: task.trailing
|
|
176
|
+
}) : null
|
|
177
|
+
]
|
|
178
|
+
}) }, task.id)) }) })]
|
|
182
179
|
}, project.id))
|
|
183
180
|
})]
|
|
184
181
|
})] }),
|
|
@@ -228,31 +225,15 @@ function CodingAgentEmptyState({ title = "What should we build?", description, i
|
|
|
228
225
|
}) : null,
|
|
229
226
|
suggestions.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
230
227
|
className: "mt-8 grid w-full grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
|
|
231
|
-
children: suggestions.map((suggestion) => /* @__PURE__ */
|
|
232
|
-
variant: "
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
className: "text-primary-text",
|
|
241
|
-
children: suggestion.icon
|
|
242
|
-
}),
|
|
243
|
-
/* @__PURE__ */ jsx(Text, {
|
|
244
|
-
weight: "medium",
|
|
245
|
-
tone: "foreground",
|
|
246
|
-
children: suggestion.title
|
|
247
|
-
}),
|
|
248
|
-
suggestion.description ? /* @__PURE__ */ jsx(Text, {
|
|
249
|
-
size: "caption",
|
|
250
|
-
tone: "muted",
|
|
251
|
-
className: "leading-5",
|
|
252
|
-
children: suggestion.description
|
|
253
|
-
}) : null
|
|
254
|
-
]
|
|
255
|
-
})
|
|
228
|
+
children: suggestions.map((suggestion) => /* @__PURE__ */ jsxs(Item, {
|
|
229
|
+
variant: "outline",
|
|
230
|
+
render: /* @__PURE__ */ jsx("button", {
|
|
231
|
+
type: "button",
|
|
232
|
+
onClick: () => onSuggestionSelect?.(suggestion.prompt ?? suggestion.title, suggestion)
|
|
233
|
+
}),
|
|
234
|
+
className: "min-h-28 w-full flex-col items-start text-start",
|
|
235
|
+
style: { "--cui-item-media-foreground": "var(--primary-text)" },
|
|
236
|
+
children: [/* @__PURE__ */ jsx(ItemMedia, { children: suggestion.icon }), /* @__PURE__ */ jsxs(ItemContent, { children: [/* @__PURE__ */ jsx(ItemTitle, { children: suggestion.title }), suggestion.description ? /* @__PURE__ */ jsx(ItemDescription, { children: suggestion.description }) : null] })]
|
|
256
237
|
}, suggestion.id))
|
|
257
238
|
}) : null
|
|
258
239
|
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Button } from "../ui/button.js";
|
|
3
3
|
import { Heading } from "../ui/typography.js";
|
|
4
|
+
import { Separator } from "../ui/separator.js";
|
|
4
5
|
import { resizeDesignCanvasLayer } from "./design-canvas-data.js";
|
|
5
6
|
import { ColorPickerArea } from "../ui/color-picker-area.js";
|
|
6
7
|
import { ColorPickerHue } from "../ui/color-picker-sliders.js";
|
|
@@ -9,7 +10,6 @@ import { NumberField, NumberFieldGroup, NumberFieldInput, NumberFieldScrubArea }
|
|
|
9
10
|
import { ColorPickerEyeDropper, ColorPickerInput } from "../ui/color-picker-values.js";
|
|
10
11
|
import { ColorPicker, ColorPickerContent, ColorPickerTrigger } from "../ui/color-picker.js";
|
|
11
12
|
import { Empty, EmptyDescription, EmptyHeader, EmptyTitle } from "../ui/empty.js";
|
|
12
|
-
import { Separator } from "../ui/separator.js";
|
|
13
13
|
import { Toggle } from "../ui/toggle.js";
|
|
14
14
|
import { useState } from "react";
|
|
15
15
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -11,7 +11,7 @@ import { Toolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator } from "../ui/to
|
|
|
11
11
|
import { InfiniteCanvas, InfiniteCanvasContent, InfiniteCanvasControls, InfiniteCanvasItem } from "../ui/infinite-canvas.js";
|
|
12
12
|
import { ResizableFloatingPanel } from "../ui/resizable.js";
|
|
13
13
|
import { useRef, useState } from "react";
|
|
14
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
15
15
|
import { CircleIcon, FrameIcon, HandIcon, LayersIcon, MousePointer2Icon, SlidersHorizontalIcon, SquareIcon, TypeIcon } from "lucide-react";
|
|
16
16
|
//#region src/blocks/design-canvas.tsx
|
|
17
17
|
const TOOLS = [
|
|
@@ -53,10 +53,10 @@ const TOOLS = [
|
|
|
53
53
|
}
|
|
54
54
|
];
|
|
55
55
|
const LAYER_ICONS = {
|
|
56
|
-
frame: /* @__PURE__ */ jsx(FrameIcon, {}),
|
|
57
|
-
rectangle: /* @__PURE__ */ jsx(SquareIcon, {}),
|
|
58
|
-
ellipse: /* @__PURE__ */ jsx(CircleIcon, {}),
|
|
59
|
-
text: /* @__PURE__ */ jsx(TypeIcon, {})
|
|
56
|
+
frame: /* @__PURE__ */ jsx(FrameIcon, { className: "text-muted-foreground" }),
|
|
57
|
+
rectangle: /* @__PURE__ */ jsx(SquareIcon, { className: "text-muted-foreground" }),
|
|
58
|
+
ellipse: /* @__PURE__ */ jsx(CircleIcon, { className: "text-muted-foreground" }),
|
|
59
|
+
text: /* @__PURE__ */ jsx(TypeIcon, { className: "text-muted-foreground" })
|
|
60
60
|
};
|
|
61
61
|
const NUDGE_DIRECTIONS = {
|
|
62
62
|
ArrowLeft: {
|
|
@@ -246,7 +246,7 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
|
|
|
246
246
|
onPointerCancel: cancelDraft,
|
|
247
247
|
onKeyDown: handleShortcut,
|
|
248
248
|
children: [/* @__PURE__ */ jsxs(InfiniteCanvasContent, {
|
|
249
|
-
className: cn(tool !== "move" && "
|
|
249
|
+
className: cn(tool !== "move" && "pointer-events-none"),
|
|
250
250
|
children: [currentLayers.map((layer) => /* @__PURE__ */ jsx(DesignCanvasLayerNode, {
|
|
251
251
|
layer,
|
|
252
252
|
selected: layer.id === currentSelectedLayerId,
|
|
@@ -288,7 +288,6 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
|
|
|
288
288
|
onOpenChange: setLayersOpen,
|
|
289
289
|
children: /* @__PURE__ */ jsx(DrawerContent, {
|
|
290
290
|
side: "left",
|
|
291
|
-
className: "gap-0 p-0",
|
|
292
291
|
children: /* @__PURE__ */ jsx(DesignCanvasPanel, {
|
|
293
292
|
label: layersLabel,
|
|
294
293
|
title: layersLabel,
|
|
@@ -303,7 +302,6 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
|
|
|
303
302
|
onOpenChange: setPropertiesOpen,
|
|
304
303
|
children: /* @__PURE__ */ jsx(DrawerContent, {
|
|
305
304
|
side: "right",
|
|
306
|
-
className: "gap-0 p-0",
|
|
307
305
|
children: /* @__PURE__ */ jsx(DesignCanvasPanel, {
|
|
308
306
|
label: propertiesLabel,
|
|
309
307
|
title: propertiesTitle,
|
|
@@ -353,24 +351,27 @@ function DesignCanvasBlock({ layers, defaultLayers = [], onLayersChange, selecte
|
|
|
353
351
|
});
|
|
354
352
|
}
|
|
355
353
|
function DesignCanvasPanel({ label, title, inDrawer = false, children }) {
|
|
356
|
-
const titleClassName = "flex h-11 shrink-0 items-center border-b px-3";
|
|
357
|
-
const titleText = /* @__PURE__ */ jsx("span", {
|
|
358
|
-
className: "truncate",
|
|
359
|
-
title,
|
|
360
|
-
children: title
|
|
361
|
-
});
|
|
362
354
|
return /* @__PURE__ */ jsxs("aside", {
|
|
363
355
|
"aria-label": label,
|
|
364
356
|
className: "flex min-h-0 flex-1 flex-col",
|
|
365
|
-
children: [
|
|
366
|
-
className:
|
|
367
|
-
children:
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
357
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
358
|
+
className: "flex h-11 shrink-0 items-center border-b px-3",
|
|
359
|
+
children: inDrawer ? /* @__PURE__ */ jsx(DrawerTitle, {
|
|
360
|
+
className: "truncate",
|
|
361
|
+
title,
|
|
362
|
+
style: {
|
|
363
|
+
"--cui-popup-title-font-size": "var(--text-caption)",
|
|
364
|
+
"--cui-popup-title-font-weight": "var(--font-weight-medium)"
|
|
365
|
+
},
|
|
366
|
+
children: title
|
|
367
|
+
}) : /* @__PURE__ */ jsx(Heading, {
|
|
368
|
+
level: 2,
|
|
369
|
+
size: "caption",
|
|
370
|
+
weight: "medium",
|
|
371
|
+
className: "truncate",
|
|
372
|
+
title,
|
|
373
|
+
children: title
|
|
374
|
+
})
|
|
374
375
|
}), /* @__PURE__ */ jsx(ScrollArea, {
|
|
375
376
|
className: "min-h-0 flex-1",
|
|
376
377
|
children
|
|
@@ -385,7 +386,8 @@ function DesignCanvasLayerList({ layers, selectedLayerId, onSelect }) {
|
|
|
385
386
|
size: "sm",
|
|
386
387
|
active: layer.id === selectedLayerId,
|
|
387
388
|
"aria-pressed": layer.id === selectedLayerId,
|
|
388
|
-
className: "w-full justify-start
|
|
389
|
+
className: "w-full justify-start",
|
|
390
|
+
style: { "--cui-button-icon": "calc(var(--spacing) * 3.5)" },
|
|
389
391
|
onClick: () => onSelect(layer.id),
|
|
390
392
|
children: [LAYER_ICONS[layer.kind], /* @__PURE__ */ jsx("span", {
|
|
391
393
|
className: "truncate",
|
|
@@ -407,7 +409,6 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onKeyDown, onLayerCh
|
|
|
407
409
|
"aria-pressed": interactive ? selected : void 0,
|
|
408
410
|
"aria-keyshortcuts": interactive ? LAYER_KEY_SHORTCUTS : void 0,
|
|
409
411
|
"data-selected": selected || void 0,
|
|
410
|
-
className: "outline-primary data-selected:outline-2",
|
|
411
412
|
style: {
|
|
412
413
|
width: layer.width,
|
|
413
414
|
height: layer.height,
|
|
@@ -442,15 +443,21 @@ function DesignCanvasLayerNode({ layer, selected, onSelect, onKeyDown, onLayerCh
|
|
|
442
443
|
borderRadius: layer.kind === "ellipse" ? "50%" : layer.cornerRadius
|
|
443
444
|
}
|
|
444
445
|
}),
|
|
445
|
-
selected ? /* @__PURE__ */ jsxs(
|
|
446
|
-
|
|
447
|
-
className: "absolute inset-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
446
|
+
selected ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
447
|
+
"aria-hidden": "true",
|
|
448
|
+
className: "absolute inset-0 outline-2 outline-primary"
|
|
449
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
450
|
+
className: "absolute inset-x-0 top-full mx-auto mt-1.5 flex w-max rounded-sm bg-primary px-1 whitespace-nowrap text-primary-foreground",
|
|
451
|
+
children: /* @__PURE__ */ jsxs(Text, {
|
|
452
|
+
size: "micro",
|
|
453
|
+
numeric: true,
|
|
454
|
+
children: [
|
|
455
|
+
layer.width,
|
|
456
|
+
" × ",
|
|
457
|
+
layer.height
|
|
458
|
+
]
|
|
459
|
+
})
|
|
460
|
+
})] }) : null
|
|
454
461
|
]
|
|
455
462
|
});
|
|
456
463
|
}
|
|
@@ -70,7 +70,7 @@ function DiscussionComposer({ label, placeholder, submitLabel = "Post", secondar
|
|
|
70
70
|
error ? /* @__PURE__ */ jsx(Text, {
|
|
71
71
|
as: "p",
|
|
72
72
|
role: "alert",
|
|
73
|
-
className: "
|
|
73
|
+
className: "mx-3",
|
|
74
74
|
children: error
|
|
75
75
|
}) : null,
|
|
76
76
|
/* @__PURE__ */ jsxs(ChatComposerToolbar, { children: [/* @__PURE__ */ jsx(Text, {
|