@vllnt/ui 0.2.0 → 0.2.1-canary.9c473e0
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 +12 -1
- package/README.md +27 -12
- 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/connector-edge/connector-edge.js +66 -0
- package/dist/components/connector-edge/index.js +6 -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 +263 -0
- package/dist/components/form/index.js +16 -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 +88 -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/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 +455 -5
- package/package.json +1 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { X } from "lucide-react";
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
function normalizeTag(tag) {
|
|
7
|
+
return tag.trim();
|
|
8
|
+
}
|
|
9
|
+
function getNormalizedTags(tags) {
|
|
10
|
+
return tags.map(normalizeTag).filter(
|
|
11
|
+
(tag, index, values) => tag.length > 0 && values.indexOf(tag) === index
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
function shouldAddTagFromKey(key) {
|
|
15
|
+
return key === "Enter" || key === ",";
|
|
16
|
+
}
|
|
17
|
+
function useTagsInputState({
|
|
18
|
+
defaultValue,
|
|
19
|
+
onValueChange,
|
|
20
|
+
value
|
|
21
|
+
}) {
|
|
22
|
+
const [uncontrolledValue, setUncontrolledValue] = React.useState(
|
|
23
|
+
() => getNormalizedTags(defaultValue)
|
|
24
|
+
);
|
|
25
|
+
const isControlled = value !== void 0;
|
|
26
|
+
const tags = React.useMemo(
|
|
27
|
+
() => getNormalizedTags(value ?? uncontrolledValue),
|
|
28
|
+
[uncontrolledValue, value]
|
|
29
|
+
);
|
|
30
|
+
const updateTags = React.useCallback(
|
|
31
|
+
(nextTags) => {
|
|
32
|
+
const normalizedTags = getNormalizedTags(nextTags);
|
|
33
|
+
if (!isControlled) {
|
|
34
|
+
setUncontrolledValue(normalizedTags);
|
|
35
|
+
}
|
|
36
|
+
onValueChange?.(normalizedTags);
|
|
37
|
+
},
|
|
38
|
+
[isControlled, onValueChange]
|
|
39
|
+
);
|
|
40
|
+
return { tags, updateTags };
|
|
41
|
+
}
|
|
42
|
+
function useTagsInputHandlers({
|
|
43
|
+
disabled,
|
|
44
|
+
inputValue,
|
|
45
|
+
onKeyDown,
|
|
46
|
+
setInputValue,
|
|
47
|
+
tags,
|
|
48
|
+
updateTags
|
|
49
|
+
}) {
|
|
50
|
+
const removeTag = React.useCallback(
|
|
51
|
+
(tagToRemove) => {
|
|
52
|
+
updateTags(tags.filter((tag) => tag !== tagToRemove));
|
|
53
|
+
},
|
|
54
|
+
[tags, updateTags]
|
|
55
|
+
);
|
|
56
|
+
const commitTag = React.useCallback(() => {
|
|
57
|
+
const nextTag = normalizeTag(inputValue);
|
|
58
|
+
if (nextTag.length === 0 || tags.includes(nextTag)) {
|
|
59
|
+
setInputValue("");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
updateTags([...tags, nextTag]);
|
|
63
|
+
setInputValue("");
|
|
64
|
+
}, [inputValue, setInputValue, tags, updateTags]);
|
|
65
|
+
const handleKeyDown = React.useCallback(
|
|
66
|
+
(event) => {
|
|
67
|
+
onKeyDown?.(event);
|
|
68
|
+
if (event.defaultPrevented || disabled) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (shouldAddTagFromKey(event.key)) {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
commitTag();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if ((event.key === "Backspace" || event.key === "Delete") && inputValue.length === 0) {
|
|
77
|
+
const lastTag = tags.at(-1);
|
|
78
|
+
if (lastTag) {
|
|
79
|
+
event.preventDefault();
|
|
80
|
+
removeTag(lastTag);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
[commitTag, disabled, inputValue.length, onKeyDown, removeTag, tags]
|
|
85
|
+
);
|
|
86
|
+
return { handleKeyDown, removeTag };
|
|
87
|
+
}
|
|
88
|
+
function TagList({ disabled, onRemove, tags }) {
|
|
89
|
+
return /* @__PURE__ */ jsx("ul", { className: "flex flex-wrap items-center gap-2", children: tags.map((tag) => /* @__PURE__ */ jsxs(
|
|
90
|
+
"li",
|
|
91
|
+
{
|
|
92
|
+
className: "flex items-center gap-1 rounded-md border bg-muted px-2 py-1 text-sm text-foreground",
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsx("span", { children: tag }),
|
|
95
|
+
/* @__PURE__ */ jsx(
|
|
96
|
+
"button",
|
|
97
|
+
{
|
|
98
|
+
"aria-label": `Remove ${tag}`,
|
|
99
|
+
className: "rounded-sm text-muted-foreground outline-none ring-offset-background transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
100
|
+
disabled,
|
|
101
|
+
onClick: (event) => {
|
|
102
|
+
event.stopPropagation();
|
|
103
|
+
onRemove(tag);
|
|
104
|
+
},
|
|
105
|
+
type: "button",
|
|
106
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
|
|
107
|
+
}
|
|
108
|
+
)
|
|
109
|
+
]
|
|
110
|
+
},
|
|
111
|
+
tag
|
|
112
|
+
)) });
|
|
113
|
+
}
|
|
114
|
+
const TagsInput = React.forwardRef(
|
|
115
|
+
({
|
|
116
|
+
className,
|
|
117
|
+
defaultValue = [],
|
|
118
|
+
disabled = false,
|
|
119
|
+
onBlur,
|
|
120
|
+
onKeyDown,
|
|
121
|
+
onValueChange,
|
|
122
|
+
placeholder = "Add a tag",
|
|
123
|
+
value,
|
|
124
|
+
...props
|
|
125
|
+
}, ref) => {
|
|
126
|
+
const [inputValue, setInputValue] = React.useState("");
|
|
127
|
+
const { tags, updateTags } = useTagsInputState({
|
|
128
|
+
defaultValue,
|
|
129
|
+
onValueChange,
|
|
130
|
+
value
|
|
131
|
+
});
|
|
132
|
+
const { handleKeyDown, removeTag } = useTagsInputHandlers({
|
|
133
|
+
disabled,
|
|
134
|
+
inputValue,
|
|
135
|
+
onKeyDown,
|
|
136
|
+
setInputValue,
|
|
137
|
+
tags,
|
|
138
|
+
updateTags
|
|
139
|
+
});
|
|
140
|
+
return /* @__PURE__ */ jsxs(
|
|
141
|
+
"div",
|
|
142
|
+
{
|
|
143
|
+
"aria-disabled": disabled || void 0,
|
|
144
|
+
className: cn(
|
|
145
|
+
"flex min-h-10 w-full flex-wrap items-center gap-2 rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background transition-colors focus-within:outline-none focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2",
|
|
146
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
147
|
+
className
|
|
148
|
+
),
|
|
149
|
+
"data-disabled": disabled ? "true" : void 0,
|
|
150
|
+
role: "group",
|
|
151
|
+
children: [
|
|
152
|
+
/* @__PURE__ */ jsx(TagList, { disabled, onRemove: removeTag, tags }),
|
|
153
|
+
/* @__PURE__ */ jsx(
|
|
154
|
+
"input",
|
|
155
|
+
{
|
|
156
|
+
...props,
|
|
157
|
+
className: "min-w-[8rem] flex-1 border-0 bg-transparent p-0 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed",
|
|
158
|
+
disabled,
|
|
159
|
+
onBlur,
|
|
160
|
+
onChange: (event) => {
|
|
161
|
+
setInputValue(event.target.value);
|
|
162
|
+
},
|
|
163
|
+
onKeyDown: handleKeyDown,
|
|
164
|
+
placeholder,
|
|
165
|
+
ref,
|
|
166
|
+
type: "text",
|
|
167
|
+
value: inputValue
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
TagsInput.displayName = "TagsInput";
|
|
176
|
+
export {
|
|
177
|
+
TagsInput
|
|
178
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
const TopBar = forwardRef(
|
|
5
|
+
({ children, className, leading, subtitle, title, trailing, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
6
|
+
"header",
|
|
7
|
+
{
|
|
8
|
+
className: cn(
|
|
9
|
+
"flex min-h-14 items-center justify-between gap-3 border-b border-border bg-background px-4 font-mono",
|
|
10
|
+
className
|
|
11
|
+
),
|
|
12
|
+
ref,
|
|
13
|
+
...props,
|
|
14
|
+
children: [
|
|
15
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
16
|
+
leading ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: leading }) : null,
|
|
17
|
+
title || subtitle ? /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
18
|
+
title ? /* @__PURE__ */ jsx("div", { className: "truncate text-sm font-medium uppercase tracking-[0.18em] text-foreground", children: title }) : null,
|
|
19
|
+
subtitle ? /* @__PURE__ */ jsx("div", { className: "truncate text-[11px] uppercase tracking-[0.18em] text-muted-foreground", children: subtitle }) : null
|
|
20
|
+
] }) : null
|
|
21
|
+
] }),
|
|
22
|
+
children ? /* @__PURE__ */ jsx("div", { className: "flex flex-1 items-center justify-center", children }) : null,
|
|
23
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-1 items-center justify-end gap-2", children: trailing })
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
TopBar.displayName = "TopBar";
|
|
29
|
+
export {
|
|
30
|
+
TopBar
|
|
31
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useMemo, useState } from "react";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
const WorkspaceSwitcher = forwardRef(
|
|
6
|
+
({ className, defaultValue, onValueChange, value, workspaces, ...props }, ref) => {
|
|
7
|
+
const fallbackValue = defaultValue ?? workspaces[0]?.id ?? "";
|
|
8
|
+
const [internalValue, setInternalValue] = useState(fallbackValue);
|
|
9
|
+
const currentValue = value ?? internalValue;
|
|
10
|
+
const currentWorkspace = useMemo(
|
|
11
|
+
() => workspaces.find((workspace) => workspace.id === currentValue),
|
|
12
|
+
[currentValue, workspaces]
|
|
13
|
+
);
|
|
14
|
+
function handleSelect(nextValue) {
|
|
15
|
+
if (value === void 0) {
|
|
16
|
+
setInternalValue(nextValue);
|
|
17
|
+
}
|
|
18
|
+
onValueChange?.(nextValue);
|
|
19
|
+
}
|
|
20
|
+
return /* @__PURE__ */ jsxs(
|
|
21
|
+
"div",
|
|
22
|
+
{
|
|
23
|
+
className: cn(
|
|
24
|
+
"inline-flex min-w-0 items-center gap-1 rounded-full border border-border/70 bg-muted/50 p-1",
|
|
25
|
+
className
|
|
26
|
+
),
|
|
27
|
+
ref,
|
|
28
|
+
role: "radiogroup",
|
|
29
|
+
...props,
|
|
30
|
+
children: [
|
|
31
|
+
workspaces.map((workspace) => {
|
|
32
|
+
const isActive = workspace.id === currentValue;
|
|
33
|
+
return /* @__PURE__ */ jsx(
|
|
34
|
+
"button",
|
|
35
|
+
{
|
|
36
|
+
"aria-checked": isActive,
|
|
37
|
+
className: cn(
|
|
38
|
+
"rounded-full px-3 py-1.5 text-sm font-medium transition-colors",
|
|
39
|
+
isActive ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"
|
|
40
|
+
),
|
|
41
|
+
onClick: () => {
|
|
42
|
+
handleSelect(workspace.id);
|
|
43
|
+
},
|
|
44
|
+
role: "radio",
|
|
45
|
+
title: workspace.description,
|
|
46
|
+
type: "button",
|
|
47
|
+
children: workspace.label
|
|
48
|
+
},
|
|
49
|
+
workspace.id
|
|
50
|
+
);
|
|
51
|
+
}),
|
|
52
|
+
currentWorkspace?.description ? /* @__PURE__ */ jsx("span", { className: "hidden pl-2 pr-1 text-xs text-muted-foreground md:inline", children: currentWorkspace.description }) : null
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
WorkspaceSwitcher.displayName = "WorkspaceSwitcher";
|
|
59
|
+
export {
|
|
60
|
+
WorkspaceSwitcher
|
|
61
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { Minus, Plus, RotateCcw } from "lucide-react";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
import { Button } from "../button";
|
|
6
|
+
const ZoomHUD = forwardRef(
|
|
7
|
+
({ className, onReset, onZoomIn, onZoomOut, zoom, ...props }, ref) => /* @__PURE__ */ jsxs(
|
|
8
|
+
"div",
|
|
9
|
+
{
|
|
10
|
+
className: cn(
|
|
11
|
+
"inline-flex items-center gap-1 rounded-sm border border-border bg-background p-1 font-mono",
|
|
12
|
+
className
|
|
13
|
+
),
|
|
14
|
+
ref,
|
|
15
|
+
...props,
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ jsx(
|
|
18
|
+
Button,
|
|
19
|
+
{
|
|
20
|
+
"aria-label": "Zoom out",
|
|
21
|
+
onClick: onZoomOut,
|
|
22
|
+
size: "icon",
|
|
23
|
+
type: "button",
|
|
24
|
+
variant: "ghost",
|
|
25
|
+
children: /* @__PURE__ */ jsx(Minus, { className: "size-4" })
|
|
26
|
+
}
|
|
27
|
+
),
|
|
28
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-16 px-2 text-center text-xs font-medium tabular-nums text-foreground", children: [
|
|
29
|
+
Math.round(zoom * 100),
|
|
30
|
+
"%"
|
|
31
|
+
] }),
|
|
32
|
+
/* @__PURE__ */ jsx(
|
|
33
|
+
Button,
|
|
34
|
+
{
|
|
35
|
+
"aria-label": "Zoom in",
|
|
36
|
+
onClick: onZoomIn,
|
|
37
|
+
size: "icon",
|
|
38
|
+
type: "button",
|
|
39
|
+
variant: "ghost",
|
|
40
|
+
children: /* @__PURE__ */ jsx(Plus, { className: "size-4" })
|
|
41
|
+
}
|
|
42
|
+
),
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
Button,
|
|
45
|
+
{
|
|
46
|
+
"aria-label": "Reset zoom",
|
|
47
|
+
onClick: onReset,
|
|
48
|
+
size: "icon",
|
|
49
|
+
type: "button",
|
|
50
|
+
variant: "ghost",
|
|
51
|
+
children: /* @__PURE__ */ jsx(RotateCcw, { className: "size-4" })
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
ZoomHUD.displayName = "ZoomHUD";
|
|
59
|
+
export {
|
|
60
|
+
ZoomHUD
|
|
61
|
+
};
|