@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.
Files changed (58) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/README.md +27 -12
  3. package/dist/components/activity-log/activity-log.js +1 -0
  4. package/dist/components/anchor-port/anchor-port.js +51 -0
  5. package/dist/components/anchor-port/index.js +4 -0
  6. package/dist/components/animated-text/animated-text.js +1 -0
  7. package/dist/components/bottom-bar/bottom-bar.js +25 -0
  8. package/dist/components/bottom-bar/index.js +4 -0
  9. package/dist/components/canvas-shell/canvas-foundation-demo.js +183 -0
  10. package/dist/components/canvas-shell/canvas-shell-route-config.js +0 -0
  11. package/dist/components/canvas-shell/canvas-shell.js +261 -0
  12. package/dist/components/canvas-shell/index.js +4 -0
  13. package/dist/components/canvas-view/canvas-view.js +461 -0
  14. package/dist/components/canvas-view/index.js +6 -0
  15. package/dist/components/chart/area-chart.js +1 -0
  16. package/dist/components/chart/line-chart.js +1 -0
  17. package/dist/components/chat-dock-section/chat-dock-section.js +56 -0
  18. package/dist/components/chat-dock-section/index.js +6 -0
  19. package/dist/components/connector-edge/connector-edge.js +66 -0
  20. package/dist/components/connector-edge/index.js +6 -0
  21. package/dist/components/data-list/data-list.js +1 -0
  22. package/dist/components/edge-label/edge-label.js +26 -0
  23. package/dist/components/edge-label/index.js +4 -0
  24. package/dist/components/form/form.js +263 -0
  25. package/dist/components/form/index.js +16 -0
  26. package/dist/components/glass-panel/glass-panel.js +21 -0
  27. package/dist/components/glass-panel/index.js +4 -0
  28. package/dist/components/group-hull/group-hull.js +29 -0
  29. package/dist/components/group-hull/index.js +4 -0
  30. package/dist/components/index.js +88 -0
  31. package/dist/components/left-rail/index.js +4 -0
  32. package/dist/components/left-rail/left-rail.js +25 -0
  33. package/dist/components/mini-map-panel/index.js +6 -0
  34. package/dist/components/mini-map-panel/mini-map-panel.js +74 -0
  35. package/dist/components/multi-select/index.js +6 -0
  36. package/dist/components/multi-select/multi-select.js +258 -0
  37. package/dist/components/object-card/index.js +6 -0
  38. package/dist/components/object-card/object-card.js +126 -0
  39. package/dist/components/object-handle/index.js +4 -0
  40. package/dist/components/object-handle/object-handle.js +38 -0
  41. package/dist/components/overview-board/index.js +8 -0
  42. package/dist/components/overview-board/overview-board.js +127 -0
  43. package/dist/components/right-dock/index.js +4 -0
  44. package/dist/components/right-dock/right-dock.js +28 -0
  45. package/dist/components/segmented-control/index.js +12 -0
  46. package/dist/components/segmented-control/segmented-control.js +61 -0
  47. package/dist/components/spinner/unicode-spinner.js +1 -0
  48. package/dist/components/tags-input/index.js +4 -0
  49. package/dist/components/tags-input/tags-input.js +178 -0
  50. package/dist/components/top-bar/index.js +4 -0
  51. package/dist/components/top-bar/top-bar.js +31 -0
  52. package/dist/components/usage-breakdown/usage-breakdown.js +1 -0
  53. package/dist/components/workspace-switcher/index.js +6 -0
  54. package/dist/components/workspace-switcher/workspace-switcher.js +61 -0
  55. package/dist/components/zoom-hud/index.js +4 -0
  56. package/dist/components/zoom-hud/zoom-hud.js +61 -0
  57. package/dist/index.d.ts +455 -5
  58. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ import { TagsInput } from "./tags-input";
2
+ export {
3
+ TagsInput
4
+ };
@@ -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,4 @@
1
+ import { TopBar } from "./top-bar";
2
+ export {
3
+ TopBar
4
+ };
@@ -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
+ };
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx, jsxs } from "react/jsx-runtime";
2
3
  import { forwardRef, useMemo } from "react";
3
4
  import { ArrowDownRight, ArrowUpRight } from "lucide-react";
@@ -0,0 +1,6 @@
1
+ import {
2
+ WorkspaceSwitcher
3
+ } from "./workspace-switcher";
4
+ export {
5
+ WorkspaceSwitcher
6
+ };
@@ -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,4 @@
1
+ import { ZoomHUD } from "./zoom-hud";
2
+ export {
3
+ ZoomHUD
4
+ };
@@ -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
+ };