@tangle-network/sandbox-ui 0.3.12 → 0.4.0
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 +7 -1
- package/dist/auth.js +2 -3
- package/dist/{chat-container-Dn1jWtWo.d.ts → chat-container-Cg-GwyiK.d.ts} +17 -3
- package/dist/chat.d.ts +1 -1
- package/dist/chat.js +1 -1
- package/dist/{chunk-QMKWQF6F.js → chunk-DQYODCBN.js} +102 -30
- package/dist/{chunk-6H3EFUUC.js → chunk-GVUW4VDD.js} +235 -110
- package/dist/chunk-HXEA7L2T.js +1401 -0
- package/dist/{chunk-IAIJUFM6.js → chunk-HYLTXGOI.js} +1 -1
- package/dist/{chunk-MCGKDCOR.js → chunk-IW2JZCOC.js} +55 -14
- package/dist/{chunk-DMYYQXPN.js → chunk-MVYFNPAH.js} +600 -460
- package/dist/{chunk-PCTEG6HR.js → chunk-OHMO7NUX.js} +2 -4
- package/dist/{chunk-CSIXZEKN.js → chunk-SSKVYXCR.js} +94 -1
- package/dist/dashboard.d.ts +1 -1
- package/dist/dashboard.js +40 -6
- package/dist/{document-editor-pane-AVKKXSLG.js → document-editor-pane-5TN2VWGZ.js} +1 -1
- package/dist/{document-editor-pane-Xnl8SmA7.d.ts → document-editor-pane-A70-EhdQ.d.ts} +1 -1
- package/dist/editor.d.ts +2 -2
- package/dist/editor.js +1 -1
- package/dist/files.d.ts +1 -1
- package/dist/files.js +1 -1
- package/dist/{index-BJIPTCKk.d.ts → index-tTfThG0n.d.ts} +131 -26
- package/dist/index.d.ts +6 -4
- package/dist/index.js +76 -16
- package/dist/primitives.d.ts +20 -1
- package/dist/primitives.js +7 -7
- package/dist/workspace.d.ts +8 -2
- package/dist/workspace.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-4HT5J6CE.js +0 -11001
- package/dist/chunk-B26TQ7SA.js +0 -47
package/README.md
CHANGED
|
@@ -222,6 +222,12 @@ For that, compose directly from:
|
|
|
222
222
|
|
|
223
223
|
Retheming is absolutely supported, but the documentation was thinner than it should be. The token layer is strong; the higher-level surfaces are themeable, but more opinionated. For a radically different product look, prefer keeping the token contract and wrapping the higher-level workbench/chat surfaces rather than fighting every internal class.
|
|
224
224
|
|
|
225
|
+
## Docs
|
|
226
|
+
|
|
227
|
+
| Guide | Description |
|
|
228
|
+
|-------|-------------|
|
|
229
|
+
| [Sidebar](./docs/sidebar.md) | Composable Rail + Panel sidebar system (architecture, components, full API) |
|
|
230
|
+
|
|
225
231
|
## Subpath Exports
|
|
226
232
|
|
|
227
233
|
| Subpath | Description |
|
|
@@ -232,7 +238,7 @@ Retheming is absolutely supported, but the documentation was thinner than it sho
|
|
|
232
238
|
| `/workspace` | SandboxWorkbench, WorkspaceLayout, DirectoryPane, RuntimePane, StatusBar |
|
|
233
239
|
| `/openui` | OpenUIArtifactRenderer and schema types for structured artifact rendering |
|
|
234
240
|
| `/files` | FileTree, FilePreview, FileTabs, FileArtifactPane |
|
|
235
|
-
| `/dashboard` | DashboardLayout, BillingDashboard, UsageChart, ProfileSelector |
|
|
241
|
+
| `/dashboard` | [Sidebar](./docs/sidebar.md), DashboardLayout, BillingDashboard, UsageChart, ProfileSelector |
|
|
236
242
|
| `/editor` | TipTap collaborative editor (requires optional peers) |
|
|
237
243
|
| `/terminal` | xterm.js terminal view (requires optional peers) |
|
|
238
244
|
| `/markdown` | Markdown renderer with GFM, code blocks, copy button |
|
package/dist/auth.js
CHANGED
|
@@ -3,9 +3,8 @@ import {
|
|
|
3
3
|
GitHubLoginButton,
|
|
4
4
|
LoginLayout,
|
|
5
5
|
UserMenu
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-MCGKDCOR.js";
|
|
6
|
+
} from "./chunk-OHMO7NUX.js";
|
|
7
|
+
import "./chunk-IW2JZCOC.js";
|
|
9
8
|
import "./chunk-HWLX5NME.js";
|
|
10
9
|
import "./chunk-RQHJBTEU.js";
|
|
11
10
|
export {
|
|
@@ -8,11 +8,13 @@ import { R as Run } from './run-CtFZ6s-D.js';
|
|
|
8
8
|
import { OpenUIAction } from './openui.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* ChatInput — message input bar with file attach, send/cancel
|
|
11
|
+
* ChatInput — message input bar with file attach, drag-and-drop, send/cancel.
|
|
12
12
|
*
|
|
13
13
|
* - Auto-resizing textarea (up to max height)
|
|
14
14
|
* - Enter to send, Shift+Enter for newline
|
|
15
|
-
* -
|
|
15
|
+
* - Drag-and-drop files onto the input with styled overlay
|
|
16
|
+
* - File attachment button (files) + folder attachment button
|
|
17
|
+
* - Pending file/folder chips
|
|
16
18
|
* - Cancel button when streaming
|
|
17
19
|
* - Optional model selector pill
|
|
18
20
|
*/
|
|
@@ -20,6 +22,9 @@ interface PendingFile {
|
|
|
20
22
|
id: string;
|
|
21
23
|
name: string;
|
|
22
24
|
size: number;
|
|
25
|
+
type: "file" | "folder";
|
|
26
|
+
/** Number of files inside (for folders) */
|
|
27
|
+
fileCount?: number;
|
|
23
28
|
status: "pending" | "uploading" | "ready" | "error";
|
|
24
29
|
}
|
|
25
30
|
interface ChatInputProps {
|
|
@@ -34,10 +39,19 @@ interface ChatInputProps {
|
|
|
34
39
|
/** Pending uploaded files */
|
|
35
40
|
pendingFiles?: PendingFile[];
|
|
36
41
|
onRemoveFile?: (id: string) => void;
|
|
42
|
+
/** Called when files are attached (via button or drag-and-drop) */
|
|
37
43
|
onAttach?: (files: FileList) => void;
|
|
44
|
+
/** Called when a folder is selected via the folder button */
|
|
45
|
+
onAttachFolder?: (files: FileList) => void;
|
|
46
|
+
/** Accepted file types for the file input (e.g. ".pdf,.csv") */
|
|
47
|
+
accept?: string;
|
|
48
|
+
/** Drop zone overlay title */
|
|
49
|
+
dropTitle?: string;
|
|
50
|
+
/** Drop zone overlay description */
|
|
51
|
+
dropDescription?: string;
|
|
38
52
|
className?: string;
|
|
39
53
|
}
|
|
40
|
-
declare function ChatInput({ onSend, onCancel, isStreaming, disabled, placeholder, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, className, }: ChatInputProps): react_jsx_runtime.JSX.Element;
|
|
54
|
+
declare function ChatInput({ onSend, onCancel, isStreaming, disabled, placeholder, modelLabel, onModelClick, pendingFiles, onRemoveFile, onAttach, onAttachFolder, accept, dropTitle, dropDescription, className, }: ChatInputProps): react_jsx_runtime.JSX.Element;
|
|
41
55
|
|
|
42
56
|
interface ChatContainerProps {
|
|
43
57
|
messages: SessionMessage[];
|
package/dist/chat.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as ChatContainer, a as ChatContainerProps, b as ChatInput, c as ChatInputProps, P as PendingFile } from './chat-container-
|
|
1
|
+
export { C as ChatContainer, a as ChatContainerProps, b as ChatInput, c as ChatInputProps, P as PendingFile } from './chat-container-Cg-GwyiK.js';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { ReactNode } from 'react';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
package/dist/chat.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-MUOL44AE.js";
|
|
11
11
|
import {
|
|
12
12
|
ChatContainer
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-GVUW4VDD.js";
|
|
14
14
|
import {
|
|
15
15
|
OpenUIArtifactRenderer
|
|
16
16
|
} from "./chunk-YDBXQQLC.js";
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
FileArtifactPane,
|
|
19
19
|
FileTree,
|
|
20
20
|
filterFileTree
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-HYLTXGOI.js";
|
|
22
22
|
import {
|
|
23
23
|
ArtifactPane
|
|
24
24
|
} from "./chunk-W4LM3QYZ.js";
|
|
@@ -121,6 +121,43 @@ function ResizeHandle({ label, onDragStart, onStep, className }) {
|
|
|
121
121
|
}
|
|
122
122
|
);
|
|
123
123
|
}
|
|
124
|
+
function HorizontalResizeHandle({ label, onDragStart, onStep, className }) {
|
|
125
|
+
const handlePointerDown = (event) => {
|
|
126
|
+
event.preventDefault();
|
|
127
|
+
onDragStart(event.clientY);
|
|
128
|
+
};
|
|
129
|
+
const handleKeyDown = (event) => {
|
|
130
|
+
if (event.key === "ArrowUp") {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
onStep(24);
|
|
133
|
+
}
|
|
134
|
+
if (event.key === "ArrowDown") {
|
|
135
|
+
event.preventDefault();
|
|
136
|
+
onStep(-24);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
return /* @__PURE__ */ jsxs(
|
|
140
|
+
"button",
|
|
141
|
+
{
|
|
142
|
+
type: "button",
|
|
143
|
+
"aria-label": label,
|
|
144
|
+
role: "separator",
|
|
145
|
+
"aria-orientation": "horizontal",
|
|
146
|
+
onPointerDown: handlePointerDown,
|
|
147
|
+
onKeyDown: handleKeyDown,
|
|
148
|
+
className: cn(
|
|
149
|
+
"relative hidden h-3 shrink-0 cursor-row-resize lg:flex",
|
|
150
|
+
"items-center justify-center bg-transparent touch-none w-full",
|
|
151
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
|
|
152
|
+
className
|
|
153
|
+
),
|
|
154
|
+
children: [
|
|
155
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-[var(--border-subtle)] transition-colors" }),
|
|
156
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-x-0 top-1/2 h-[3px] -translate-y-1/2 rounded-full bg-transparent hover:bg-[var(--brand-cool)]/30 focus-visible:bg-[var(--brand-cool)]/40" })
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
}
|
|
124
161
|
function MobileDrawer({ side, title, header, onClose, children }) {
|
|
125
162
|
return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex lg:hidden", "aria-modal": "true", role: "dialog", "aria-label": title, children: [
|
|
126
163
|
/* @__PURE__ */ jsx(
|
|
@@ -174,10 +211,13 @@ function WorkspaceLayout({
|
|
|
174
211
|
defaultBottomOpen = false,
|
|
175
212
|
defaultLeftWidth = 280,
|
|
176
213
|
defaultRightWidth = 480,
|
|
214
|
+
defaultBottomHeight = 224,
|
|
177
215
|
minLeftWidth = 220,
|
|
178
216
|
maxLeftWidth = 420,
|
|
179
217
|
minRightWidth = 320,
|
|
180
218
|
maxRightWidth = 720,
|
|
219
|
+
minBottomHeight = 100,
|
|
220
|
+
maxBottomHeight = 500,
|
|
181
221
|
persistenceKey,
|
|
182
222
|
resizable = true,
|
|
183
223
|
theme = "operator",
|
|
@@ -202,6 +242,9 @@ function WorkspaceLayout({
|
|
|
202
242
|
const [rightWidth, setRightWidth] = useState(
|
|
203
243
|
clamp(storedLayout?.rightWidth ?? defaultRightWidth, minRightWidth, maxRightWidth)
|
|
204
244
|
);
|
|
245
|
+
const [bottomHeight, setBottomHeight] = useState(
|
|
246
|
+
clamp(storedLayout?.bottomHeight ?? defaultBottomHeight, minBottomHeight, maxBottomHeight)
|
|
247
|
+
);
|
|
205
248
|
useEffect(() => {
|
|
206
249
|
if (!persistenceKey || typeof window === "undefined") return;
|
|
207
250
|
const payload = {
|
|
@@ -209,16 +252,20 @@ function WorkspaceLayout({
|
|
|
209
252
|
rightOpen,
|
|
210
253
|
bottomOpen,
|
|
211
254
|
leftWidth,
|
|
212
|
-
rightWidth
|
|
255
|
+
rightWidth,
|
|
256
|
+
bottomHeight
|
|
213
257
|
};
|
|
214
258
|
window.localStorage.setItem(persistenceKey, JSON.stringify(payload));
|
|
215
|
-
}, [bottomOpen, leftOpen, leftWidth, persistenceKey, rightOpen, rightWidth]);
|
|
259
|
+
}, [bottomHeight, bottomOpen, leftOpen, leftWidth, persistenceKey, rightOpen, rightWidth]);
|
|
216
260
|
useEffect(() => {
|
|
217
261
|
if (!desktop) return;
|
|
218
262
|
const handlePointerMove = (event) => {
|
|
219
263
|
const dragState = dragStateRef.current;
|
|
220
264
|
if (!dragState) return;
|
|
221
|
-
if (dragState.side === "
|
|
265
|
+
if (dragState.side === "bottom") {
|
|
266
|
+
const delta = dragState.pointerStartY - event.clientY;
|
|
267
|
+
setBottomHeight(clamp(dragState.heightStart + delta, minBottomHeight, maxBottomHeight));
|
|
268
|
+
} else if (dragState.side === "left") {
|
|
222
269
|
const delta = event.clientX - dragState.pointerStartX;
|
|
223
270
|
setLeftWidth(clamp(dragState.widthStart + delta, minLeftWidth, maxLeftWidth));
|
|
224
271
|
} else {
|
|
@@ -237,14 +284,25 @@ function WorkspaceLayout({
|
|
|
237
284
|
window.removeEventListener("pointerup", handlePointerUp);
|
|
238
285
|
window.removeEventListener("pointercancel", handlePointerUp);
|
|
239
286
|
};
|
|
240
|
-
}, [desktop, maxLeftWidth, maxRightWidth, minLeftWidth, minRightWidth]);
|
|
287
|
+
}, [desktop, maxBottomHeight, maxLeftWidth, maxRightWidth, minBottomHeight, minLeftWidth, minRightWidth]);
|
|
241
288
|
const leftStyle = useMemo(() => ({ width: `${leftWidth}px` }), [leftWidth]);
|
|
242
289
|
const rightStyle = useMemo(() => ({ width: `${rightWidth}px` }), [rightWidth]);
|
|
243
290
|
const startResize = (side, pointerStartX) => {
|
|
244
291
|
dragStateRef.current = {
|
|
245
292
|
side,
|
|
246
293
|
pointerStartX,
|
|
247
|
-
|
|
294
|
+
pointerStartY: 0,
|
|
295
|
+
widthStart: side === "left" ? leftWidth : rightWidth,
|
|
296
|
+
heightStart: 0
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
const startBottomResize = (pointerStartY) => {
|
|
300
|
+
dragStateRef.current = {
|
|
301
|
+
side: "bottom",
|
|
302
|
+
pointerStartX: 0,
|
|
303
|
+
pointerStartY,
|
|
304
|
+
widthStart: 0,
|
|
305
|
+
heightStart: bottomHeight
|
|
248
306
|
};
|
|
249
307
|
};
|
|
250
308
|
const stepLeftWidth = (delta) => {
|
|
@@ -253,6 +311,9 @@ function WorkspaceLayout({
|
|
|
253
311
|
const stepRightWidth = (delta) => {
|
|
254
312
|
setRightWidth((current) => clamp(current + delta, minRightWidth, maxRightWidth));
|
|
255
313
|
};
|
|
314
|
+
const stepBottomHeight = (delta) => {
|
|
315
|
+
setBottomHeight((current) => clamp(current + delta, minBottomHeight, maxBottomHeight));
|
|
316
|
+
};
|
|
256
317
|
return /* @__PURE__ */ jsxs(
|
|
257
318
|
"div",
|
|
258
319
|
{
|
|
@@ -334,29 +395,40 @@ function WorkspaceLayout({
|
|
|
334
395
|
)
|
|
335
396
|
] }),
|
|
336
397
|
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: center }),
|
|
337
|
-
bottom && bottomOpen && /* @__PURE__ */ jsxs(
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
398
|
+
bottom && bottomOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
399
|
+
resizable && /* @__PURE__ */ jsx(
|
|
400
|
+
HorizontalResizeHandle,
|
|
401
|
+
{
|
|
402
|
+
label: "Resize bottom panel",
|
|
403
|
+
onDragStart: startBottomResize,
|
|
404
|
+
onStep: stepBottomHeight
|
|
405
|
+
}
|
|
406
|
+
),
|
|
407
|
+
/* @__PURE__ */ jsx(
|
|
408
|
+
"section",
|
|
409
|
+
{
|
|
410
|
+
"aria-label": bottomLabel,
|
|
411
|
+
className: "border-t border-[var(--border-subtle)] bg-[var(--bg-card)] shrink-0",
|
|
412
|
+
style: { height: `${bottomHeight}px` },
|
|
413
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
|
|
414
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-[var(--border-subtle)] px-3 py-2 shrink-0", children: [
|
|
415
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: bottomHeader ?? /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-[0.12em] text-[var(--text-muted)]", children: "Runtime" }) }),
|
|
416
|
+
/* @__PURE__ */ jsx(
|
|
417
|
+
"button",
|
|
418
|
+
{
|
|
419
|
+
type: "button",
|
|
420
|
+
"aria-label": "Collapse bottom panel",
|
|
421
|
+
onClick: () => setBottomOpen(false),
|
|
422
|
+
className: "rounded-[var(--radius-sm)] p-1.5 text-[var(--text-muted)] transition-colors hover:bg-[var(--bg-hover)] hover:text-[var(--text-secondary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--brand-cool)]/60",
|
|
423
|
+
children: /* @__PURE__ */ jsx(PanelBottomClose, { className: "h-4 w-4" })
|
|
424
|
+
}
|
|
425
|
+
)
|
|
426
|
+
] }),
|
|
427
|
+
/* @__PURE__ */ jsx("div", { className: "min-h-0 flex-1 overflow-auto", children: bottom })
|
|
428
|
+
] })
|
|
429
|
+
}
|
|
430
|
+
)
|
|
431
|
+
] }),
|
|
360
432
|
centerFooter && /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-[var(--border-subtle)] bg-[var(--bg-dark)]", children: centerFooter })
|
|
361
433
|
] }),
|
|
362
434
|
desktop && right && rightOpen && /* @__PURE__ */ jsxs(Fragment, { children: [
|