@vllnt/ui 0.2.1-canary.8b618ce → 0.2.1-canary.9e6a7be
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 +21 -6
- package/dist/components/activity-log/activity-log.js +1 -0
- package/dist/components/anchor-port/anchor-port.js +51 -0
- package/dist/components/anchor-port/index.js +4 -0
- package/dist/components/animated-text/animated-text.js +1 -0
- package/dist/components/bottom-bar/bottom-bar.js +25 -0
- package/dist/components/bottom-bar/index.js +4 -0
- package/dist/components/canvas-shell/canvas-foundation-demo.js +183 -0
- package/dist/components/canvas-shell/canvas-shell-route-config.js +0 -0
- package/dist/components/canvas-shell/canvas-shell.js +261 -0
- package/dist/components/canvas-shell/index.js +4 -0
- package/dist/components/canvas-view/canvas-view.js +461 -0
- package/dist/components/canvas-view/index.js +6 -0
- package/dist/components/chart/area-chart.js +1 -0
- package/dist/components/chart/line-chart.js +1 -0
- package/dist/components/chat-dock-section/chat-dock-section.js +56 -0
- package/dist/components/chat-dock-section/index.js +6 -0
- package/dist/components/checklist/checklist.js +7 -0
- package/dist/components/checklist/index.js +3 -1
- package/dist/components/connector-edge/connector-edge.js +66 -0
- package/dist/components/connector-edge/index.js +6 -0
- package/dist/components/curriculum/curriculum.js +349 -0
- package/dist/components/curriculum/index.js +10 -0
- package/dist/components/data-list/data-list.js +1 -0
- package/dist/components/edge-label/edge-label.js +26 -0
- package/dist/components/edge-label/index.js +4 -0
- package/dist/components/form/form.js +432 -0
- package/dist/components/form/index.js +20 -0
- package/dist/components/glass-panel/glass-panel.js +21 -0
- package/dist/components/glass-panel/index.js +4 -0
- package/dist/components/group-hull/group-hull.js +29 -0
- package/dist/components/group-hull/index.js +4 -0
- package/dist/components/index.js +114 -0
- package/dist/components/left-rail/index.js +4 -0
- package/dist/components/left-rail/left-rail.js +25 -0
- package/dist/components/mini-map-panel/index.js +6 -0
- package/dist/components/mini-map-panel/mini-map-panel.js +74 -0
- package/dist/components/multi-select/index.js +6 -0
- package/dist/components/multi-select/multi-select.js +258 -0
- package/dist/components/object-card/index.js +6 -0
- package/dist/components/object-card/object-card.js +126 -0
- package/dist/components/object-handle/index.js +4 -0
- package/dist/components/object-handle/object-handle.js +38 -0
- package/dist/components/overview-board/index.js +8 -0
- package/dist/components/overview-board/overview-board.js +127 -0
- package/dist/components/progress-tracker/index.js +20 -0
- package/dist/components/progress-tracker/progress-tracker.js +527 -0
- package/dist/components/right-dock/index.js +4 -0
- package/dist/components/right-dock/right-dock.js +28 -0
- package/dist/components/segmented-control/index.js +12 -0
- package/dist/components/segmented-control/segmented-control.js +61 -0
- package/dist/components/spinner/unicode-spinner.js +1 -0
- package/dist/components/tags-input/index.js +4 -0
- package/dist/components/tags-input/tags-input.js +178 -0
- package/dist/components/top-bar/index.js +4 -0
- package/dist/components/top-bar/top-bar.js +31 -0
- package/dist/components/usage-breakdown/usage-breakdown.js +1 -0
- package/dist/components/workspace-switcher/index.js +6 -0
- package/dist/components/workspace-switcher/workspace-switcher.js +61 -0
- package/dist/components/zoom-hud/index.js +4 -0
- package/dist/components/zoom-hud/zoom-hud.js +61 -0
- package/dist/index.d.ts +551 -2
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -218,7 +218,7 @@ import {
|
|
|
218
218
|
| `Alert` | `{ Alert, AlertTitle, AlertDescription, alertVariants }` | Static alert banner |
|
|
219
219
|
| `Badge` | `{ Badge, badgeVariants }` | Inline status label. Variants: default, secondary, destructive, outline |
|
|
220
220
|
| `Skeleton` | `{ Skeleton }` | Loading placeholder |
|
|
221
|
-
| `Spinner` | `{ Spinner }` |
|
|
221
|
+
| `Spinner` | `{ Spinner, UnicodeSpinner }` | Styled spinner + ASCII-art `UnicodeSpinner` for terminals / code blocks |
|
|
222
222
|
|
|
223
223
|
### Navigation
|
|
224
224
|
|
|
@@ -242,7 +242,7 @@ import {
|
|
|
242
242
|
| `BarChart` | `{ BarChart }` | Chart component |
|
|
243
243
|
| `LineChart` | `{ LineChart }` | Chart component |
|
|
244
244
|
| `CodeBlock` | `{ CodeBlock }` | Syntax-highlighted code via `react-syntax-highlighter` |
|
|
245
|
-
| `FlowDiagram` | `{ FlowDiagram }` | Flow diagram via `@xyflow/react` |
|
|
245
|
+
| `FlowDiagram` | `{ FlowDiagram, FlowControls, FlowFullscreen, FlowErrorBoundary, useFlowDiagram }` | Flow diagram via `@xyflow/react`. Extras: custom controls, fullscreen wrapper, error boundary, and the `useFlowDiagram` hook for imperative access. |
|
|
246
246
|
| `TableOfContents` | `{ TableOfContents }` | Page table of contents |
|
|
247
247
|
|
|
248
248
|
### App Components
|
|
@@ -276,7 +276,10 @@ import {
|
|
|
276
276
|
| `Flashcard` | `{ Flashcard }` | Flip-card for spaced repetition |
|
|
277
277
|
| `Stepper` | `{ Stepper }` | Linear progress stepper |
|
|
278
278
|
| `Tour` | `{ Tour }` | Guided product tour |
|
|
279
|
-
| `Annotation` | `{ Annotation }` | Inline annotation
|
|
279
|
+
| `Annotation` | `{ Annotation, Highlight }` | Inline annotation block + inline `Highlight` span for in-prose emphasis |
|
|
280
|
+
| `LearningObjectives` | `{ LearningObjectives, Prerequisites, Summary }` | Objectives list plus companion `Prerequisites` and `Summary` blocks |
|
|
281
|
+
| `KeyConcept` | `{ KeyConcept, Glossary }` | Concept callout + `Glossary` term list |
|
|
282
|
+
| `Comparison` | `{ Comparison, BeforeAfter }` | Side-by-side compare block + `BeforeAfter` slider |
|
|
280
283
|
| `CompletionDialog` | `{ CompletionDialog }` | End-of-flow celebration dialog |
|
|
281
284
|
| `TruncatedText` | `{ TruncatedText }` | Expand-on-overflow text block |
|
|
282
285
|
| `TableOfContentsPanel` | `{ TableOfContentsPanel }` | Sidebar TOC panel |
|
|
@@ -334,7 +337,7 @@ import {
|
|
|
334
337
|
| `BorderBeam` | `{ BorderBeam }` | Animated gradient border |
|
|
335
338
|
| `Marquee` | `{ Marquee }` | Infinite scroll marquee |
|
|
336
339
|
| `NumberTicker` | `{ NumberTicker }` | Animated number counter |
|
|
337
|
-
| `Spinner` | `{ Spinner }` |
|
|
340
|
+
| `Spinner` | `{ Spinner, UnicodeSpinner }` | Styled spinner + ASCII-art `UnicodeSpinner` for terminals / code blocks |
|
|
338
341
|
|
|
339
342
|
### Form Additions
|
|
340
343
|
|
|
@@ -386,10 +389,22 @@ import { cn } from "@vllnt/ui";
|
|
|
386
389
|
<div className={cn("p-4 bg-primary", isActive && "bg-accent", className)} />
|
|
387
390
|
```
|
|
388
391
|
|
|
392
|
+
### Hooks
|
|
393
|
+
|
|
394
|
+
| Hook | Purpose |
|
|
395
|
+
|------|---------|
|
|
396
|
+
| `useDebounce(value, delayMs)` | Returns the value after `delayMs` of idle — ideal for search inputs. |
|
|
397
|
+
| `useHorizontalScroll(ref)` | Drives the behavior used by `HorizontalScrollRow` — wheel → horizontal scroll, scroll-snap helpers. |
|
|
398
|
+
| `useMobile(breakpoint?)` | Boolean for "viewport is below breakpoint" (default `768`). SSR-safe. |
|
|
399
|
+
| `useSidebar()` | Reads `SidebarProvider` state — `{ open, setOpen, toggle }`. Throws outside a provider. |
|
|
400
|
+
| `useFlowDiagram(options)` | Imperative controller for `FlowDiagram` — fit view, zoom, export to PNG. |
|
|
401
|
+
| `useSocialFab()` | Drives the open/close state of `SocialFab`. |
|
|
402
|
+
|
|
389
403
|
```tsx
|
|
390
|
-
import { useDebounce } from "@vllnt/ui";
|
|
404
|
+
import { useDebounce, useMobile } from "@vllnt/ui";
|
|
391
405
|
|
|
392
|
-
const
|
|
406
|
+
const query = useDebounce(input, 300);
|
|
407
|
+
const isMobile = useMobile();
|
|
393
408
|
```
|
|
394
409
|
|
|
395
410
|
## Types
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
const toneClasses = {
|
|
5
|
+
bidirectional: "border-violet-500/40 bg-violet-500/15 text-violet-700 dark:text-violet-300",
|
|
6
|
+
input: "border-sky-500/40 bg-sky-500/15 text-sky-700 dark:text-sky-300",
|
|
7
|
+
output: "border-emerald-500/40 bg-emerald-500/15 text-emerald-700 dark:text-emerald-300"
|
|
8
|
+
};
|
|
9
|
+
const stateClasses = {
|
|
10
|
+
active: "scale-100 opacity-100",
|
|
11
|
+
blocked: "opacity-60 saturate-50",
|
|
12
|
+
idle: "opacity-80"
|
|
13
|
+
};
|
|
14
|
+
const sideClasses = {
|
|
15
|
+
bottom: "self-end",
|
|
16
|
+
left: "self-start",
|
|
17
|
+
right: "self-end",
|
|
18
|
+
top: "self-start"
|
|
19
|
+
};
|
|
20
|
+
const AnchorPort = forwardRef(
|
|
21
|
+
({
|
|
22
|
+
className,
|
|
23
|
+
side = "right",
|
|
24
|
+
state = "idle",
|
|
25
|
+
tone = "bidirectional",
|
|
26
|
+
...props
|
|
27
|
+
}, ref) => /* @__PURE__ */ jsx(
|
|
28
|
+
"span",
|
|
29
|
+
{
|
|
30
|
+
"aria-label": props["aria-label"] ?? `${tone} ${side} port ${state}`,
|
|
31
|
+
className: cn(
|
|
32
|
+
"inline-flex size-7 items-center justify-center rounded-full border shadow-sm",
|
|
33
|
+
toneClasses[tone],
|
|
34
|
+
stateClasses[state],
|
|
35
|
+
sideClasses[side],
|
|
36
|
+
className
|
|
37
|
+
),
|
|
38
|
+
"data-side": side,
|
|
39
|
+
"data-state": state,
|
|
40
|
+
"data-tone": tone,
|
|
41
|
+
ref,
|
|
42
|
+
role: "img",
|
|
43
|
+
...props,
|
|
44
|
+
children: /* @__PURE__ */ jsx("span", { className: "size-2.5 rounded-full bg-current" })
|
|
45
|
+
}
|
|
46
|
+
)
|
|
47
|
+
);
|
|
48
|
+
AnchorPort.displayName = "AnchorPort";
|
|
49
|
+
export {
|
|
50
|
+
AnchorPort
|
|
51
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
const BottomBar = forwardRef(
|
|
5
|
+
({ center, className, leading, trailing, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
6
|
+
"div",
|
|
7
|
+
{
|
|
8
|
+
className: cn(
|
|
9
|
+
"flex min-h-14 items-center gap-3 px-4 py-3 text-sm",
|
|
10
|
+
className
|
|
11
|
+
),
|
|
12
|
+
ref,
|
|
13
|
+
...props,
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: leading }),
|
|
16
|
+
center ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center justify-center gap-2", children: center }) : null,
|
|
17
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center justify-end gap-2", children: trailing })
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
BottomBar.displayName = "BottomBar";
|
|
23
|
+
export {
|
|
24
|
+
BottomBar
|
|
25
|
+
};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Activity, Bot, Compass, Layers3, Sparkles } from "lucide-react";
|
|
3
|
+
import { BottomBar } from "../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";
|
|
12
|
+
import { CanvasShell } from "./canvas-shell";
|
|
13
|
+
function DemoLeftBar() {
|
|
14
|
+
return /* @__PURE__ */ jsx(GlassPanel, { className: "overflow-hidden", children: /* @__PURE__ */ jsxs(
|
|
15
|
+
LeftRail,
|
|
16
|
+
{
|
|
17
|
+
className: "w-[5rem] border-0 bg-transparent px-3 py-4",
|
|
18
|
+
footer: /* @__PURE__ */ jsx(Button, { "aria-label": "Runs", size: "icon", type: "button", variant: "ghost", children: /* @__PURE__ */ jsx(Activity, { className: "size-4" }) }),
|
|
19
|
+
title: "Mode",
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ jsx(
|
|
22
|
+
Button,
|
|
23
|
+
{
|
|
24
|
+
"aria-label": "Overview",
|
|
25
|
+
size: "icon",
|
|
26
|
+
type: "button",
|
|
27
|
+
variant: "secondary",
|
|
28
|
+
children: /* @__PURE__ */ jsx(Compass, { className: "size-4" })
|
|
29
|
+
}
|
|
30
|
+
),
|
|
31
|
+
/* @__PURE__ */ jsx(Button, { "aria-label": "Objects", size: "icon", type: "button", variant: "ghost", children: /* @__PURE__ */ jsx(Layers3, { className: "size-4" }) }),
|
|
32
|
+
/* @__PURE__ */ jsx(Button, { "aria-label": "Agents", size: "icon", type: "button", variant: "ghost", children: /* @__PURE__ */ jsx(Bot, { className: "size-4" }) })
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
) });
|
|
36
|
+
}
|
|
37
|
+
function DemoTopBar() {
|
|
38
|
+
return /* @__PURE__ */ jsx(GlassPanel, { children: /* @__PURE__ */ jsx(
|
|
39
|
+
TopBar,
|
|
40
|
+
{
|
|
41
|
+
className: "border-0 bg-transparent px-5 font-sans",
|
|
42
|
+
leading: /* @__PURE__ */ jsx("div", { className: "flex size-9 items-center justify-center rounded-xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Sparkles, { className: "size-4" }) }),
|
|
43
|
+
subtitle: "Calm operating surface",
|
|
44
|
+
title: "Operator workspace",
|
|
45
|
+
trailing: /* @__PURE__ */ jsx(Button, { size: "sm", type: "button", variant: "outline", children: "Open command" }),
|
|
46
|
+
children: /* @__PURE__ */ jsx(
|
|
47
|
+
WorkspaceSwitcher,
|
|
48
|
+
{
|
|
49
|
+
className: "bg-background/60",
|
|
50
|
+
defaultValue: "orchestrate",
|
|
51
|
+
workspaces: [
|
|
52
|
+
{ id: "orchestrate", label: "Orchestrate" },
|
|
53
|
+
{ id: "objects", label: "Objects" },
|
|
54
|
+
{ id: "signals", label: "Signals" }
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
) });
|
|
60
|
+
}
|
|
61
|
+
function DemoRightBar() {
|
|
62
|
+
return /* @__PURE__ */ jsx(GlassPanel, { className: "h-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
63
|
+
RightDock,
|
|
64
|
+
{
|
|
65
|
+
className: "h-full min-w-[22rem] max-w-[22rem] border-0 bg-transparent",
|
|
66
|
+
footer: /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Chat stays contextual and secondary to the center workspace." }),
|
|
67
|
+
header: /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Context shifts by route while the shell stays stable." }),
|
|
68
|
+
title: "Context",
|
|
69
|
+
children: /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
70
|
+
/* @__PURE__ */ jsx(
|
|
71
|
+
ChatDockSection,
|
|
72
|
+
{
|
|
73
|
+
contextLabel: "Today \xB7 overview",
|
|
74
|
+
messages: [
|
|
75
|
+
{
|
|
76
|
+
body: "Three failed runs came in overnight. Start with the invoice retry and the security digest.",
|
|
77
|
+
id: "assistant",
|
|
78
|
+
speaker: "Assistant"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
body: "Queue the approvals first, then review the stale automations after lunch.",
|
|
82
|
+
id: "operator",
|
|
83
|
+
speaker: "Operator"
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
),
|
|
88
|
+
/* @__PURE__ */ jsxs("div", { className: "rounded-2xl border border-border/70 bg-background/75 p-4 shadow-[0_10px_35px_hsl(var(--foreground)/0.06)] backdrop-blur-xl", children: [
|
|
89
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.24em] text-muted-foreground", children: "Selected context" }),
|
|
90
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 text-sm font-medium text-foreground", children: "Inbox triage" }),
|
|
91
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 text-sm leading-6 text-muted-foreground", children: "Landing route keeps the assistant close to the operational queue instead of taking over the center canvas." })
|
|
92
|
+
] })
|
|
93
|
+
] })
|
|
94
|
+
}
|
|
95
|
+
) });
|
|
96
|
+
}
|
|
97
|
+
function DemoBottomBar() {
|
|
98
|
+
return /* @__PURE__ */ jsx(GlassPanel, { children: /* @__PURE__ */ jsx(
|
|
99
|
+
BottomBar,
|
|
100
|
+
{
|
|
101
|
+
center: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
102
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-full border border-border/70 px-3 py-1 text-xs text-muted-foreground", children: "3 errors" }),
|
|
103
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-full border border-border/70 px-3 py-1 text-xs text-muted-foreground", children: "7 awaiting action" })
|
|
104
|
+
] }),
|
|
105
|
+
leading: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
106
|
+
/* @__PURE__ */ jsx(Activity, { className: "size-4" }),
|
|
107
|
+
"System healthy enough to proceed"
|
|
108
|
+
] }),
|
|
109
|
+
trailing: /* @__PURE__ */ jsx(Button, { size: "sm", type: "button", variant: "ghost", children: "Open inbox" })
|
|
110
|
+
}
|
|
111
|
+
) });
|
|
112
|
+
}
|
|
113
|
+
function DemoCanvasObjects() {
|
|
114
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative h-[1200px] w-[1600px] overflow-hidden rounded-[28px] border border-border/12 bg-[radial-gradient(circle_at_top,hsl(var(--primary)/0.07),transparent_38%),linear-gradient(180deg,hsl(var(--background)/0.18),hsl(var(--background)/0.04))]", children: [
|
|
115
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute left-[14%] top-[22%] w-72 rounded-[2rem] border border-border/18 bg-background/18 p-5 shadow-[0_22px_80px_hsl(var(--foreground)/0.05)] backdrop-blur-xl", children: [
|
|
116
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
117
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-11 items-center justify-center rounded-2xl bg-primary/10 text-primary", children: /* @__PURE__ */ jsx(Layers3, { className: "size-5" }) }),
|
|
118
|
+
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-primary/50" })
|
|
119
|
+
] }),
|
|
120
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-5 space-y-3", children: [
|
|
121
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-24 rounded-full bg-foreground/10" }),
|
|
122
|
+
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
123
|
+
/* @__PURE__ */ jsx("div", { className: "h-20 rounded-[1.5rem] border border-border/18 bg-background/35" }),
|
|
124
|
+
/* @__PURE__ */ jsx("div", { className: "h-20 rounded-[1.5rem] border border-border/18 bg-background/28" })
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsx("div", { className: "h-10 rounded-[1.25rem] border border-border/18 bg-background/30" })
|
|
127
|
+
] })
|
|
128
|
+
] }),
|
|
129
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute right-[15%] top-[18%] w-56 rounded-[1.75rem] border border-border/18 bg-background/14 p-4 shadow-[0_18px_60px_hsl(var(--foreground)/0.04)] backdrop-blur-xl", children: [
|
|
130
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
131
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-10 items-center justify-center rounded-2xl bg-background/60 text-foreground/70", children: /* @__PURE__ */ jsx(Activity, { className: "size-4" }) }),
|
|
132
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-1.5", children: [
|
|
133
|
+
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-foreground/10" }),
|
|
134
|
+
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-foreground/10" }),
|
|
135
|
+
/* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-primary/45" })
|
|
136
|
+
] })
|
|
137
|
+
] }),
|
|
138
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-3", children: [
|
|
139
|
+
/* @__PURE__ */ jsx("div", { className: "h-3 w-20 rounded-full bg-foreground/10" }),
|
|
140
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
141
|
+
/* @__PURE__ */ jsx("div", { className: "h-11 rounded-[1rem] border border-border/18 bg-background/32" }),
|
|
142
|
+
/* @__PURE__ */ jsx("div", { className: "h-11 rounded-[1rem] border border-border/18 bg-background/24" }),
|
|
143
|
+
/* @__PURE__ */ jsx("div", { className: "h-11 rounded-[1rem] border border-border/18 bg-background/18" })
|
|
144
|
+
] })
|
|
145
|
+
] })
|
|
146
|
+
] }),
|
|
147
|
+
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-[18%] left-[22%] w-64 rounded-[1.75rem] border border-border/18 bg-background/12 p-4 shadow-[0_18px_60px_hsl(var(--foreground)/0.04)] backdrop-blur-xl", children: [
|
|
148
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
149
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-10 items-center justify-center rounded-2xl bg-background/55 text-foreground/70", children: /* @__PURE__ */ jsx(Sparkles, { className: "size-4" }) }),
|
|
150
|
+
/* @__PURE__ */ jsx("div", { className: "h-7 w-16 rounded-full border border-border/18 bg-background/38" })
|
|
151
|
+
] }),
|
|
152
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 grid grid-cols-3 gap-2", children: [
|
|
153
|
+
/* @__PURE__ */ jsx("div", { className: "h-16 rounded-[1rem] border border-border/18 bg-background/26" }),
|
|
154
|
+
/* @__PURE__ */ jsx("div", { className: "h-16 rounded-[1rem] border border-border/18 bg-background/20" }),
|
|
155
|
+
/* @__PURE__ */ jsx("div", { className: "h-16 rounded-[1rem] border border-border/18 bg-background/14" })
|
|
156
|
+
] })
|
|
157
|
+
] })
|
|
158
|
+
] });
|
|
159
|
+
}
|
|
160
|
+
function CanvasFoundationDemo() {
|
|
161
|
+
return /* @__PURE__ */ jsx(
|
|
162
|
+
CanvasShell,
|
|
163
|
+
{
|
|
164
|
+
bottomBar: /* @__PURE__ */ jsx(DemoBottomBar, {}),
|
|
165
|
+
className: "h-[100dvh] min-h-[720px]",
|
|
166
|
+
contentPadding: { bottom: 120, left: 112, right: 392, top: 112 },
|
|
167
|
+
leftBar: /* @__PURE__ */ jsx(DemoLeftBar, {}),
|
|
168
|
+
rightBar: /* @__PURE__ */ jsx(DemoRightBar, {}),
|
|
169
|
+
topBar: /* @__PURE__ */ jsx(DemoTopBar, {}),
|
|
170
|
+
children: /* @__PURE__ */ jsx(
|
|
171
|
+
CanvasView,
|
|
172
|
+
{
|
|
173
|
+
className: "h-full rounded-none border-0 bg-background/25",
|
|
174
|
+
defaultViewport: { x: 0, y: 0, zoom: 1 },
|
|
175
|
+
children: /* @__PURE__ */ jsx(DemoCanvasObjects, {})
|
|
176
|
+
}
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
export {
|
|
182
|
+
CanvasFoundationDemo
|
|
183
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
function toInsetValue(value) {
|
|
5
|
+
if (typeof value === "number") {
|
|
6
|
+
return `${value}px`;
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
const FLOATING_BOTTOM_BAR_FOOTPRINT = "3.5rem";
|
|
11
|
+
const FLOATING_LEFT_BAR_FOOTPRINT = "4.5rem";
|
|
12
|
+
const FLOATING_RIGHT_BAR_FOOTPRINT = "18rem";
|
|
13
|
+
const FLOATING_TOP_BAR_FOOTPRINT = "3.5rem";
|
|
14
|
+
function getReservedInset(inset, footprint, override) {
|
|
15
|
+
return toInsetValue(override) ?? `calc(${inset} + ${footprint})`;
|
|
16
|
+
}
|
|
17
|
+
function getSafeAreaInsets({
|
|
18
|
+
chromeInset,
|
|
19
|
+
contentPadding,
|
|
20
|
+
hasBottomBar,
|
|
21
|
+
hasLeftBar,
|
|
22
|
+
hasRightBar,
|
|
23
|
+
hasTopBar
|
|
24
|
+
}) {
|
|
25
|
+
const inset = toInsetValue(chromeInset) ?? "16px";
|
|
26
|
+
return {
|
|
27
|
+
bottom: hasBottomBar ? getReservedInset(
|
|
28
|
+
inset,
|
|
29
|
+
FLOATING_BOTTOM_BAR_FOOTPRINT,
|
|
30
|
+
contentPadding?.bottom
|
|
31
|
+
) : toInsetValue(contentPadding?.bottom) ?? inset,
|
|
32
|
+
left: hasLeftBar ? getReservedInset(
|
|
33
|
+
inset,
|
|
34
|
+
FLOATING_LEFT_BAR_FOOTPRINT,
|
|
35
|
+
contentPadding?.left
|
|
36
|
+
) : toInsetValue(contentPadding?.left) ?? inset,
|
|
37
|
+
right: hasRightBar ? getReservedInset(
|
|
38
|
+
inset,
|
|
39
|
+
FLOATING_RIGHT_BAR_FOOTPRINT,
|
|
40
|
+
contentPadding?.right
|
|
41
|
+
) : toInsetValue(contentPadding?.right) ?? inset,
|
|
42
|
+
top: hasTopBar ? getReservedInset(inset, FLOATING_TOP_BAR_FOOTPRINT, contentPadding?.top) : toInsetValue(contentPadding?.top) ?? inset
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function getSafeAreaStyle(insets) {
|
|
46
|
+
return {
|
|
47
|
+
"--canvas-shell-safe-bottom": insets.bottom,
|
|
48
|
+
"--canvas-shell-safe-left": insets.left,
|
|
49
|
+
"--canvas-shell-safe-right": insets.right,
|
|
50
|
+
"--canvas-shell-safe-top": insets.top
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const hasChromeContent = Boolean;
|
|
54
|
+
function CanvasShellChromeBefore({
|
|
55
|
+
inset,
|
|
56
|
+
leftBar,
|
|
57
|
+
topBar
|
|
58
|
+
}) {
|
|
59
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
60
|
+
hasChromeContent(topBar) ? /* @__PURE__ */ jsx(
|
|
61
|
+
"div",
|
|
62
|
+
{
|
|
63
|
+
className: "pointer-events-none absolute inset-x-0 z-30",
|
|
64
|
+
style: { top: inset },
|
|
65
|
+
children: /* @__PURE__ */ jsx(
|
|
66
|
+
"div",
|
|
67
|
+
{
|
|
68
|
+
className: "pointer-events-auto mx-auto w-full max-w-[960px]",
|
|
69
|
+
style: { paddingLeft: inset, paddingRight: inset },
|
|
70
|
+
children: topBar
|
|
71
|
+
}
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
) : null,
|
|
75
|
+
hasChromeContent(leftBar) ? /* @__PURE__ */ jsx(
|
|
76
|
+
"div",
|
|
77
|
+
{
|
|
78
|
+
className: "pointer-events-none absolute left-0 z-30 flex",
|
|
79
|
+
style: {
|
|
80
|
+
bottom: "var(--canvas-shell-safe-bottom)",
|
|
81
|
+
left: inset,
|
|
82
|
+
top: "var(--canvas-shell-safe-top)"
|
|
83
|
+
},
|
|
84
|
+
children: /* @__PURE__ */ jsx("div", { className: "pointer-events-auto flex", children: leftBar })
|
|
85
|
+
}
|
|
86
|
+
) : null
|
|
87
|
+
] });
|
|
88
|
+
}
|
|
89
|
+
function CanvasShellChromeAfter({
|
|
90
|
+
bottomBar,
|
|
91
|
+
inset,
|
|
92
|
+
rightBar
|
|
93
|
+
}) {
|
|
94
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
95
|
+
hasChromeContent(rightBar) ? /* @__PURE__ */ jsx(
|
|
96
|
+
"div",
|
|
97
|
+
{
|
|
98
|
+
className: "pointer-events-none absolute right-0 z-30 flex",
|
|
99
|
+
style: {
|
|
100
|
+
bottom: "var(--canvas-shell-safe-bottom)",
|
|
101
|
+
right: inset,
|
|
102
|
+
top: "var(--canvas-shell-safe-top)"
|
|
103
|
+
},
|
|
104
|
+
children: /* @__PURE__ */ jsx("div", { className: "pointer-events-auto flex", children: rightBar })
|
|
105
|
+
}
|
|
106
|
+
) : null,
|
|
107
|
+
hasChromeContent(bottomBar) ? /* @__PURE__ */ jsx(
|
|
108
|
+
"div",
|
|
109
|
+
{
|
|
110
|
+
className: "pointer-events-none absolute inset-x-0 z-30",
|
|
111
|
+
style: { bottom: inset },
|
|
112
|
+
children: /* @__PURE__ */ jsx(
|
|
113
|
+
"div",
|
|
114
|
+
{
|
|
115
|
+
className: "pointer-events-auto mx-auto w-full max-w-[960px]",
|
|
116
|
+
style: { paddingLeft: inset, paddingRight: inset },
|
|
117
|
+
children: bottomBar
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
) : null
|
|
122
|
+
] });
|
|
123
|
+
}
|
|
124
|
+
function renderLegacyCanvasShell({
|
|
125
|
+
bottomBar: _bottomBar,
|
|
126
|
+
bottomSlot,
|
|
127
|
+
children,
|
|
128
|
+
chromeInset: _chromeInset = 16,
|
|
129
|
+
className,
|
|
130
|
+
contentPadding: _contentPadding,
|
|
131
|
+
leftBar: _leftBar,
|
|
132
|
+
leftRail,
|
|
133
|
+
rightBar: _rightBar,
|
|
134
|
+
rightDock,
|
|
135
|
+
style,
|
|
136
|
+
topBar,
|
|
137
|
+
...props
|
|
138
|
+
}, ref) {
|
|
139
|
+
return /* @__PURE__ */ jsxs(
|
|
140
|
+
"section",
|
|
141
|
+
{
|
|
142
|
+
className: cn(
|
|
143
|
+
"flex min-h-[720px] w-full flex-col overflow-hidden rounded-md border border-border bg-background",
|
|
144
|
+
className
|
|
145
|
+
),
|
|
146
|
+
ref,
|
|
147
|
+
style,
|
|
148
|
+
...props,
|
|
149
|
+
children: [
|
|
150
|
+
topBar,
|
|
151
|
+
/* @__PURE__ */ jsxs("div", { className: "grid min-h-0 flex-1 grid-cols-[auto_minmax(0,1fr)_auto] overflow-hidden bg-background", children: [
|
|
152
|
+
leftRail ?? /* @__PURE__ */ jsx("div", {}),
|
|
153
|
+
/* @__PURE__ */ jsx("div", { className: "relative min-h-0 min-w-0 overflow-hidden", children }),
|
|
154
|
+
rightDock ?? /* @__PURE__ */ jsx("div", {})
|
|
155
|
+
] }),
|
|
156
|
+
bottomSlot ? /* @__PURE__ */ jsx("div", { className: "border-t border-border bg-background px-4 py-2", children: bottomSlot }) : null
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
function renderFloatingContent(children, contentStyle) {
|
|
162
|
+
return /* @__PURE__ */ jsx(
|
|
163
|
+
"div",
|
|
164
|
+
{
|
|
165
|
+
className: "relative z-0 h-full w-full min-h-0 min-w-0",
|
|
166
|
+
"data-slot": "canvas-shell-content",
|
|
167
|
+
style: contentStyle,
|
|
168
|
+
children: /* @__PURE__ */ jsx("div", { className: "h-full w-full min-h-0 min-w-0 overflow-hidden", children })
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
function renderFloatingCanvasShell({
|
|
173
|
+
bottomBar,
|
|
174
|
+
bottomSlot,
|
|
175
|
+
children,
|
|
176
|
+
chromeInset = 16,
|
|
177
|
+
className,
|
|
178
|
+
contentPadding,
|
|
179
|
+
leftBar,
|
|
180
|
+
leftRail,
|
|
181
|
+
rightBar,
|
|
182
|
+
rightDock,
|
|
183
|
+
style,
|
|
184
|
+
topBar,
|
|
185
|
+
...props
|
|
186
|
+
}, ref) {
|
|
187
|
+
const inset = toInsetValue(chromeInset) ?? "16px";
|
|
188
|
+
const resolvedBottomBar = bottomBar ?? bottomSlot;
|
|
189
|
+
const resolvedLeftBar = leftBar ?? leftRail;
|
|
190
|
+
const resolvedRightBar = rightBar ?? rightDock;
|
|
191
|
+
const hasTopBar = hasChromeContent(topBar);
|
|
192
|
+
const hasLeftBar = hasChromeContent(resolvedLeftBar);
|
|
193
|
+
const hasRightBar = hasChromeContent(resolvedRightBar);
|
|
194
|
+
const hasBottomBar = hasChromeContent(resolvedBottomBar);
|
|
195
|
+
const safeAreaInsets = getSafeAreaInsets({
|
|
196
|
+
chromeInset,
|
|
197
|
+
contentPadding,
|
|
198
|
+
hasBottomBar,
|
|
199
|
+
hasLeftBar,
|
|
200
|
+
hasRightBar,
|
|
201
|
+
hasTopBar
|
|
202
|
+
});
|
|
203
|
+
const mergedStyle = {
|
|
204
|
+
...getSafeAreaStyle(safeAreaInsets),
|
|
205
|
+
...style
|
|
206
|
+
};
|
|
207
|
+
const contentStyle = {
|
|
208
|
+
paddingBottom: "var(--canvas-shell-safe-bottom)",
|
|
209
|
+
paddingLeft: "var(--canvas-shell-safe-left)",
|
|
210
|
+
paddingRight: "var(--canvas-shell-safe-right)",
|
|
211
|
+
paddingTop: "var(--canvas-shell-safe-top)"
|
|
212
|
+
};
|
|
213
|
+
return /* @__PURE__ */ jsxs(
|
|
214
|
+
"section",
|
|
215
|
+
{
|
|
216
|
+
className: cn(
|
|
217
|
+
"relative isolate flex min-h-[720px] w-full overflow-hidden bg-[radial-gradient(circle_at_top,hsl(var(--background)/0.94),hsl(var(--muted)/0.6))]",
|
|
218
|
+
className
|
|
219
|
+
),
|
|
220
|
+
ref,
|
|
221
|
+
style: mergedStyle,
|
|
222
|
+
...props,
|
|
223
|
+
children: [
|
|
224
|
+
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-[linear-gradient(180deg,hsl(var(--background)/0.94),hsl(var(--background)/0.8))]" }),
|
|
225
|
+
/* @__PURE__ */ jsx(
|
|
226
|
+
CanvasShellChromeBefore,
|
|
227
|
+
{
|
|
228
|
+
inset,
|
|
229
|
+
leftBar: hasLeftBar ? resolvedLeftBar : void 0,
|
|
230
|
+
topBar: hasTopBar ? topBar : void 0
|
|
231
|
+
}
|
|
232
|
+
),
|
|
233
|
+
renderFloatingContent(children, contentStyle),
|
|
234
|
+
/* @__PURE__ */ jsx(
|
|
235
|
+
CanvasShellChromeAfter,
|
|
236
|
+
{
|
|
237
|
+
bottomBar: hasBottomBar ? resolvedBottomBar : void 0,
|
|
238
|
+
inset,
|
|
239
|
+
rightBar: hasRightBar ? resolvedRightBar : void 0
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
const CanvasShell = forwardRef((props, ref) => {
|
|
247
|
+
const { bottomBar, chromeInset, contentPadding, leftBar, rightBar } = props;
|
|
248
|
+
const hasExplicitChromeInset = Object.prototype.hasOwnProperty.call(
|
|
249
|
+
props,
|
|
250
|
+
"chromeInset"
|
|
251
|
+
);
|
|
252
|
+
const usesFloatingChrome = hasChromeContent(bottomBar) || hasChromeContent(leftBar) || hasChromeContent(rightBar) || contentPadding !== void 0 || hasExplicitChromeInset && chromeInset !== void 0;
|
|
253
|
+
if (!usesFloatingChrome) {
|
|
254
|
+
return renderLegacyCanvasShell(props, ref);
|
|
255
|
+
}
|
|
256
|
+
return renderFloatingCanvasShell(props, ref);
|
|
257
|
+
});
|
|
258
|
+
CanvasShell.displayName = "CanvasShell";
|
|
259
|
+
export {
|
|
260
|
+
CanvasShell
|
|
261
|
+
};
|