@vllnt/ui 0.3.0-canary.a42d8f4 → 0.3.0-canary.e1218e7
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/CHANGELOG.md +2 -0
- package/dist/components/activity-log/activity-log.js +5 -5
- package/dist/components/agent-activity/agent-activity.js +11 -5
- package/dist/components/ai-artifact/ai-artifact.js +23 -6
- package/dist/components/ai-chat-input/ai-chat-input.js +3 -1
- package/dist/components/ai-message-bubble/ai-message-bubble.js +1 -1
- package/dist/components/ai-sidebar/ai-sidebar.js +1 -0
- package/dist/components/auto-reload/auto-reload.js +28 -4
- package/dist/components/blog-card/blog-card.js +1 -1
- package/dist/components/candlestick-chart/candlestick-chart.js +7 -7
- package/dist/components/canvas-shell/canvas-foundation-demo.js +8 -8
- package/dist/components/canvas-shell/canvas-shell.js +6 -3
- package/dist/components/canvas-view/canvas-view.js +71 -28
- package/dist/components/chain-of-thought/chain-of-thought.js +77 -0
- package/dist/components/chain-of-thought/index.js +6 -0
- package/dist/components/choropleth-map/choropleth-map.js +6 -1
- package/dist/components/chronological-timeline/chronological-timeline.js +1 -1
- package/dist/components/civilization-card/civilization-card.js +18 -1
- package/dist/components/code-block/code-block.js +10 -10
- package/dist/components/code-playground/code-playground.js +4 -1
- package/dist/components/combobox/combobox.js +2 -2
- package/dist/components/content-intro/content-intro.js +4 -1
- package/dist/components/countdown-timer/countdown-timer.js +1 -1
- package/dist/components/data-table/data-table.js +4 -4
- package/dist/components/date-picker/date-picker.js +2 -2
- package/dist/components/era-comparison/era-comparison.js +40 -22
- package/dist/components/flashcard/flashcard.js +8 -2
- package/dist/components/geography-quiz-map/geography-quiz-map.js +6 -5
- package/dist/components/grid/grid.js +94 -0
- package/dist/components/grid/index.js +4 -0
- package/dist/components/historic-timeline/historic-timeline.js +2 -2
- package/dist/components/index.js +62 -0
- package/dist/components/interactive-timeline/interactive-timeline.js +15 -2
- package/dist/components/kbd/kbd.js +17 -9
- package/dist/components/knowledge-check/knowledge-check.js +42 -17
- package/dist/components/link/index.js +5 -0
- package/dist/components/link/link.js +55 -0
- package/dist/components/live-feed/live-feed.js +1 -1
- package/dist/components/map-timeline/map-timeline.js +1 -1
- package/dist/components/mdx-content/mdx-content.js +4 -1
- package/dist/components/meter/index.js +5 -0
- package/dist/components/meter/meter.js +78 -0
- package/dist/components/metric-gauge/metric-gauge.js +1 -1
- package/dist/components/model-comparison/model-comparison.js +25 -6
- package/dist/components/model-selector/model-selector.js +5 -5
- package/dist/components/multi-select/multi-select.js +3 -3
- package/dist/components/navbar-saas/navbar-saas.js +2 -2
- package/dist/components/newsletter-signup/newsletter-signup.js +2 -2
- package/dist/components/object-card/object-card.js +1 -1
- package/dist/components/panel/index.js +16 -0
- package/dist/components/panel/panel.js +81 -0
- package/dist/components/parallel-timeline/parallel-timeline.js +2 -2
- package/dist/components/pricing-table/pricing-table.js +55 -18
- package/dist/components/progress-card/progress-card.js +1 -1
- package/dist/components/progress-tracker/progress-tracker.js +3 -3
- package/dist/components/prompt-input/index.js +4 -0
- package/dist/components/prompt-input/prompt-input.js +186 -0
- package/dist/components/prompt-templates/prompt-templates.js +15 -23
- package/dist/components/qr-code/index.js +4 -0
- package/dist/components/qr-code/qr-code.js +51 -0
- package/dist/components/reasoning/index.js +4 -0
- package/dist/components/reasoning/reasoning.js +118 -0
- package/dist/components/scope-selector/scope-selector.js +5 -5
- package/dist/components/search-dialog/search-dialog.js +1 -1
- package/dist/components/slideshow/slideshow.js +352 -273
- package/dist/components/sparkline-grid/sparkline-grid.js +3 -2
- package/dist/components/static-code/static-code-copy.js +5 -10
- package/dist/components/status-board/status-board.js +1 -1
- package/dist/components/toolbar/index.js +8 -0
- package/dist/components/toolbar/toolbar.js +83 -0
- package/dist/components/tour/tour.js +8 -2
- package/dist/components/transaction-list/transaction-list.js +13 -7
- package/dist/components/tutorial-card/tutorial-card.js +1 -1
- package/dist/components/tutorial-complete/tutorial-complete.js +2 -2
- package/dist/components/tutorial-mdx/tutorial-mdx.js +14 -14
- package/dist/components/typography/index.js +26 -0
- package/dist/components/typography/typography.js +150 -0
- package/dist/components/usage-breakdown/usage-breakdown.js +1 -1
- package/dist/index.d.ts +438 -20
- package/dist/index.js +6 -0
- package/dist/lib/use-theme-preset.js +1 -0
- package/package.json +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
30
30
|
- **Time navigation** — `TimelineScrubber`, `PlaybackGhost`, `BottomActivityStrip`, `RunTimeline`.
|
|
31
31
|
- Total component count: **225** (up from 140).
|
|
32
32
|
|
|
33
|
+
- **OKLCH theming system** — color tokens migrated to the OKLCH color space, with 13 runtime theme presets (`default`, `matrix`, `dracula`, `synthwave`, `tron`, `cyberpunk`, `nord`, `claude`, `chatgpt`, `gemini`, `dusk`, `cyberlime`, `aura`). New public theme exports from `@vllnt/ui`: `THEME_PRESETS`, `DEFAULT_THEME_PRESET`, `CUSTOM_THEME_NAME`, `isThemePresetName`, the `ThemePreset` and `ThemePresetName` types, plus the `useThemePreset` hook (with `UseThemePresetResult`), `setThemePreset`, and `setCustomTheme` for runtime preset switching and user-supplied custom themes.
|
|
34
|
+
|
|
33
35
|
- **A11y heading-level override** — every title-bearing component (`ProfileSection`, `FAQ`, `Slideshow`, `WorldClockBar`, `TableOfContentsPanel`, `TableOfContents`, `KeyboardShortcutsHelp`, `Watchlist`, `OrderBook`, `HorizontalScrollRow`, `MarketTreemap`, `ActivityHeatmap`, `Glossary`, `StatusBoard`, `CodePlayground`, `Comparison`, `Quiz`, `Exercise`, `ShareSection`, `CompletionDialog`, `Checklist`, `LearningObjectives`, `CandlestickChart`, `StepByStep`) accepts an `as` prop (`"h1"`–`"h6"`); multi-title components (`ContentIntro`, `TutorialComplete`) expose `titleAs` + `tocLabelAs` / `sectionLabelAs`. Defaults preserve existing heading tags. `HeadingTag` is re-exported from `@vllnt/ui`.
|
|
34
36
|
|
|
35
37
|
### Changed
|
|
@@ -4,17 +4,17 @@ import { forwardRef, useMemo, useState } from "react";
|
|
|
4
4
|
import { ArrowRight, ChevronLeft, ChevronRight } from "lucide-react";
|
|
5
5
|
import { cn } from "../../lib/utils";
|
|
6
6
|
import { Avatar, AvatarFallback } from "../avatar/avatar";
|
|
7
|
-
import { Badge } from "../badge";
|
|
8
|
-
import { Button } from "../button";
|
|
7
|
+
import { Badge } from "../badge/badge";
|
|
8
|
+
import { Button } from "../button/button";
|
|
9
9
|
import {
|
|
10
10
|
Card,
|
|
11
11
|
CardContent,
|
|
12
12
|
CardDescription,
|
|
13
13
|
CardHeader,
|
|
14
14
|
CardTitle
|
|
15
|
-
} from "../card";
|
|
16
|
-
import { ScrollArea } from "../scroll-area";
|
|
17
|
-
import { Separator } from "../separator";
|
|
15
|
+
} from "../card/card";
|
|
16
|
+
import { ScrollArea } from "../scroll-area/scroll-area";
|
|
17
|
+
import { Separator } from "../separator/separator";
|
|
18
18
|
const toneConfig = {
|
|
19
19
|
danger: {
|
|
20
20
|
badgeClassName: "border-destructive/20 bg-destructive/10 text-destructive dark:text-destructive",
|
|
@@ -59,6 +59,7 @@ const DEFAULT_LABELS = {
|
|
|
59
59
|
elapsed: "Elapsed",
|
|
60
60
|
expand: "Show details"
|
|
61
61
|
};
|
|
62
|
+
const AgentActivityLabelsContext = createContext(DEFAULT_LABELS);
|
|
62
63
|
const ACTIVITY_LIVE_REGION_ROLE = {
|
|
63
64
|
completed: "status",
|
|
64
65
|
error: "status",
|
|
@@ -75,8 +76,11 @@ const AgentActivity = forwardRef(
|
|
|
75
76
|
status = "idle",
|
|
76
77
|
...rest
|
|
77
78
|
} = props;
|
|
78
|
-
const resolvedLabels =
|
|
79
|
-
|
|
79
|
+
const resolvedLabels = useMemo(
|
|
80
|
+
() => ({ ...DEFAULT_LABELS, ...labels }),
|
|
81
|
+
[labels]
|
|
82
|
+
);
|
|
83
|
+
return /* @__PURE__ */ jsx(AgentActivityLabelsContext.Provider, { value: resolvedLabels, children: /* @__PURE__ */ jsxs(
|
|
80
84
|
"section",
|
|
81
85
|
{
|
|
82
86
|
"aria-live": status === "running" ? "polite" : "off",
|
|
@@ -103,7 +107,7 @@ const AgentActivity = forwardRef(
|
|
|
103
107
|
/* @__PURE__ */ jsx("ol", { className: "flex flex-col gap-2", children })
|
|
104
108
|
]
|
|
105
109
|
}
|
|
106
|
-
);
|
|
110
|
+
) });
|
|
107
111
|
}
|
|
108
112
|
);
|
|
109
113
|
AgentActivity.displayName = "AgentActivity";
|
|
@@ -193,6 +197,7 @@ const AgentStep = forwardRef(
|
|
|
193
197
|
const hasDetails = split.body.length > 0;
|
|
194
198
|
const [open, setOpen] = useState(defaultOpen);
|
|
195
199
|
const detailsId = useId();
|
|
200
|
+
const labels = useContext(AgentActivityLabelsContext);
|
|
196
201
|
const handleToggle = useCallback(() => {
|
|
197
202
|
setOpen((value) => !value);
|
|
198
203
|
}, []);
|
|
@@ -222,15 +227,16 @@ const AgentStep = forwardRef(
|
|
|
222
227
|
header: split.header,
|
|
223
228
|
icon: resolvedIcon,
|
|
224
229
|
iconClass: palette.iconClass,
|
|
225
|
-
labels
|
|
230
|
+
labels,
|
|
226
231
|
onToggle: handleToggle,
|
|
227
232
|
open
|
|
228
233
|
}
|
|
229
234
|
),
|
|
230
|
-
hasDetails
|
|
235
|
+
hasDetails ? /* @__PURE__ */ jsx(
|
|
231
236
|
"div",
|
|
232
237
|
{
|
|
233
238
|
className: "border-t border-border/60 px-3 py-2 text-xs",
|
|
239
|
+
hidden: !open,
|
|
234
240
|
id: detailsId,
|
|
235
241
|
children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2 pl-8", children: split.body })
|
|
236
242
|
}
|
|
@@ -5,7 +5,9 @@ import {
|
|
|
5
5
|
forwardRef,
|
|
6
6
|
useCallback,
|
|
7
7
|
useContext,
|
|
8
|
+
useEffect,
|
|
8
9
|
useMemo,
|
|
10
|
+
useRef,
|
|
9
11
|
useState
|
|
10
12
|
} from "react";
|
|
11
13
|
import {
|
|
@@ -121,6 +123,24 @@ function ArtifactHeader({
|
|
|
121
123
|
subtitle ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: subtitle }) : null
|
|
122
124
|
] });
|
|
123
125
|
}
|
|
126
|
+
function useCopiedFlag() {
|
|
127
|
+
const [copied, setCopied] = useState(false);
|
|
128
|
+
const timerRef = useRef(void 0);
|
|
129
|
+
useEffect(
|
|
130
|
+
() => () => {
|
|
131
|
+
clearTimeout(timerRef.current);
|
|
132
|
+
},
|
|
133
|
+
[]
|
|
134
|
+
);
|
|
135
|
+
const flagCopied = useCallback(() => {
|
|
136
|
+
setCopied(true);
|
|
137
|
+
clearTimeout(timerRef.current);
|
|
138
|
+
timerRef.current = setTimeout(() => {
|
|
139
|
+
setCopied(false);
|
|
140
|
+
}, COPIED_TIMEOUT_MS);
|
|
141
|
+
}, []);
|
|
142
|
+
return { copied, flagCopied };
|
|
143
|
+
}
|
|
124
144
|
function useArtifactController(options) {
|
|
125
145
|
const {
|
|
126
146
|
defaultFullscreen,
|
|
@@ -133,7 +153,7 @@ function useArtifactController(options) {
|
|
|
133
153
|
value
|
|
134
154
|
} = options;
|
|
135
155
|
const [fullscreen, setFullscreen] = useState(defaultFullscreen);
|
|
136
|
-
const
|
|
156
|
+
const { copied, flagCopied } = useCopiedFlag();
|
|
137
157
|
const resolvedFilename = useMemo(
|
|
138
158
|
() => buildFilename({ filename, language, title, type }),
|
|
139
159
|
[filename, language, title, type]
|
|
@@ -141,12 +161,9 @@ function useArtifactController(options) {
|
|
|
141
161
|
const copy = useCallback(async () => {
|
|
142
162
|
const ok = await writeToClipboard(value);
|
|
143
163
|
if (!ok) return false;
|
|
144
|
-
|
|
145
|
-
setTimeout(() => {
|
|
146
|
-
setCopied(false);
|
|
147
|
-
}, COPIED_TIMEOUT_MS);
|
|
164
|
+
flagCopied();
|
|
148
165
|
return true;
|
|
149
|
-
}, [value]);
|
|
166
|
+
}, [flagCopied, value]);
|
|
150
167
|
const download = useCallback(() => {
|
|
151
168
|
downloadValueAsFile(value, resolvedFilename);
|
|
152
169
|
}, [resolvedFilename, value]);
|
|
@@ -4,7 +4,7 @@ import { cva } from "class-variance-authority";
|
|
|
4
4
|
import { LoaderCircle, SendHorizontal } from "lucide-react";
|
|
5
5
|
import { cn } from "../../lib/utils";
|
|
6
6
|
import { Button } from "../button/button";
|
|
7
|
-
import { Textarea } from "../textarea";
|
|
7
|
+
import { Textarea } from "../textarea/textarea";
|
|
8
8
|
const formShellVariants = cva(
|
|
9
9
|
"rounded-2xl border border-border/70 bg-background shadow-sm"
|
|
10
10
|
);
|
|
@@ -48,6 +48,7 @@ const AIChatInput = forwardRef(
|
|
|
48
48
|
className,
|
|
49
49
|
disabled = false,
|
|
50
50
|
helperText,
|
|
51
|
+
inputLabel = "Chat message",
|
|
51
52
|
isSubmitting = false,
|
|
52
53
|
onSubmit,
|
|
53
54
|
onValueChange,
|
|
@@ -72,6 +73,7 @@ const AIChatInput = forwardRef(
|
|
|
72
73
|
/* @__PURE__ */ jsx(
|
|
73
74
|
Textarea,
|
|
74
75
|
{
|
|
76
|
+
"aria-label": inputLabel,
|
|
75
77
|
className: "min-h-[120px] resize-none rounded-xl border-0 bg-transparent p-1 shadow-none focus-visible:ring-0 focus-visible:ring-offset-0",
|
|
76
78
|
disabled,
|
|
77
79
|
onChange: (event) => {
|
|
@@ -3,7 +3,7 @@ import { forwardRef } from "react";
|
|
|
3
3
|
import { cva } from "class-variance-authority";
|
|
4
4
|
import { cn } from "../../lib/utils";
|
|
5
5
|
import { Avatar, AvatarFallback } from "../avatar/avatar";
|
|
6
|
-
import { Badge } from "../badge";
|
|
6
|
+
import { Badge } from "../badge/badge";
|
|
7
7
|
const bubbleVariants = cva(
|
|
8
8
|
"rounded-2xl border px-4 py-3 shadow-sm transition-colors",
|
|
9
9
|
{
|
|
@@ -180,13 +180,19 @@ function useAutoReloadController(options) {
|
|
|
180
180
|
defaultReloadAmountCents,
|
|
181
181
|
defaultThresholdCents,
|
|
182
182
|
enabled: controlledEnabled,
|
|
183
|
+
onReloadAmountChange,
|
|
184
|
+
onThresholdChange,
|
|
183
185
|
onToggle,
|
|
184
186
|
reloadAmountCents: controlledReload,
|
|
185
187
|
thresholdCents: controlledThreshold
|
|
186
188
|
} = options;
|
|
187
189
|
const [uncontrolledEnabled, setUncontrolledEnabled] = useState(defaultEnabled);
|
|
188
|
-
const [
|
|
189
|
-
|
|
190
|
+
const [uncontrolledThreshold, setUncontrolledThreshold] = useState(
|
|
191
|
+
defaultThresholdCents
|
|
192
|
+
);
|
|
193
|
+
const [uncontrolledReloadAmount, setUncontrolledReloadAmount] = useState(
|
|
194
|
+
defaultReloadAmountCents
|
|
195
|
+
);
|
|
190
196
|
const enabled = controlledEnabled ?? uncontrolledEnabled;
|
|
191
197
|
const handleToggle = useCallback(
|
|
192
198
|
(next) => {
|
|
@@ -195,13 +201,27 @@ function useAutoReloadController(options) {
|
|
|
195
201
|
},
|
|
196
202
|
[controlledEnabled, onToggle]
|
|
197
203
|
);
|
|
204
|
+
const setReloadAmount = useCallback(
|
|
205
|
+
(next) => {
|
|
206
|
+
if (controlledReload === void 0) setUncontrolledReloadAmount(next);
|
|
207
|
+
onReloadAmountChange?.(next);
|
|
208
|
+
},
|
|
209
|
+
[controlledReload, onReloadAmountChange]
|
|
210
|
+
);
|
|
211
|
+
const setThreshold = useCallback(
|
|
212
|
+
(next) => {
|
|
213
|
+
if (controlledThreshold === void 0) setUncontrolledThreshold(next);
|
|
214
|
+
onThresholdChange?.(next);
|
|
215
|
+
},
|
|
216
|
+
[controlledThreshold, onThresholdChange]
|
|
217
|
+
);
|
|
198
218
|
return {
|
|
199
219
|
enabled,
|
|
200
220
|
handleToggle,
|
|
201
|
-
reloadAmount: controlledReload ??
|
|
221
|
+
reloadAmount: controlledReload ?? uncontrolledReloadAmount,
|
|
202
222
|
setReloadAmount,
|
|
203
223
|
setThreshold,
|
|
204
|
-
threshold: controlledThreshold ??
|
|
224
|
+
threshold: controlledThreshold ?? uncontrolledThreshold
|
|
205
225
|
};
|
|
206
226
|
}
|
|
207
227
|
const DisabledBanner = forwardRef(
|
|
@@ -291,7 +311,9 @@ function useAutoReloadInternals(props) {
|
|
|
291
311
|
enabled: controlledEnabled,
|
|
292
312
|
labels,
|
|
293
313
|
locale = DEFAULT_LOCALE,
|
|
314
|
+
onReloadAmountChange,
|
|
294
315
|
onSave,
|
|
316
|
+
onThresholdChange,
|
|
295
317
|
onToggle,
|
|
296
318
|
reloadAmountCents: controlledReload,
|
|
297
319
|
thresholdCents: controlledThreshold
|
|
@@ -308,6 +330,8 @@ function useAutoReloadInternals(props) {
|
|
|
308
330
|
defaultReloadAmountCents,
|
|
309
331
|
defaultThresholdCents,
|
|
310
332
|
enabled: controlledEnabled,
|
|
333
|
+
onReloadAmountChange,
|
|
334
|
+
onThresholdChange,
|
|
311
335
|
onToggle,
|
|
312
336
|
reloadAmountCents: controlledReload,
|
|
313
337
|
thresholdCents: controlledThreshold
|
|
@@ -79,7 +79,7 @@ function PriceGrid({
|
|
|
79
79
|
children: formatValue(tick.value)
|
|
80
80
|
}
|
|
81
81
|
)
|
|
82
|
-
] }, tick.
|
|
82
|
+
] }, tick.y));
|
|
83
83
|
}
|
|
84
84
|
function CandleMarks({
|
|
85
85
|
data,
|
|
@@ -95,12 +95,12 @@ function CandleMarks({
|
|
|
95
95
|
const bodyY = Math.min(openY, closeY);
|
|
96
96
|
const bodyHeight = Math.max(Math.abs(openY - closeY), 3);
|
|
97
97
|
const isBullish = candle.close >= candle.open;
|
|
98
|
-
const
|
|
99
|
-
return /* @__PURE__ */ jsxs("g", { children: [
|
|
98
|
+
const colorClass = isBullish ? "text-emerald-600 dark:text-emerald-400" : "text-rose-600 dark:text-rose-400";
|
|
99
|
+
return /* @__PURE__ */ jsxs("g", { className: colorClass, children: [
|
|
100
100
|
/* @__PURE__ */ jsx(
|
|
101
101
|
"line",
|
|
102
102
|
{
|
|
103
|
-
stroke:
|
|
103
|
+
stroke: "currentColor",
|
|
104
104
|
strokeLinecap: "round",
|
|
105
105
|
strokeWidth: 2,
|
|
106
106
|
x1: centerX,
|
|
@@ -112,11 +112,11 @@ function CandleMarks({
|
|
|
112
112
|
/* @__PURE__ */ jsx(
|
|
113
113
|
"rect",
|
|
114
114
|
{
|
|
115
|
-
fill,
|
|
115
|
+
fill: "currentColor",
|
|
116
116
|
fillOpacity: isBullish ? 0.25 : 0.18,
|
|
117
117
|
height: bodyHeight,
|
|
118
118
|
rx: 4,
|
|
119
|
-
stroke:
|
|
119
|
+
stroke: "currentColor",
|
|
120
120
|
strokeWidth: 1.5,
|
|
121
121
|
width: metrics.bodyWidth,
|
|
122
122
|
x: centerX - metrics.bodyWidth / 2,
|
|
@@ -135,7 +135,7 @@ function CandleMarks({
|
|
|
135
135
|
children: candle.label
|
|
136
136
|
}
|
|
137
137
|
)
|
|
138
|
-
] }, candle.label);
|
|
138
|
+
] }, `${candle.label}-${index.toString()}`);
|
|
139
139
|
});
|
|
140
140
|
}
|
|
141
141
|
function SessionPill({ sessionChange }) {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Activity, Bot, Compass, Layers3, Sparkles } from "lucide-react";
|
|
3
3
|
import { BottomBar } from "../bottom-bar/bottom-bar";
|
|
4
|
-
import { Button } from "../button";
|
|
5
|
-
import { CanvasView } from "../canvas-view";
|
|
6
|
-
import { ChatDockSection } from "../chat-dock-section";
|
|
7
|
-
import { GlassPanel } from "../glass-panel";
|
|
8
|
-
import { LeftRail } from "../left-rail";
|
|
9
|
-
import { RightDock } from "../right-dock";
|
|
10
|
-
import { TopBar } from "../top-bar";
|
|
11
|
-
import { WorkspaceSwitcher } from "../workspace-switcher";
|
|
4
|
+
import { Button } from "../button/button";
|
|
5
|
+
import { CanvasView } from "../canvas-view/canvas-view";
|
|
6
|
+
import { ChatDockSection } from "../chat-dock-section/chat-dock-section";
|
|
7
|
+
import { GlassPanel } from "../glass-panel/glass-panel";
|
|
8
|
+
import { LeftRail } from "../left-rail/left-rail";
|
|
9
|
+
import { RightDock } from "../right-dock/right-dock";
|
|
10
|
+
import { TopBar } from "../top-bar/top-bar";
|
|
11
|
+
import { WorkspaceSwitcher } from "../workspace-switcher/workspace-switcher";
|
|
12
12
|
import { CanvasShell } from "./canvas-shell";
|
|
13
13
|
function DemoLeftBar() {
|
|
14
14
|
return /* @__PURE__ */ jsx(GlassPanel, { className: "overflow-hidden", children: /* @__PURE__ */ jsxs(
|
|
@@ -158,14 +158,17 @@ function renderLegacyCanvasShell({
|
|
|
158
158
|
}
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
|
-
function
|
|
161
|
+
function CanvasShellContent({
|
|
162
|
+
content,
|
|
163
|
+
contentStyle
|
|
164
|
+
}) {
|
|
162
165
|
return /* @__PURE__ */ jsx(
|
|
163
166
|
"div",
|
|
164
167
|
{
|
|
165
168
|
className: "relative z-0 h-full w-full min-h-0 min-w-0",
|
|
166
169
|
"data-slot": "canvas-shell-content",
|
|
167
170
|
style: contentStyle,
|
|
168
|
-
children: /* @__PURE__ */ jsx("div", { className: "h-full w-full min-h-0 min-w-0 overflow-hidden", children })
|
|
171
|
+
children: /* @__PURE__ */ jsx("div", { className: "h-full w-full min-h-0 min-w-0 overflow-hidden", children: content })
|
|
169
172
|
}
|
|
170
173
|
);
|
|
171
174
|
}
|
|
@@ -230,7 +233,7 @@ function renderFloatingCanvasShell({
|
|
|
230
233
|
topBar: hasTopBar ? topBar : void 0
|
|
231
234
|
}
|
|
232
235
|
),
|
|
233
|
-
|
|
236
|
+
/* @__PURE__ */ jsx(CanvasShellContent, { content: children, contentStyle }),
|
|
234
237
|
/* @__PURE__ */ jsx(
|
|
235
238
|
CanvasShellChromeAfter,
|
|
236
239
|
{
|
|
@@ -46,11 +46,18 @@ function supportsScrollableOverflow(value) {
|
|
|
46
46
|
return value === "auto" || value === "overlay" || value === "scroll";
|
|
47
47
|
}
|
|
48
48
|
function hasScrollableAxis(element, axis) {
|
|
49
|
-
const style = window.getComputedStyle(element);
|
|
50
49
|
if (axis === "x") {
|
|
51
|
-
|
|
50
|
+
if (element.scrollWidth <= element.clientWidth) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return supportsScrollableOverflow(
|
|
54
|
+
window.getComputedStyle(element).overflowX
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
if (element.scrollHeight <= element.clientHeight) {
|
|
58
|
+
return false;
|
|
52
59
|
}
|
|
53
|
-
return supportsScrollableOverflow(
|
|
60
|
+
return supportsScrollableOverflow(window.getComputedStyle(element).overflowY);
|
|
54
61
|
}
|
|
55
62
|
function hasScrollableAncestor(element, container, delta) {
|
|
56
63
|
if (!container.contains(element) || element === container) {
|
|
@@ -67,8 +74,8 @@ function shouldHandleCanvasKeyboardEvent(event) {
|
|
|
67
74
|
}
|
|
68
75
|
return true;
|
|
69
76
|
}
|
|
70
|
-
function shouldHandleCanvasWheelEvent(event) {
|
|
71
|
-
if (isHtmlElement(event.target) && hasScrollableAncestor(event.target,
|
|
77
|
+
function shouldHandleCanvasWheelEvent(event, container) {
|
|
78
|
+
if (isHtmlElement(event.target) && hasScrollableAncestor(event.target, container, {
|
|
72
79
|
x: event.deltaX,
|
|
73
80
|
y: event.deltaY
|
|
74
81
|
})) {
|
|
@@ -177,6 +184,7 @@ function useViewportState({
|
|
|
177
184
|
};
|
|
178
185
|
}
|
|
179
186
|
function useCanvasKeyboardInteractions({
|
|
187
|
+
containerRef,
|
|
180
188
|
nudgeViewport,
|
|
181
189
|
resetViewport,
|
|
182
190
|
setViewport,
|
|
@@ -184,24 +192,13 @@ function useCanvasKeyboardInteractions({
|
|
|
184
192
|
zoomStep
|
|
185
193
|
}) {
|
|
186
194
|
const [isSpacePressed, setIsSpacePressed] = useState(false);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
});
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (!shouldHandleCanvasWheelEvent(event)) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
event.preventDefault();
|
|
201
|
-
nudgeViewport(-event.deltaX, -event.deltaY);
|
|
202
|
-
},
|
|
203
|
-
[nudgeViewport, setViewport, viewportRef, zoomStep]
|
|
204
|
-
);
|
|
195
|
+
useCanvasWheel({
|
|
196
|
+
containerRef,
|
|
197
|
+
nudgeViewport,
|
|
198
|
+
setViewport,
|
|
199
|
+
viewportRef,
|
|
200
|
+
zoomStep
|
|
201
|
+
});
|
|
205
202
|
const handleKeyDown = useCallback(
|
|
206
203
|
(event) => {
|
|
207
204
|
if (!shouldHandleCanvasKeyboardEvent(event)) {
|
|
@@ -233,7 +230,43 @@ function useCanvasKeyboardInteractions({
|
|
|
233
230
|
},
|
|
234
231
|
[]
|
|
235
232
|
);
|
|
236
|
-
|
|
233
|
+
const handleBlur = useCallback(() => {
|
|
234
|
+
setIsSpacePressed(false);
|
|
235
|
+
}, []);
|
|
236
|
+
return { handleBlur, handleKeyDown, handleKeyUp, isSpacePressed };
|
|
237
|
+
}
|
|
238
|
+
function useCanvasWheel({
|
|
239
|
+
containerRef,
|
|
240
|
+
nudgeViewport,
|
|
241
|
+
setViewport,
|
|
242
|
+
viewportRef,
|
|
243
|
+
zoomStep
|
|
244
|
+
}) {
|
|
245
|
+
useEffect(() => {
|
|
246
|
+
const container = containerRef.current;
|
|
247
|
+
if (!container) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const handleWheel = (event) => {
|
|
251
|
+
if (event.ctrlKey || event.metaKey) {
|
|
252
|
+
event.preventDefault();
|
|
253
|
+
setViewport({
|
|
254
|
+
...viewportRef.current,
|
|
255
|
+
zoom: viewportRef.current.zoom + (event.deltaY > 0 ? -zoomStep : zoomStep)
|
|
256
|
+
});
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (!shouldHandleCanvasWheelEvent(event, container)) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
event.preventDefault();
|
|
263
|
+
nudgeViewport(-event.deltaX, -event.deltaY);
|
|
264
|
+
};
|
|
265
|
+
container.addEventListener("wheel", handleWheel, { passive: false });
|
|
266
|
+
return () => {
|
|
267
|
+
container.removeEventListener("wheel", handleWheel);
|
|
268
|
+
};
|
|
269
|
+
}, [containerRef, nudgeViewport, setViewport, viewportRef, zoomStep]);
|
|
237
270
|
}
|
|
238
271
|
function endCanvasDrag(event, dragOriginRef, setIsDragging) {
|
|
239
272
|
dragOriginRef.current = null;
|
|
@@ -328,16 +361,17 @@ function useCanvasViewHandle(ref, viewportState) {
|
|
|
328
361
|
}
|
|
329
362
|
function CanvasInteractionLayer({
|
|
330
363
|
children,
|
|
364
|
+
containerRef,
|
|
331
365
|
instructionsId,
|
|
332
366
|
isDragging,
|
|
333
367
|
isSpacePressed,
|
|
368
|
+
onBlur,
|
|
334
369
|
onKeyDown,
|
|
335
370
|
onKeyUp,
|
|
336
371
|
onPointerCancel,
|
|
337
372
|
onPointerDown,
|
|
338
373
|
onPointerMove,
|
|
339
374
|
onPointerUp,
|
|
340
|
-
onWheel,
|
|
341
375
|
viewport
|
|
342
376
|
}) {
|
|
343
377
|
return /* @__PURE__ */ jsxs(
|
|
@@ -351,13 +385,14 @@ function CanvasInteractionLayer({
|
|
|
351
385
|
isDragging || isSpacePressed ? "cursor-grab active:cursor-grabbing" : "cursor-default"
|
|
352
386
|
),
|
|
353
387
|
"data-viewport": JSON.stringify(viewport),
|
|
388
|
+
onBlur,
|
|
354
389
|
onKeyDown,
|
|
355
390
|
onKeyUp,
|
|
356
391
|
onPointerCancel,
|
|
357
392
|
onPointerDown,
|
|
358
393
|
onPointerMove,
|
|
359
394
|
onPointerUp,
|
|
360
|
-
|
|
395
|
+
ref: containerRef,
|
|
361
396
|
role: "button",
|
|
362
397
|
tabIndex: 0,
|
|
363
398
|
children: [
|
|
@@ -369,6 +404,7 @@ function CanvasInteractionLayer({
|
|
|
369
404
|
}
|
|
370
405
|
function CanvasContentLayer({
|
|
371
406
|
children,
|
|
407
|
+
isDragging,
|
|
372
408
|
overlay,
|
|
373
409
|
viewport
|
|
374
410
|
}) {
|
|
@@ -376,7 +412,10 @@ function CanvasContentLayer({
|
|
|
376
412
|
/* @__PURE__ */ jsx(
|
|
377
413
|
"div",
|
|
378
414
|
{
|
|
379
|
-
className:
|
|
415
|
+
className: cn(
|
|
416
|
+
"absolute inset-0 origin-top-left",
|
|
417
|
+
isDragging ? "" : "transition-transform duration-150 ease-out"
|
|
418
|
+
),
|
|
380
419
|
style: {
|
|
381
420
|
transform: `translate3d(${viewport.x}px, ${viewport.y}px, 0) scale(${viewport.zoom})`
|
|
382
421
|
},
|
|
@@ -399,6 +438,7 @@ const CanvasView = forwardRef(
|
|
|
399
438
|
...props
|
|
400
439
|
}, ref) => {
|
|
401
440
|
const instructionsId = useId();
|
|
441
|
+
const interactionRef = useRef(null);
|
|
402
442
|
const viewportState = useViewportState({
|
|
403
443
|
defaultViewport,
|
|
404
444
|
maxZoom,
|
|
@@ -406,6 +446,7 @@ const CanvasView = forwardRef(
|
|
|
406
446
|
onViewportChange
|
|
407
447
|
});
|
|
408
448
|
const keyboard = useCanvasKeyboardInteractions({
|
|
449
|
+
containerRef: interactionRef,
|
|
409
450
|
nudgeViewport: viewportState.nudgeViewport,
|
|
410
451
|
resetViewport: viewportState.resetViewport,
|
|
411
452
|
setViewport: viewportState.setViewport,
|
|
@@ -430,20 +471,22 @@ const CanvasView = forwardRef(
|
|
|
430
471
|
children: /* @__PURE__ */ jsx(
|
|
431
472
|
CanvasInteractionLayer,
|
|
432
473
|
{
|
|
474
|
+
containerRef: interactionRef,
|
|
433
475
|
instructionsId,
|
|
434
476
|
isDragging: pointer.isDragging,
|
|
435
477
|
isSpacePressed: keyboard.isSpacePressed,
|
|
478
|
+
onBlur: keyboard.handleBlur,
|
|
436
479
|
onKeyDown: keyboard.handleKeyDown,
|
|
437
480
|
onKeyUp: keyboard.handleKeyUp,
|
|
438
481
|
onPointerCancel: pointer.handlePointerCancel,
|
|
439
482
|
onPointerDown: pointer.handlePointerDown,
|
|
440
483
|
onPointerMove: pointer.handlePointerMove,
|
|
441
484
|
onPointerUp: pointer.handlePointerUp,
|
|
442
|
-
onWheel: keyboard.handleWheel,
|
|
443
485
|
viewport: viewportState.viewport,
|
|
444
486
|
children: /* @__PURE__ */ jsx(
|
|
445
487
|
CanvasContentLayer,
|
|
446
488
|
{
|
|
489
|
+
isDragging: pointer.isDragging,
|
|
447
490
|
overlay,
|
|
448
491
|
viewport: viewportState.viewport,
|
|
449
492
|
children
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { Check, LoaderCircle, X } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
const markerVariants = cva(
|
|
7
|
+
"flex size-6 shrink-0 items-center justify-center rounded-full border text-xs font-medium",
|
|
8
|
+
{
|
|
9
|
+
defaultVariants: {
|
|
10
|
+
status: "pending"
|
|
11
|
+
},
|
|
12
|
+
variants: {
|
|
13
|
+
status: {
|
|
14
|
+
active: "border-primary bg-primary/10 text-primary",
|
|
15
|
+
complete: "border-transparent bg-primary text-primary-foreground",
|
|
16
|
+
error: "border-transparent bg-destructive text-destructive-foreground",
|
|
17
|
+
pending: "border-border bg-muted text-muted-foreground"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
function StepMarkerIcon({
|
|
23
|
+
index,
|
|
24
|
+
status
|
|
25
|
+
}) {
|
|
26
|
+
if (status === "complete") {
|
|
27
|
+
return /* @__PURE__ */ jsx(Check, { className: "size-3.5" });
|
|
28
|
+
}
|
|
29
|
+
if (status === "error") {
|
|
30
|
+
return /* @__PURE__ */ jsx(X, { className: "size-3.5" });
|
|
31
|
+
}
|
|
32
|
+
if (status === "active") {
|
|
33
|
+
return /* @__PURE__ */ jsx(LoaderCircle, { className: "size-3.5 animate-spin" });
|
|
34
|
+
}
|
|
35
|
+
return /* @__PURE__ */ jsx("span", { children: index + 1 });
|
|
36
|
+
}
|
|
37
|
+
function ChainOfThoughtItem({
|
|
38
|
+
index,
|
|
39
|
+
isLast,
|
|
40
|
+
step
|
|
41
|
+
}) {
|
|
42
|
+
const status = step.status ?? "pending";
|
|
43
|
+
return /* @__PURE__ */ jsxs("li", { className: "flex gap-3", children: [
|
|
44
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
45
|
+
/* @__PURE__ */ jsx("span", { className: markerVariants({ status }), children: /* @__PURE__ */ jsx(StepMarkerIcon, { index, status }) }),
|
|
46
|
+
isLast ? null : /* @__PURE__ */ jsx("span", { className: "my-1 w-px flex-1 bg-border" })
|
|
47
|
+
] }),
|
|
48
|
+
/* @__PURE__ */ jsxs("div", { className: cn("pb-4", isLast && "pb-0"), children: [
|
|
49
|
+
/* @__PURE__ */ jsx(
|
|
50
|
+
"p",
|
|
51
|
+
{
|
|
52
|
+
className: cn(
|
|
53
|
+
"text-sm font-medium",
|
|
54
|
+
status === "pending" ? "text-muted-foreground" : "text-foreground"
|
|
55
|
+
),
|
|
56
|
+
children: step.title
|
|
57
|
+
}
|
|
58
|
+
),
|
|
59
|
+
step.description ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: step.description }) : null
|
|
60
|
+
] })
|
|
61
|
+
] });
|
|
62
|
+
}
|
|
63
|
+
const ChainOfThought = forwardRef(
|
|
64
|
+
({ className, steps }, ref) => /* @__PURE__ */ jsx("ol", { className: cn("flex flex-col", className), ref, children: steps.map((step, index) => /* @__PURE__ */ jsx(
|
|
65
|
+
ChainOfThoughtItem,
|
|
66
|
+
{
|
|
67
|
+
index,
|
|
68
|
+
isLast: index === steps.length - 1,
|
|
69
|
+
step
|
|
70
|
+
},
|
|
71
|
+
`${index}-${step.title}`
|
|
72
|
+
)) })
|
|
73
|
+
);
|
|
74
|
+
ChainOfThought.displayName = "ChainOfThought";
|
|
75
|
+
export {
|
|
76
|
+
ChainOfThought
|
|
77
|
+
};
|