@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,461 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import {
|
|
4
|
+
forwardRef,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
useId,
|
|
8
|
+
useImperativeHandle,
|
|
9
|
+
useRef,
|
|
10
|
+
useState
|
|
11
|
+
} from "react";
|
|
12
|
+
import { cn } from "../../lib/utils";
|
|
13
|
+
const DEFAULT_VIEWPORT = { x: 0, y: 0, zoom: 1 };
|
|
14
|
+
const INTERACTIVE_ELEMENT_SELECTOR = [
|
|
15
|
+
"a[href]",
|
|
16
|
+
"button",
|
|
17
|
+
'input:not([type="hidden"])',
|
|
18
|
+
"select",
|
|
19
|
+
"textarea",
|
|
20
|
+
"summary",
|
|
21
|
+
'[contenteditable=""]',
|
|
22
|
+
'[contenteditable="true"]',
|
|
23
|
+
'[role="button"]',
|
|
24
|
+
'[role="checkbox"]',
|
|
25
|
+
'[role="link"]',
|
|
26
|
+
'[role="menuitem"]',
|
|
27
|
+
'[role="option"]',
|
|
28
|
+
'[role="radio"]',
|
|
29
|
+
'[role="slider"]',
|
|
30
|
+
'[role="spinbutton"]',
|
|
31
|
+
'[role="switch"]',
|
|
32
|
+
'[role="tab"]',
|
|
33
|
+
'[role="textbox"]'
|
|
34
|
+
].join(", ");
|
|
35
|
+
function clampZoom(value, minZoom, maxZoom) {
|
|
36
|
+
return Math.min(maxZoom, Math.max(minZoom, Number(value.toFixed(2))));
|
|
37
|
+
}
|
|
38
|
+
function isHtmlElement(target) {
|
|
39
|
+
return target instanceof HTMLElement;
|
|
40
|
+
}
|
|
41
|
+
function isInteractiveDescendant(element, container) {
|
|
42
|
+
const interactiveAncestor = element.closest(INTERACTIVE_ELEMENT_SELECTOR);
|
|
43
|
+
return interactiveAncestor !== null && container.contains(interactiveAncestor);
|
|
44
|
+
}
|
|
45
|
+
function supportsScrollableOverflow(value) {
|
|
46
|
+
return value === "auto" || value === "overlay" || value === "scroll";
|
|
47
|
+
}
|
|
48
|
+
function hasScrollableAxis(element, axis) {
|
|
49
|
+
const style = window.getComputedStyle(element);
|
|
50
|
+
if (axis === "x") {
|
|
51
|
+
return supportsScrollableOverflow(style.overflowX) && element.scrollWidth > element.clientWidth;
|
|
52
|
+
}
|
|
53
|
+
return supportsScrollableOverflow(style.overflowY) && element.scrollHeight > element.clientHeight;
|
|
54
|
+
}
|
|
55
|
+
function hasScrollableAncestor(element, container, delta) {
|
|
56
|
+
if (!container.contains(element) || element === container) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (delta.x !== 0 && hasScrollableAxis(element, "x") || delta.y !== 0 && hasScrollableAxis(element, "y")) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return element.parentElement === null ? false : hasScrollableAncestor(element.parentElement, container, delta);
|
|
63
|
+
}
|
|
64
|
+
function shouldHandleCanvasKeyboardEvent(event) {
|
|
65
|
+
if (isHtmlElement(event.target) && event.target !== event.currentTarget && isInteractiveDescendant(event.target, event.currentTarget)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
function shouldHandleCanvasWheelEvent(event) {
|
|
71
|
+
if (isHtmlElement(event.target) && hasScrollableAncestor(event.target, event.currentTarget, {
|
|
72
|
+
x: event.deltaX,
|
|
73
|
+
y: event.deltaY
|
|
74
|
+
})) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
function isPanGesture(event, isSpacePressed) {
|
|
80
|
+
return event.button === 1 || event.button === 0 && isSpacePressed;
|
|
81
|
+
}
|
|
82
|
+
function createViewportKeyHandler({
|
|
83
|
+
nudgeViewport,
|
|
84
|
+
resetViewport,
|
|
85
|
+
setViewport,
|
|
86
|
+
viewportRef,
|
|
87
|
+
zoomStep
|
|
88
|
+
}) {
|
|
89
|
+
return (event) => {
|
|
90
|
+
if (event.key === "+" || event.key === "=") {
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
setViewport({
|
|
93
|
+
...viewportRef.current,
|
|
94
|
+
zoom: viewportRef.current.zoom + zoomStep
|
|
95
|
+
});
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (event.key === "-") {
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
setViewport({
|
|
101
|
+
...viewportRef.current,
|
|
102
|
+
zoom: viewportRef.current.zoom - zoomStep
|
|
103
|
+
});
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (event.key === "0") {
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
resetViewport();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
if (event.key === "ArrowLeft") {
|
|
112
|
+
event.preventDefault();
|
|
113
|
+
nudgeViewport(40, 0);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (event.key === "ArrowRight") {
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
nudgeViewport(-40, 0);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (event.key === "ArrowUp") {
|
|
122
|
+
event.preventDefault();
|
|
123
|
+
nudgeViewport(0, 40);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (event.key === "ArrowDown") {
|
|
127
|
+
event.preventDefault();
|
|
128
|
+
nudgeViewport(0, -40);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function useViewportState({
|
|
133
|
+
defaultViewport,
|
|
134
|
+
maxZoom,
|
|
135
|
+
minZoom,
|
|
136
|
+
onViewportChange
|
|
137
|
+
}) {
|
|
138
|
+
const defaultViewportRef = useRef(defaultViewport);
|
|
139
|
+
const viewportRef = useRef(defaultViewport);
|
|
140
|
+
const [viewport, setViewport] = useState(defaultViewport);
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
defaultViewportRef.current = defaultViewport;
|
|
143
|
+
}, [defaultViewport]);
|
|
144
|
+
const applyViewport = useCallback(
|
|
145
|
+
(nextViewport) => {
|
|
146
|
+
const resolvedViewport = {
|
|
147
|
+
x: Math.round(nextViewport.x),
|
|
148
|
+
y: Math.round(nextViewport.y),
|
|
149
|
+
zoom: clampZoom(nextViewport.zoom, minZoom, maxZoom)
|
|
150
|
+
};
|
|
151
|
+
viewportRef.current = resolvedViewport;
|
|
152
|
+
setViewport(resolvedViewport);
|
|
153
|
+
onViewportChange?.(resolvedViewport);
|
|
154
|
+
},
|
|
155
|
+
[maxZoom, minZoom, onViewportChange]
|
|
156
|
+
);
|
|
157
|
+
const resetViewport = useCallback(() => {
|
|
158
|
+
applyViewport(defaultViewportRef.current);
|
|
159
|
+
}, [applyViewport]);
|
|
160
|
+
const nudgeViewport = useCallback(
|
|
161
|
+
(deltaX, deltaY) => {
|
|
162
|
+
const currentViewport = viewportRef.current;
|
|
163
|
+
applyViewport({
|
|
164
|
+
x: currentViewport.x + deltaX,
|
|
165
|
+
y: currentViewport.y + deltaY,
|
|
166
|
+
zoom: currentViewport.zoom
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
[applyViewport]
|
|
170
|
+
);
|
|
171
|
+
return {
|
|
172
|
+
nudgeViewport,
|
|
173
|
+
resetViewport,
|
|
174
|
+
setViewport: applyViewport,
|
|
175
|
+
viewport,
|
|
176
|
+
viewportRef
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function useCanvasKeyboardInteractions({
|
|
180
|
+
nudgeViewport,
|
|
181
|
+
resetViewport,
|
|
182
|
+
setViewport,
|
|
183
|
+
viewportRef,
|
|
184
|
+
zoomStep
|
|
185
|
+
}) {
|
|
186
|
+
const [isSpacePressed, setIsSpacePressed] = useState(false);
|
|
187
|
+
const handleWheel = useCallback(
|
|
188
|
+
(event) => {
|
|
189
|
+
if (event.ctrlKey || event.metaKey) {
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
setViewport({
|
|
192
|
+
...viewportRef.current,
|
|
193
|
+
zoom: viewportRef.current.zoom + (event.deltaY > 0 ? -zoomStep : zoomStep)
|
|
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
|
+
);
|
|
205
|
+
const handleKeyDown = useCallback(
|
|
206
|
+
(event) => {
|
|
207
|
+
if (!shouldHandleCanvasKeyboardEvent(event)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (event.key === " ") {
|
|
211
|
+
event.preventDefault();
|
|
212
|
+
setIsSpacePressed(true);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
createViewportKeyHandler({
|
|
216
|
+
nudgeViewport,
|
|
217
|
+
resetViewport,
|
|
218
|
+
setViewport,
|
|
219
|
+
viewportRef,
|
|
220
|
+
zoomStep
|
|
221
|
+
})(event);
|
|
222
|
+
},
|
|
223
|
+
[nudgeViewport, resetViewport, setViewport, viewportRef, zoomStep]
|
|
224
|
+
);
|
|
225
|
+
const handleKeyUp = useCallback(
|
|
226
|
+
(event) => {
|
|
227
|
+
if (!shouldHandleCanvasKeyboardEvent(event)) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (event.key === " ") {
|
|
231
|
+
setIsSpacePressed(false);
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
[]
|
|
235
|
+
);
|
|
236
|
+
return { handleKeyDown, handleKeyUp, handleWheel, isSpacePressed };
|
|
237
|
+
}
|
|
238
|
+
function endCanvasDrag(event, dragOriginRef, setIsDragging) {
|
|
239
|
+
dragOriginRef.current = null;
|
|
240
|
+
setIsDragging(false);
|
|
241
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
242
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function useCanvasPointerInteractions({
|
|
246
|
+
isSpacePressed,
|
|
247
|
+
setViewport,
|
|
248
|
+
viewportRef
|
|
249
|
+
}) {
|
|
250
|
+
const dragOriginRef = useRef(null);
|
|
251
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
252
|
+
const handlePointerDown = useCallback(
|
|
253
|
+
(event) => {
|
|
254
|
+
if (!isPanGesture(event, isSpacePressed)) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (event.button === 1) {
|
|
258
|
+
event.preventDefault();
|
|
259
|
+
}
|
|
260
|
+
dragOriginRef.current = {
|
|
261
|
+
pointerX: event.clientX,
|
|
262
|
+
pointerY: event.clientY,
|
|
263
|
+
viewport: viewportRef.current
|
|
264
|
+
};
|
|
265
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
266
|
+
setIsDragging(true);
|
|
267
|
+
},
|
|
268
|
+
[isSpacePressed, viewportRef]
|
|
269
|
+
);
|
|
270
|
+
const handlePointerMove = useCallback(
|
|
271
|
+
(event) => {
|
|
272
|
+
const dragOrigin = dragOriginRef.current;
|
|
273
|
+
if (!dragOrigin) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
setViewport({
|
|
277
|
+
x: dragOrigin.viewport.x + (event.clientX - dragOrigin.pointerX),
|
|
278
|
+
y: dragOrigin.viewport.y + (event.clientY - dragOrigin.pointerY),
|
|
279
|
+
zoom: dragOrigin.viewport.zoom
|
|
280
|
+
});
|
|
281
|
+
},
|
|
282
|
+
[setViewport]
|
|
283
|
+
);
|
|
284
|
+
const handlePointerCancel = useCallback(
|
|
285
|
+
(event) => {
|
|
286
|
+
endCanvasDrag(event, dragOriginRef, setIsDragging);
|
|
287
|
+
},
|
|
288
|
+
[]
|
|
289
|
+
);
|
|
290
|
+
const handlePointerUp = useCallback(
|
|
291
|
+
(event) => {
|
|
292
|
+
endCanvasDrag(event, dragOriginRef, setIsDragging);
|
|
293
|
+
},
|
|
294
|
+
[]
|
|
295
|
+
);
|
|
296
|
+
return {
|
|
297
|
+
handlePointerCancel,
|
|
298
|
+
handlePointerDown,
|
|
299
|
+
handlePointerMove,
|
|
300
|
+
handlePointerUp,
|
|
301
|
+
isDragging
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function usePreventBodySelection(disabled) {
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
if (typeof document === "undefined") {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const { body } = document;
|
|
310
|
+
const previousUserSelect = body.style.userSelect;
|
|
311
|
+
if (disabled) {
|
|
312
|
+
body.style.userSelect = "none";
|
|
313
|
+
}
|
|
314
|
+
return () => {
|
|
315
|
+
body.style.userSelect = previousUserSelect;
|
|
316
|
+
};
|
|
317
|
+
}, [disabled]);
|
|
318
|
+
}
|
|
319
|
+
function useCanvasViewHandle(ref, viewportState) {
|
|
320
|
+
useImperativeHandle(
|
|
321
|
+
ref,
|
|
322
|
+
() => ({
|
|
323
|
+
resetViewport: viewportState.resetViewport,
|
|
324
|
+
setViewport: viewportState.setViewport
|
|
325
|
+
}),
|
|
326
|
+
[viewportState.resetViewport, viewportState.setViewport]
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
function CanvasInteractionLayer({
|
|
330
|
+
children,
|
|
331
|
+
instructionsId,
|
|
332
|
+
isDragging,
|
|
333
|
+
isSpacePressed,
|
|
334
|
+
onKeyDown,
|
|
335
|
+
onKeyUp,
|
|
336
|
+
onPointerCancel,
|
|
337
|
+
onPointerDown,
|
|
338
|
+
onPointerMove,
|
|
339
|
+
onPointerUp,
|
|
340
|
+
onWheel,
|
|
341
|
+
viewport
|
|
342
|
+
}) {
|
|
343
|
+
return /* @__PURE__ */ jsxs(
|
|
344
|
+
"div",
|
|
345
|
+
{
|
|
346
|
+
"aria-describedby": instructionsId,
|
|
347
|
+
"aria-label": "Canvas workspace",
|
|
348
|
+
"aria-roledescription": "canvas",
|
|
349
|
+
className: cn(
|
|
350
|
+
"relative h-full w-full select-none touch-none outline-none",
|
|
351
|
+
isDragging || isSpacePressed ? "cursor-grab active:cursor-grabbing" : "cursor-default"
|
|
352
|
+
),
|
|
353
|
+
"data-viewport": JSON.stringify(viewport),
|
|
354
|
+
onKeyDown,
|
|
355
|
+
onKeyUp,
|
|
356
|
+
onPointerCancel,
|
|
357
|
+
onPointerDown,
|
|
358
|
+
onPointerMove,
|
|
359
|
+
onPointerUp,
|
|
360
|
+
onWheel,
|
|
361
|
+
role: "button",
|
|
362
|
+
tabIndex: 0,
|
|
363
|
+
children: [
|
|
364
|
+
/* @__PURE__ */ jsx("div", { className: "sr-only", id: instructionsId, children: "Hold space and drag or use the middle mouse button to pan. Use plus, minus, or control wheel to zoom. Press zero to reset the viewport." }),
|
|
365
|
+
children
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
function CanvasContentLayer({
|
|
371
|
+
children,
|
|
372
|
+
overlay,
|
|
373
|
+
viewport
|
|
374
|
+
}) {
|
|
375
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
376
|
+
/* @__PURE__ */ jsx(
|
|
377
|
+
"div",
|
|
378
|
+
{
|
|
379
|
+
className: "absolute inset-0 origin-top-left transition-transform duration-150 ease-out",
|
|
380
|
+
style: {
|
|
381
|
+
transform: `translate3d(${viewport.x}px, ${viewport.y}px, 0) scale(${viewport.zoom})`
|
|
382
|
+
},
|
|
383
|
+
children
|
|
384
|
+
}
|
|
385
|
+
),
|
|
386
|
+
overlay ? /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 z-20", children: overlay }) : null
|
|
387
|
+
] });
|
|
388
|
+
}
|
|
389
|
+
const CanvasView = forwardRef(
|
|
390
|
+
({
|
|
391
|
+
children,
|
|
392
|
+
className,
|
|
393
|
+
defaultViewport = DEFAULT_VIEWPORT,
|
|
394
|
+
maxZoom = 2,
|
|
395
|
+
minZoom = 0.5,
|
|
396
|
+
onViewportChange,
|
|
397
|
+
overlay,
|
|
398
|
+
zoomStep = 0.1,
|
|
399
|
+
...props
|
|
400
|
+
}, ref) => {
|
|
401
|
+
const instructionsId = useId();
|
|
402
|
+
const viewportState = useViewportState({
|
|
403
|
+
defaultViewport,
|
|
404
|
+
maxZoom,
|
|
405
|
+
minZoom,
|
|
406
|
+
onViewportChange
|
|
407
|
+
});
|
|
408
|
+
const keyboard = useCanvasKeyboardInteractions({
|
|
409
|
+
nudgeViewport: viewportState.nudgeViewport,
|
|
410
|
+
resetViewport: viewportState.resetViewport,
|
|
411
|
+
setViewport: viewportState.setViewport,
|
|
412
|
+
viewportRef: viewportState.viewportRef,
|
|
413
|
+
zoomStep
|
|
414
|
+
});
|
|
415
|
+
const pointer = useCanvasPointerInteractions({
|
|
416
|
+
isSpacePressed: keyboard.isSpacePressed,
|
|
417
|
+
setViewport: viewportState.setViewport,
|
|
418
|
+
viewportRef: viewportState.viewportRef
|
|
419
|
+
});
|
|
420
|
+
usePreventBodySelection(pointer.isDragging);
|
|
421
|
+
useCanvasViewHandle(ref, viewportState);
|
|
422
|
+
return /* @__PURE__ */ jsx(
|
|
423
|
+
"div",
|
|
424
|
+
{
|
|
425
|
+
className: cn(
|
|
426
|
+
"relative h-full min-h-[32rem] overflow-hidden rounded-sm border border-border bg-background",
|
|
427
|
+
className
|
|
428
|
+
),
|
|
429
|
+
...props,
|
|
430
|
+
children: /* @__PURE__ */ jsx(
|
|
431
|
+
CanvasInteractionLayer,
|
|
432
|
+
{
|
|
433
|
+
instructionsId,
|
|
434
|
+
isDragging: pointer.isDragging,
|
|
435
|
+
isSpacePressed: keyboard.isSpacePressed,
|
|
436
|
+
onKeyDown: keyboard.handleKeyDown,
|
|
437
|
+
onKeyUp: keyboard.handleKeyUp,
|
|
438
|
+
onPointerCancel: pointer.handlePointerCancel,
|
|
439
|
+
onPointerDown: pointer.handlePointerDown,
|
|
440
|
+
onPointerMove: pointer.handlePointerMove,
|
|
441
|
+
onPointerUp: pointer.handlePointerUp,
|
|
442
|
+
onWheel: keyboard.handleWheel,
|
|
443
|
+
viewport: viewportState.viewport,
|
|
444
|
+
children: /* @__PURE__ */ jsx(
|
|
445
|
+
CanvasContentLayer,
|
|
446
|
+
{
|
|
447
|
+
overlay,
|
|
448
|
+
viewport: viewportState.viewport,
|
|
449
|
+
children
|
|
450
|
+
}
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
);
|
|
458
|
+
CanvasView.displayName = "CanvasView";
|
|
459
|
+
export {
|
|
460
|
+
CanvasView
|
|
461
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { ArrowUpRight, MessageSquareText } from "lucide-react";
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
import { Button } from "../button";
|
|
6
|
+
const ChatDockSection = forwardRef(
|
|
7
|
+
({
|
|
8
|
+
className,
|
|
9
|
+
composerPlaceholder = "Ask about runs, errors, or pending work\u2026",
|
|
10
|
+
contextLabel,
|
|
11
|
+
messages,
|
|
12
|
+
title = "Assistant",
|
|
13
|
+
...props
|
|
14
|
+
}, ref) => /* @__PURE__ */ jsxs(
|
|
15
|
+
"section",
|
|
16
|
+
{
|
|
17
|
+
className: cn(
|
|
18
|
+
"flex flex-col gap-4 rounded-2xl border border-border/70 bg-background/75 p-4 shadow-[0_10px_35px_hsl(var(--foreground)/0.06)] backdrop-blur-xl",
|
|
19
|
+
className
|
|
20
|
+
),
|
|
21
|
+
ref,
|
|
22
|
+
...props,
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
25
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
26
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [
|
|
27
|
+
/* @__PURE__ */ jsx(MessageSquareText, { className: "size-4 text-primary" }),
|
|
28
|
+
title
|
|
29
|
+
] }),
|
|
30
|
+
contextLabel ? /* @__PURE__ */ jsx("div", { className: "text-xs uppercase tracking-[0.24em] text-muted-foreground", children: contextLabel }) : null
|
|
31
|
+
] }),
|
|
32
|
+
/* @__PURE__ */ jsxs(Button, { size: "sm", type: "button", variant: "ghost", children: [
|
|
33
|
+
"Open thread",
|
|
34
|
+
/* @__PURE__ */ jsx(ArrowUpRight, { className: "size-4" })
|
|
35
|
+
] })
|
|
36
|
+
] }),
|
|
37
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-3", children: messages.map((message) => /* @__PURE__ */ jsxs(
|
|
38
|
+
"div",
|
|
39
|
+
{
|
|
40
|
+
className: "rounded-xl border border-border/60 bg-background/85 px-3 py-2",
|
|
41
|
+
children: [
|
|
42
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-medium uppercase tracking-[0.18em] text-muted-foreground", children: message.speaker }),
|
|
43
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 text-sm leading-6 text-foreground", children: message.body })
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
message.id
|
|
47
|
+
)) }),
|
|
48
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-xl border border-dashed border-border/80 bg-background/70 px-3 py-3 text-sm text-muted-foreground", children: composerPlaceholder })
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
ChatDockSection.displayName = "ChatDockSection";
|
|
54
|
+
export {
|
|
55
|
+
ChatDockSection
|
|
56
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
import { EdgeLabel } from "../edge-label";
|
|
5
|
+
const strokeClasses = {
|
|
6
|
+
active: "stroke-sky-500",
|
|
7
|
+
blocked: "stroke-amber-500",
|
|
8
|
+
idle: "stroke-muted-foreground/60"
|
|
9
|
+
};
|
|
10
|
+
const ConnectorEdge = forwardRef(
|
|
11
|
+
({ className, end, label, start, state = "idle", ...props }, ref) => {
|
|
12
|
+
const width = Math.max(Math.abs(end.x - start.x), 32);
|
|
13
|
+
const height = Math.max(Math.abs(end.y - start.y), 32);
|
|
14
|
+
const midX = width / 2;
|
|
15
|
+
const startX = start.x <= end.x ? 4 : width - 4;
|
|
16
|
+
const endX = start.x <= end.x ? width - 4 : 4;
|
|
17
|
+
const startY = start.y <= end.y ? 4 : height - 4;
|
|
18
|
+
const endY = start.y <= end.y ? height - 4 : 4;
|
|
19
|
+
const path = `M ${startX} ${startY} C ${midX} ${startY}, ${midX} ${endY}, ${endX} ${endY}`;
|
|
20
|
+
const style = {
|
|
21
|
+
height,
|
|
22
|
+
width
|
|
23
|
+
};
|
|
24
|
+
return /* @__PURE__ */ jsxs(
|
|
25
|
+
"div",
|
|
26
|
+
{
|
|
27
|
+
className: cn("relative inline-flex", className),
|
|
28
|
+
ref,
|
|
29
|
+
style,
|
|
30
|
+
...props,
|
|
31
|
+
children: [
|
|
32
|
+
/* @__PURE__ */ jsx(
|
|
33
|
+
"svg",
|
|
34
|
+
{
|
|
35
|
+
className: "overflow-visible",
|
|
36
|
+
height,
|
|
37
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
38
|
+
width,
|
|
39
|
+
children: /* @__PURE__ */ jsx(
|
|
40
|
+
"path",
|
|
41
|
+
{
|
|
42
|
+
className: cn("fill-none stroke-[2.5]", strokeClasses[state]),
|
|
43
|
+
d: path,
|
|
44
|
+
strokeDasharray: state === "blocked" ? "4 4" : void 0,
|
|
45
|
+
strokeLinecap: "round"
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
label ? /* @__PURE__ */ jsx(
|
|
51
|
+
EdgeLabel,
|
|
52
|
+
{
|
|
53
|
+
className: "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2",
|
|
54
|
+
emphasis: state === "active" ? "active" : "subtle",
|
|
55
|
+
children: label
|
|
56
|
+
}
|
|
57
|
+
) : null
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
ConnectorEdge.displayName = "ConnectorEdge";
|
|
64
|
+
export {
|
|
65
|
+
ConnectorEdge
|
|
66
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { cn } from "../../lib/utils";
|
|
4
|
+
const emphasisClasses = {
|
|
5
|
+
active: "border-sky-500/30 bg-sky-500/10 text-sky-700 dark:text-sky-300",
|
|
6
|
+
subtle: "border-border/60 bg-background/90 text-muted-foreground"
|
|
7
|
+
};
|
|
8
|
+
const EdgeLabel = forwardRef(
|
|
9
|
+
({ className, emphasis = "subtle", ...props }, ref) => /* @__PURE__ */ jsx(
|
|
10
|
+
"span",
|
|
11
|
+
{
|
|
12
|
+
className: cn(
|
|
13
|
+
"inline-flex items-center rounded-full border px-2.5 py-1 text-[11px] font-medium uppercase tracking-[0.18em] shadow-sm",
|
|
14
|
+
emphasisClasses[emphasis],
|
|
15
|
+
className
|
|
16
|
+
),
|
|
17
|
+
"data-emphasis": emphasis,
|
|
18
|
+
ref,
|
|
19
|
+
...props
|
|
20
|
+
}
|
|
21
|
+
)
|
|
22
|
+
);
|
|
23
|
+
EdgeLabel.displayName = "EdgeLabel";
|
|
24
|
+
export {
|
|
25
|
+
EdgeLabel
|
|
26
|
+
};
|