@browsernode/elements 0.0.1

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 (92) hide show
  1. package/README.md +107 -0
  2. package/dist/console.d.ts +3 -0
  3. package/dist/console.d.ts.map +1 -0
  4. package/dist/console.js +161 -0
  5. package/dist/console.js.map +1 -0
  6. package/dist/editor/internal/language.d.ts +3 -0
  7. package/dist/editor/internal/language.d.ts.map +1 -0
  8. package/dist/editor/internal/tree.d.ts +13 -0
  9. package/dist/editor/internal/tree.d.ts.map +1 -0
  10. package/dist/editor/primitives/code-editor.d.ts +26 -0
  11. package/dist/editor/primitives/code-editor.d.ts.map +1 -0
  12. package/dist/editor/primitives/file-tree.d.ts +27 -0
  13. package/dist/editor/primitives/file-tree.d.ts.map +1 -0
  14. package/dist/editor/sandbox-code-editor.d.ts +32 -0
  15. package/dist/editor/sandbox-code-editor.d.ts.map +1 -0
  16. package/dist/editor/sandbox-file-tree.d.ts +29 -0
  17. package/dist/editor/sandbox-file-tree.d.ts.map +1 -0
  18. package/dist/editor/sandbox-ide.d.ts +23 -0
  19. package/dist/editor/sandbox-ide.d.ts.map +1 -0
  20. package/dist/editor.d.ts +6 -0
  21. package/dist/editor.d.ts.map +1 -0
  22. package/dist/editor.js +990 -0
  23. package/dist/editor.js.map +1 -0
  24. package/dist/files/geist-cyrillic-wght-normal.woff2 +0 -0
  25. package/dist/files/geist-latin-ext-wght-normal.woff2 +0 -0
  26. package/dist/files/geist-latin-wght-normal.woff2 +0 -0
  27. package/dist/index.d.ts +9 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +2556 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/preview/primitives/web-preview.d.ts +36 -0
  32. package/dist/preview/primitives/web-preview.d.ts.map +1 -0
  33. package/dist/preview/sandbox-preview.d.ts +58 -0
  34. package/dist/preview/sandbox-preview.d.ts.map +1 -0
  35. package/dist/primitives/lib/utils.d.ts +3 -0
  36. package/dist/primitives/lib/utils.d.ts.map +1 -0
  37. package/dist/primitives/stack-trace.d.ts +38 -0
  38. package/dist/primitives/stack-trace.d.ts.map +1 -0
  39. package/dist/primitives/ui/avatar.d.ts +12 -0
  40. package/dist/primitives/ui/avatar.d.ts.map +1 -0
  41. package/dist/primitives/ui/badge.d.ts +8 -0
  42. package/dist/primitives/ui/badge.d.ts.map +1 -0
  43. package/dist/primitives/ui/button-group.d.ts +11 -0
  44. package/dist/primitives/ui/button-group.d.ts.map +1 -0
  45. package/dist/primitives/ui/button.d.ts +9 -0
  46. package/dist/primitives/ui/button.d.ts.map +1 -0
  47. package/dist/primitives/ui/collapsible.d.ts +6 -0
  48. package/dist/primitives/ui/collapsible.d.ts.map +1 -0
  49. package/dist/primitives/ui/dialog.d.ts +18 -0
  50. package/dist/primitives/ui/dialog.d.ts.map +1 -0
  51. package/dist/primitives/ui/dropdown-menu.d.ts +30 -0
  52. package/dist/primitives/ui/dropdown-menu.d.ts.map +1 -0
  53. package/dist/primitives/ui/empty.d.ts +12 -0
  54. package/dist/primitives/ui/empty.d.ts.map +1 -0
  55. package/dist/primitives/ui/hover-card.d.ts +6 -0
  56. package/dist/primitives/ui/hover-card.d.ts.map +1 -0
  57. package/dist/primitives/ui/input-group.d.ts +19 -0
  58. package/dist/primitives/ui/input-group.d.ts.map +1 -0
  59. package/dist/primitives/ui/input.d.ts +4 -0
  60. package/dist/primitives/ui/input.d.ts.map +1 -0
  61. package/dist/primitives/ui/loading-dots.d.ts +7 -0
  62. package/dist/primitives/ui/loading-dots.d.ts.map +1 -0
  63. package/dist/primitives/ui/loading.d.ts +6 -0
  64. package/dist/primitives/ui/loading.d.ts.map +1 -0
  65. package/dist/primitives/ui/popover.d.ts +10 -0
  66. package/dist/primitives/ui/popover.d.ts.map +1 -0
  67. package/dist/primitives/ui/scroll-area.d.ts +5 -0
  68. package/dist/primitives/ui/scroll-area.d.ts.map +1 -0
  69. package/dist/primitives/ui/select.d.ts +16 -0
  70. package/dist/primitives/ui/select.d.ts.map +1 -0
  71. package/dist/primitives/ui/separator.d.ts +4 -0
  72. package/dist/primitives/ui/separator.d.ts.map +1 -0
  73. package/dist/primitives/ui/spinner.d.ts +3 -0
  74. package/dist/primitives/ui/spinner.d.ts.map +1 -0
  75. package/dist/primitives/ui/tabs.d.ts +11 -0
  76. package/dist/primitives/ui/tabs.d.ts.map +1 -0
  77. package/dist/primitives/ui/textarea.d.ts +4 -0
  78. package/dist/primitives/ui/textarea.d.ts.map +1 -0
  79. package/dist/primitives/ui/tooltip.d.ts +7 -0
  80. package/dist/primitives/ui/tooltip.d.ts.map +1 -0
  81. package/dist/provider/sandbox-provider.d.ts +44 -0
  82. package/dist/provider/sandbox-provider.d.ts.map +1 -0
  83. package/dist/sandbox-attribution.d.ts +9 -0
  84. package/dist/sandbox-attribution.d.ts.map +1 -0
  85. package/dist/sandbox-chrome.d.ts +38 -0
  86. package/dist/sandbox-chrome.d.ts.map +1 -0
  87. package/dist/sandbox.d.ts +10 -0
  88. package/dist/sandbox.d.ts.map +1 -0
  89. package/dist/snapshots/sandbox-snapshots.d.ts +14 -0
  90. package/dist/snapshots/sandbox-snapshots.d.ts.map +1 -0
  91. package/dist/styles.css +2 -0
  92. package/package.json +76 -0
package/dist/editor.js ADDED
@@ -0,0 +1,990 @@
1
+ // src/editor/sandbox-file-tree.tsx
2
+ import { useEffect, useMemo as useMemo3, useState as useState3 } from "react";
3
+ import { MenuIcon } from "lucide-react";
4
+
5
+ // src/primitives/ui/collapsible.tsx
6
+ import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible";
7
+ import { jsx } from "react/jsx-runtime";
8
+ function Collapsible({ ...props }) {
9
+ return /* @__PURE__ */ jsx(CollapsiblePrimitive.Root, { "data-slot": "collapsible", ...props });
10
+ }
11
+ function CollapsibleTrigger({ ...props }) {
12
+ return /* @__PURE__ */ jsx(CollapsiblePrimitive.Trigger, { "data-slot": "collapsible-trigger", ...props });
13
+ }
14
+ function CollapsibleContent({ ...props }) {
15
+ return /* @__PURE__ */ jsx(CollapsiblePrimitive.Panel, { "data-slot": "collapsible-content", ...props });
16
+ }
17
+
18
+ // src/primitives/lib/utils.ts
19
+ import { clsx } from "clsx";
20
+ import { twMerge } from "tailwind-merge";
21
+ function cn(...inputs) {
22
+ return twMerge(clsx(inputs));
23
+ }
24
+
25
+ // src/editor/primitives/file-tree.tsx
26
+ import {
27
+ ChevronRightIcon,
28
+ FileIcon,
29
+ FolderIcon,
30
+ FolderOpenIcon
31
+ } from "lucide-react";
32
+ import {
33
+ createContext,
34
+ useCallback,
35
+ useContext,
36
+ useMemo,
37
+ useState
38
+ } from "react";
39
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
40
+ var noop = () => {
41
+ };
42
+ var FileTreeContext = createContext({
43
+ // oxlint-disable-next-line eslint-plugin-unicorn(no-new-builtin)
44
+ expandedPaths: /* @__PURE__ */ new Set(),
45
+ togglePath: noop
46
+ });
47
+ var FileTree = ({
48
+ expanded: controlledExpanded,
49
+ defaultExpanded = /* @__PURE__ */ new Set(),
50
+ selectedPath,
51
+ onSelect,
52
+ onExpandedChange,
53
+ className,
54
+ children,
55
+ ...props
56
+ }) => {
57
+ const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);
58
+ const expandedPaths = controlledExpanded ?? internalExpanded;
59
+ const togglePath = useCallback(
60
+ (path) => {
61
+ const newExpanded = new Set(expandedPaths);
62
+ if (newExpanded.has(path)) {
63
+ newExpanded.delete(path);
64
+ } else {
65
+ newExpanded.add(path);
66
+ }
67
+ setInternalExpanded(newExpanded);
68
+ onExpandedChange?.(newExpanded);
69
+ },
70
+ [expandedPaths, onExpandedChange]
71
+ );
72
+ const contextValue = useMemo(
73
+ () => ({ expandedPaths, onSelect, selectedPath, togglePath }),
74
+ [expandedPaths, onSelect, selectedPath, togglePath]
75
+ );
76
+ return /* @__PURE__ */ jsx2(FileTreeContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx2(
77
+ "div",
78
+ {
79
+ className: cn(
80
+ "rounded-lg border bg-background font-mono text-sm",
81
+ className
82
+ ),
83
+ role: "tree",
84
+ ...props,
85
+ children: /* @__PURE__ */ jsx2("div", { className: "p-2", children })
86
+ }
87
+ ) });
88
+ };
89
+ var FileTreeIcon = ({
90
+ className,
91
+ children,
92
+ ...props
93
+ }) => /* @__PURE__ */ jsx2("span", { className: cn("shrink-0", className), ...props, children });
94
+ var FileTreeName = ({
95
+ className,
96
+ children,
97
+ ...props
98
+ }) => /* @__PURE__ */ jsx2("span", { className: cn("truncate", className), ...props, children });
99
+ var FileTreeFolderContext = createContext({
100
+ isExpanded: false,
101
+ name: "",
102
+ path: ""
103
+ });
104
+ var FileTreeFolder = ({
105
+ path,
106
+ name,
107
+ className,
108
+ children,
109
+ ...props
110
+ }) => {
111
+ const { expandedPaths, togglePath, selectedPath, onSelect } = useContext(FileTreeContext);
112
+ const isExpanded = expandedPaths.has(path);
113
+ const isSelected = selectedPath === path;
114
+ const handleOpenChange = useCallback(() => {
115
+ togglePath(path);
116
+ }, [togglePath, path]);
117
+ const handleSelect = useCallback(() => {
118
+ onSelect?.(path);
119
+ }, [onSelect, path]);
120
+ const folderContextValue = useMemo(
121
+ () => ({ isExpanded, name, path }),
122
+ [isExpanded, name, path]
123
+ );
124
+ return /* @__PURE__ */ jsx2(FileTreeFolderContext.Provider, { value: folderContextValue, children: /* @__PURE__ */ jsx2(Collapsible, { onOpenChange: handleOpenChange, open: isExpanded, children: /* @__PURE__ */ jsxs(
125
+ "div",
126
+ {
127
+ className: cn("", className),
128
+ role: "treeitem",
129
+ tabIndex: 0,
130
+ ...props,
131
+ children: [
132
+ /* @__PURE__ */ jsxs(
133
+ "div",
134
+ {
135
+ className: cn(
136
+ "flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50",
137
+ isSelected && "bg-muted"
138
+ ),
139
+ children: [
140
+ /* @__PURE__ */ jsx2(CollapsibleTrigger, { render: /* @__PURE__ */ jsx2("button", { className: "flex shrink-0 cursor-pointer items-center border-none bg-transparent p-0", type: "button" }), children: /* @__PURE__ */ jsx2(
141
+ ChevronRightIcon,
142
+ {
143
+ className: cn(
144
+ "size-4 shrink-0 text-muted-foreground transition-transform",
145
+ isExpanded && "rotate-90"
146
+ )
147
+ }
148
+ ) }),
149
+ /* @__PURE__ */ jsxs(
150
+ "button",
151
+ {
152
+ className: "flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left",
153
+ onClick: () => {
154
+ handleSelect();
155
+ togglePath(path);
156
+ },
157
+ type: "button",
158
+ children: [
159
+ /* @__PURE__ */ jsx2(FileTreeIcon, { children: isExpanded ? /* @__PURE__ */ jsx2(FolderOpenIcon, { className: "size-4 text-blue-500" }) : /* @__PURE__ */ jsx2(FolderIcon, { className: "size-4 text-blue-500" }) }),
160
+ /* @__PURE__ */ jsx2(FileTreeName, { children: name })
161
+ ]
162
+ }
163
+ )
164
+ ]
165
+ }
166
+ ),
167
+ /* @__PURE__ */ jsx2(CollapsibleContent, { children: /* @__PURE__ */ jsx2("div", { className: "ml-4 border-l pl-2", children }) })
168
+ ]
169
+ }
170
+ ) }) });
171
+ };
172
+ var FileTreeFileContext = createContext({
173
+ name: "",
174
+ path: ""
175
+ });
176
+ var FileTreeFile = ({
177
+ path,
178
+ name,
179
+ icon,
180
+ className,
181
+ children,
182
+ ...props
183
+ }) => {
184
+ const { selectedPath, onSelect } = useContext(FileTreeContext);
185
+ const isSelected = selectedPath === path;
186
+ const handleClick = useCallback(() => {
187
+ onSelect?.(path);
188
+ }, [onSelect, path]);
189
+ const handleKeyDown = useCallback(
190
+ (e) => {
191
+ if (e.key === "Enter" || e.key === " ") {
192
+ onSelect?.(path);
193
+ }
194
+ },
195
+ [onSelect, path]
196
+ );
197
+ const fileContextValue = useMemo(() => ({ name, path }), [name, path]);
198
+ return /* @__PURE__ */ jsx2(FileTreeFileContext.Provider, { value: fileContextValue, children: /* @__PURE__ */ jsx2(
199
+ "div",
200
+ {
201
+ className: cn(
202
+ "flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50",
203
+ isSelected && "bg-muted",
204
+ className
205
+ ),
206
+ onClick: handleClick,
207
+ onKeyDown: handleKeyDown,
208
+ role: "treeitem",
209
+ tabIndex: 0,
210
+ ...props,
211
+ children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
212
+ /* @__PURE__ */ jsx2("span", { className: "size-4 shrink-0" }),
213
+ /* @__PURE__ */ jsx2(FileTreeIcon, { children: icon ?? /* @__PURE__ */ jsx2(FileIcon, { className: "size-4 text-muted-foreground" }) }),
214
+ /* @__PURE__ */ jsx2(FileTreeName, { children: name })
215
+ ] })
216
+ }
217
+ ) });
218
+ };
219
+
220
+ // src/provider/sandbox-provider.tsx
221
+ import {
222
+ createContext as createContext2,
223
+ useCallback as useCallback2,
224
+ useContext as useContext2,
225
+ useMemo as useMemo2,
226
+ useState as useState2
227
+ } from "react";
228
+ import {
229
+ SandboxRuntime
230
+ } from "@browsernode/react";
231
+ import { esbuild } from "@browsernode/esbuild-wasm";
232
+ import { nextjs } from "@browsernode/nextjs";
233
+ import { useSandbox } from "@browsernode/react";
234
+ import { jsx as jsx3 } from "react/jsx-runtime";
235
+ var ElementsContext = createContext2(null);
236
+ function useElementsContext() {
237
+ return useContext2(ElementsContext);
238
+ }
239
+
240
+ // src/primitives/ui/button.tsx
241
+ import { Button as ButtonPrimitive } from "@base-ui/react/button";
242
+ import { cva } from "class-variance-authority";
243
+ import { jsx as jsx4 } from "react/jsx-runtime";
244
+ var buttonVariants = cva(
245
+ "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
246
+ {
247
+ variants: {
248
+ variant: {
249
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
250
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
251
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
252
+ ghost: "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
253
+ destructive: "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
254
+ link: "text-primary underline-offset-4 hover:underline"
255
+ },
256
+ size: {
257
+ default: "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
258
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
259
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
260
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
261
+ icon: "size-8",
262
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
263
+ "icon-sm": "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
264
+ "icon-lg": "size-9"
265
+ }
266
+ },
267
+ defaultVariants: {
268
+ variant: "default",
269
+ size: "default"
270
+ }
271
+ }
272
+ );
273
+ function Button({
274
+ className,
275
+ variant = "default",
276
+ size = "default",
277
+ ...props
278
+ }) {
279
+ return /* @__PURE__ */ jsx4(
280
+ ButtonPrimitive,
281
+ {
282
+ "data-slot": "button",
283
+ className: cn(buttonVariants({ variant, size, className })),
284
+ ...props
285
+ }
286
+ );
287
+ }
288
+
289
+ // src/primitives/ui/popover.tsx
290
+ import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
291
+ import { jsx as jsx5 } from "react/jsx-runtime";
292
+ function Popover({ ...props }) {
293
+ return /* @__PURE__ */ jsx5(PopoverPrimitive.Root, { "data-slot": "popover", ...props });
294
+ }
295
+ function PopoverTrigger({ ...props }) {
296
+ return /* @__PURE__ */ jsx5(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
297
+ }
298
+ function PopoverContent({
299
+ className,
300
+ align = "center",
301
+ alignOffset = 0,
302
+ side = "bottom",
303
+ sideOffset = 4,
304
+ ...props
305
+ }) {
306
+ return /* @__PURE__ */ jsx5(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx5(
307
+ PopoverPrimitive.Positioner,
308
+ {
309
+ align,
310
+ alignOffset,
311
+ side,
312
+ sideOffset,
313
+ className: "isolate z-50",
314
+ children: /* @__PURE__ */ jsx5(
315
+ PopoverPrimitive.Popup,
316
+ {
317
+ "data-slot": "popover-content",
318
+ className: cn(
319
+ "z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
320
+ className
321
+ ),
322
+ ...props
323
+ }
324
+ )
325
+ }
326
+ ) });
327
+ }
328
+
329
+ // src/editor/internal/tree.tsx
330
+ import { jsx as jsx6 } from "react/jsx-runtime";
331
+ function buildTree(paths) {
332
+ const root = { name: "", path: "", children: /* @__PURE__ */ new Map() };
333
+ for (const path of paths) {
334
+ const parts = path.split("/").filter(Boolean);
335
+ let cur = root;
336
+ for (let i = 0; i < parts.length; i++) {
337
+ const name = parts[i];
338
+ const isLeaf = i === parts.length - 1;
339
+ const childPath = "/" + parts.slice(0, i + 1).join("/");
340
+ if (!cur.children) break;
341
+ let child = cur.children.get(name);
342
+ if (!child) {
343
+ child = { name, path: childPath, children: isLeaf ? null : /* @__PURE__ */ new Map() };
344
+ cur.children.set(name, child);
345
+ }
346
+ if (!isLeaf && child.children) cur = child;
347
+ else if (!isLeaf && !child.children) break;
348
+ }
349
+ }
350
+ return root;
351
+ }
352
+ function renderTree(node) {
353
+ if (!node.children) return null;
354
+ const entries = Array.from(node.children.values()).sort((a, b) => {
355
+ const aFolder = a.children !== null;
356
+ const bFolder = b.children !== null;
357
+ if (aFolder !== bFolder) return aFolder ? -1 : 1;
358
+ return a.name.localeCompare(b.name);
359
+ });
360
+ return entries.map(
361
+ (entry) => entry.children ? /* @__PURE__ */ jsx6(FileTreeFolder, { name: entry.name, path: entry.path, children: renderTree(entry) }, entry.path) : /* @__PURE__ */ jsx6(FileTreeFile, { name: entry.name, path: entry.path }, entry.path)
362
+ );
363
+ }
364
+ function isFile(path, files) {
365
+ return files.includes(path);
366
+ }
367
+ function defaultExpansion(files) {
368
+ const roots = ["src", "app", "pages", "components"];
369
+ const expanded = /* @__PURE__ */ new Set();
370
+ for (const root of roots) {
371
+ const abs = "/" + root;
372
+ if (files.some((f) => f === abs || f.startsWith(`${abs}/`))) {
373
+ expanded.add(abs);
374
+ }
375
+ }
376
+ return expanded;
377
+ }
378
+
379
+ // src/editor/sandbox-file-tree.tsx
380
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
381
+ function SandboxFileTree({
382
+ sandbox: sandboxProp,
383
+ defaultExpanded,
384
+ onSelect,
385
+ display = "tree",
386
+ triggerLabel,
387
+ className
388
+ }) {
389
+ const elementsCtx = useElementsContext();
390
+ const sandboxState = useSandbox();
391
+ const sandbox = sandboxProp ?? sandboxState.sandbox;
392
+ const [files, setFiles] = useState3(
393
+ () => sandbox ? sandbox.fs.list() : []
394
+ );
395
+ const [open, setOpen] = useState3(false);
396
+ const selectedPath = elementsCtx?.selectedPath ?? null;
397
+ const setSelectedPath = elementsCtx?.setSelectedPath;
398
+ useEffect(() => {
399
+ if (!sandbox) return;
400
+ setFiles(sandbox.fs.list());
401
+ return sandbox.fs.on("change", () => setFiles(sandbox.fs.list()));
402
+ }, [sandbox]);
403
+ const tree = useMemo3(() => buildTree(files), [files]);
404
+ const handleSelect = (path) => {
405
+ if (!isFile(path, files)) return;
406
+ setSelectedPath?.(path);
407
+ onSelect?.(path);
408
+ if (display === "dropdown") setOpen(false);
409
+ };
410
+ const treeNode = /* @__PURE__ */ jsx7(
411
+ FileTree,
412
+ {
413
+ defaultExpanded: defaultExpanded ?? defaultExpansion(files),
414
+ onSelect: handleSelect,
415
+ selectedPath: selectedPath ?? void 0,
416
+ className: `h-full w-full overflow-auto rounded-none border-0 bg-transparent ${className ?? ""}`.trim(),
417
+ children: renderTree(tree)
418
+ }
419
+ );
420
+ if (display === "dropdown") {
421
+ const defaultLabel = selectedPath ? /* @__PURE__ */ jsx7(MenuIcon, { className: "size-4" }) : /* @__PURE__ */ jsxs2(Fragment2, { children: [
422
+ /* @__PURE__ */ jsx7(MenuIcon, { className: "size-4" }),
423
+ /* @__PURE__ */ jsx7("span", { children: "Select a file" })
424
+ ] });
425
+ return /* @__PURE__ */ jsxs2(Popover, { open, onOpenChange: setOpen, children: [
426
+ /* @__PURE__ */ jsx7(
427
+ PopoverTrigger,
428
+ {
429
+ render: /* @__PURE__ */ jsx7(
430
+ Button,
431
+ {
432
+ size: "sm",
433
+ variant: "ghost",
434
+ "aria-label": "Select file",
435
+ className: `h-8 gap-2 px-2 text-xs font-normal ${className ?? ""}`.trim()
436
+ }
437
+ ),
438
+ children: triggerLabel ?? defaultLabel
439
+ }
440
+ ),
441
+ /* @__PURE__ */ jsx7(
442
+ PopoverContent,
443
+ {
444
+ align: "start",
445
+ className: "w-72 p-0 max-h-[26rem] flex flex-col overflow-hidden",
446
+ children: treeNode
447
+ }
448
+ )
449
+ ] });
450
+ }
451
+ return treeNode;
452
+ }
453
+
454
+ // src/editor/sandbox-code-editor.tsx
455
+ import {
456
+ useCallback as useCallback3,
457
+ useEffect as useEffect2,
458
+ useMemo as useMemo5,
459
+ useRef,
460
+ useState as useState4
461
+ } from "react";
462
+ import { MoreHorizontalIcon } from "lucide-react";
463
+ import { keymap } from "@codemirror/view";
464
+
465
+ // src/editor/primitives/code-editor.tsx
466
+ import { useMemo as useMemo4 } from "react";
467
+ import CodeMirror, {
468
+ EditorView
469
+ } from "@uiw/react-codemirror";
470
+ import { javascript } from "@codemirror/lang-javascript";
471
+ import { css } from "@codemirror/lang-css";
472
+ import { html } from "@codemirror/lang-html";
473
+ import { json } from "@codemirror/lang-json";
474
+ import { markdown } from "@codemirror/lang-markdown";
475
+ import { jsx as jsx8 } from "react/jsx-runtime";
476
+ function CodeEditor({
477
+ value,
478
+ onChange,
479
+ language = "plaintext",
480
+ theme,
481
+ extensions: extraExtensions,
482
+ className,
483
+ basicSetup,
484
+ ...rest
485
+ }) {
486
+ const ctx = useElementsContext();
487
+ const resolvedTheme = theme ?? ctx?.theme ?? "light";
488
+ const extensions = useMemo4(() => {
489
+ const langExt = languageExtension(language);
490
+ const wrap = EditorView.lineWrapping;
491
+ const base = [wrap];
492
+ if (langExt) base.push(langExt);
493
+ return extraExtensions ? [...base, ...extraExtensions] : base;
494
+ }, [language, extraExtensions]);
495
+ return /* @__PURE__ */ jsx8(
496
+ CodeMirror,
497
+ {
498
+ value,
499
+ onChange,
500
+ extensions,
501
+ theme: resolvedTheme,
502
+ basicSetup: basicSetup ?? {
503
+ lineNumbers: true,
504
+ highlightActiveLine: true,
505
+ highlightActiveLineGutter: true,
506
+ foldGutter: true,
507
+ autocompletion: true,
508
+ bracketMatching: true,
509
+ closeBrackets: true,
510
+ indentOnInput: true,
511
+ searchKeymap: true
512
+ },
513
+ className,
514
+ ...rest
515
+ }
516
+ );
517
+ }
518
+ function languageExtension(lang) {
519
+ switch (lang) {
520
+ case "typescript":
521
+ return javascript({ typescript: true });
522
+ case "tsx":
523
+ return javascript({ typescript: true, jsx: true });
524
+ case "javascript":
525
+ return javascript();
526
+ case "jsx":
527
+ return javascript({ jsx: true });
528
+ case "css":
529
+ return css();
530
+ case "html":
531
+ return html();
532
+ case "json":
533
+ return json();
534
+ case "markdown":
535
+ return markdown();
536
+ case "plaintext":
537
+ default:
538
+ return null;
539
+ }
540
+ }
541
+
542
+ // src/primitives/ui/dropdown-menu.tsx
543
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu";
544
+ import { ChevronRightIcon as ChevronRightIcon2, CheckIcon } from "lucide-react";
545
+ import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
546
+ function DropdownMenu({ ...props }) {
547
+ return /* @__PURE__ */ jsx9(MenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
548
+ }
549
+ function DropdownMenuTrigger({ ...props }) {
550
+ return /* @__PURE__ */ jsx9(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
551
+ }
552
+ function DropdownMenuContent({
553
+ align = "start",
554
+ alignOffset = 0,
555
+ side = "bottom",
556
+ sideOffset = 4,
557
+ className,
558
+ ...props
559
+ }) {
560
+ return /* @__PURE__ */ jsx9(MenuPrimitive.Portal, { children: /* @__PURE__ */ jsx9(
561
+ MenuPrimitive.Positioner,
562
+ {
563
+ className: "isolate z-50 outline-none",
564
+ align,
565
+ alignOffset,
566
+ side,
567
+ sideOffset,
568
+ children: /* @__PURE__ */ jsx9(
569
+ MenuPrimitive.Popup,
570
+ {
571
+ "data-slot": "dropdown-menu-content",
572
+ className: cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", className),
573
+ ...props
574
+ }
575
+ )
576
+ }
577
+ ) });
578
+ }
579
+ function DropdownMenuItem({
580
+ className,
581
+ inset,
582
+ variant = "default",
583
+ ...props
584
+ }) {
585
+ return /* @__PURE__ */ jsx9(
586
+ MenuPrimitive.Item,
587
+ {
588
+ "data-slot": "dropdown-menu-item",
589
+ "data-inset": inset,
590
+ "data-variant": variant,
591
+ className: cn(
592
+ "group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:*:[svg]:text-destructive",
593
+ className
594
+ ),
595
+ ...props
596
+ }
597
+ );
598
+ }
599
+
600
+ // src/primitives/ui/loading.tsx
601
+ import { jsx as jsx10, jsxs as jsxs4 } from "react/jsx-runtime";
602
+ var LoaderIcon = ({ size = 16 }) => /* @__PURE__ */ jsxs4(
603
+ "svg",
604
+ {
605
+ height: size,
606
+ strokeLinejoin: "round",
607
+ style: { color: "currentcolor" },
608
+ viewBox: "0 0 16 16",
609
+ width: size,
610
+ children: [
611
+ /* @__PURE__ */ jsx10("title", { children: "Loader" }),
612
+ /* @__PURE__ */ jsxs4("g", { clipPath: "url(#clip0_2393_1490)", children: [
613
+ /* @__PURE__ */ jsx10("path", { d: "M8 0V4", stroke: "currentColor", strokeWidth: "1.5" }),
614
+ /* @__PURE__ */ jsx10(
615
+ "path",
616
+ {
617
+ d: "M8 16V12",
618
+ opacity: "0.5",
619
+ stroke: "currentColor",
620
+ strokeWidth: "1.5"
621
+ }
622
+ ),
623
+ /* @__PURE__ */ jsx10(
624
+ "path",
625
+ {
626
+ d: "M3.29773 1.52783L5.64887 4.7639",
627
+ opacity: "0.9",
628
+ stroke: "currentColor",
629
+ strokeWidth: "1.5"
630
+ }
631
+ ),
632
+ /* @__PURE__ */ jsx10(
633
+ "path",
634
+ {
635
+ d: "M12.7023 1.52783L10.3511 4.7639",
636
+ opacity: "0.1",
637
+ stroke: "currentColor",
638
+ strokeWidth: "1.5"
639
+ }
640
+ ),
641
+ /* @__PURE__ */ jsx10(
642
+ "path",
643
+ {
644
+ d: "M12.7023 14.472L10.3511 11.236",
645
+ opacity: "0.4",
646
+ stroke: "currentColor",
647
+ strokeWidth: "1.5"
648
+ }
649
+ ),
650
+ /* @__PURE__ */ jsx10(
651
+ "path",
652
+ {
653
+ d: "M3.29773 14.472L5.64887 11.236",
654
+ opacity: "0.6",
655
+ stroke: "currentColor",
656
+ strokeWidth: "1.5"
657
+ }
658
+ ),
659
+ /* @__PURE__ */ jsx10(
660
+ "path",
661
+ {
662
+ d: "M15.6085 5.52783L11.8043 6.7639",
663
+ opacity: "0.2",
664
+ stroke: "currentColor",
665
+ strokeWidth: "1.5"
666
+ }
667
+ ),
668
+ /* @__PURE__ */ jsx10(
669
+ "path",
670
+ {
671
+ d: "M0.391602 10.472L4.19583 9.23598",
672
+ opacity: "0.7",
673
+ stroke: "currentColor",
674
+ strokeWidth: "1.5"
675
+ }
676
+ ),
677
+ /* @__PURE__ */ jsx10(
678
+ "path",
679
+ {
680
+ d: "M15.6085 10.4722L11.8043 9.2361",
681
+ opacity: "0.3",
682
+ stroke: "currentColor",
683
+ strokeWidth: "1.5"
684
+ }
685
+ ),
686
+ /* @__PURE__ */ jsx10(
687
+ "path",
688
+ {
689
+ d: "M0.391602 5.52783L4.19583 6.7639",
690
+ opacity: "0.8",
691
+ stroke: "currentColor",
692
+ strokeWidth: "1.5"
693
+ }
694
+ )
695
+ ] }),
696
+ /* @__PURE__ */ jsx10("defs", { children: /* @__PURE__ */ jsx10("clipPath", { id: "clip0_2393_1490", children: /* @__PURE__ */ jsx10("rect", { fill: "white", height: "16", width: "16" }) }) })
697
+ ]
698
+ }
699
+ );
700
+ var Loader = ({ className, size = 16, ...props }) => /* @__PURE__ */ jsx10(
701
+ "div",
702
+ {
703
+ className: cn(
704
+ "inline-flex animate-spin items-center justify-center",
705
+ className
706
+ ),
707
+ ...props,
708
+ children: /* @__PURE__ */ jsx10(LoaderIcon, { size })
709
+ }
710
+ );
711
+
712
+ // src/editor/internal/language.ts
713
+ var EXT_TO_LANG = {
714
+ ts: "typescript",
715
+ tsx: "tsx",
716
+ js: "javascript",
717
+ jsx: "jsx",
718
+ mjs: "javascript",
719
+ cjs: "javascript",
720
+ json: "json",
721
+ md: "markdown",
722
+ mdx: "markdown",
723
+ css: "css",
724
+ scss: "css",
725
+ html: "html",
726
+ htm: "html"
727
+ };
728
+ function guessLanguage(path) {
729
+ const m = path.match(/\.([^.]+)$/);
730
+ if (!m) return "plaintext";
731
+ const ext = m[1].toLowerCase();
732
+ return EXT_TO_LANG[ext] ?? "plaintext";
733
+ }
734
+
735
+ // src/editor/sandbox-code-editor.tsx
736
+ import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
737
+ function SandboxCodeEditor({
738
+ sandbox: sandboxProp,
739
+ readOnly = false,
740
+ theme,
741
+ basicSetup,
742
+ extensions,
743
+ language: languageProp,
744
+ hideHeader = false,
745
+ emptyState,
746
+ headerStartSlot,
747
+ className
748
+ }) {
749
+ const elementsCtx = useElementsContext();
750
+ const sandboxState = useSandbox();
751
+ const sandbox = sandboxProp ?? sandboxState.sandbox;
752
+ const selectedPath = elementsCtx?.selectedPath ?? null;
753
+ const setSelectedPath = elementsCtx?.setSelectedPath;
754
+ const [savedText, setSavedText] = useState4(null);
755
+ const [buffer, setBuffer] = useState4("");
756
+ const [loadingPath, setLoadingPath] = useState4(null);
757
+ const [saveStatus, setSaveStatus] = useState4("idle");
758
+ const loadedPathRef = useRef(null);
759
+ const savedTimerRef = useRef(null);
760
+ const sandboxRef = useRef(sandbox);
761
+ const selectedPathRef = useRef(selectedPath);
762
+ const bufferRef = useRef(buffer);
763
+ const dirtyRef = useRef(false);
764
+ sandboxRef.current = sandbox;
765
+ selectedPathRef.current = selectedPath;
766
+ bufferRef.current = buffer;
767
+ useEffect2(() => {
768
+ if (!sandbox || !selectedPath) {
769
+ setSavedText(null);
770
+ setBuffer("");
771
+ loadedPathRef.current = null;
772
+ return;
773
+ }
774
+ setLoadingPath(selectedPath);
775
+ setSaveStatus("idle");
776
+ let cancelled = false;
777
+ sandbox.fs.readFile(selectedPath).then((c) => {
778
+ if (cancelled) return;
779
+ setSavedText(c);
780
+ setBuffer(c);
781
+ loadedPathRef.current = selectedPath;
782
+ setLoadingPath(null);
783
+ }).catch(() => {
784
+ if (cancelled) return;
785
+ const fallback = `// Could not read ${selectedPath}`;
786
+ setSavedText(fallback);
787
+ setBuffer(fallback);
788
+ loadedPathRef.current = null;
789
+ setLoadingPath(null);
790
+ });
791
+ return () => {
792
+ cancelled = true;
793
+ };
794
+ }, [sandbox, selectedPath]);
795
+ useEffect2(() => {
796
+ return () => {
797
+ if (savedTimerRef.current) {
798
+ clearTimeout(savedTimerRef.current);
799
+ savedTimerRef.current = null;
800
+ }
801
+ };
802
+ }, [selectedPath]);
803
+ const handleEditorChange = useCallback3(
804
+ (next) => {
805
+ setBuffer(next);
806
+ if (readOnly) return;
807
+ if (!selectedPath) return;
808
+ if (loadedPathRef.current !== selectedPath) return;
809
+ },
810
+ [readOnly, selectedPath]
811
+ );
812
+ const dirty = !readOnly && savedText !== null && buffer !== savedText;
813
+ dirtyRef.current = dirty;
814
+ const deleteFile = useCallback3(async () => {
815
+ if (readOnly) return;
816
+ const sb = sandboxRef.current;
817
+ const path = selectedPathRef.current;
818
+ if (!sb || !path) return;
819
+ try {
820
+ await sb.fs.rm(path);
821
+ setSelectedPath?.(null);
822
+ } catch {
823
+ }
824
+ }, [readOnly, setSelectedPath]);
825
+ const save = useCallback3(async () => {
826
+ if (readOnly) return;
827
+ const sb = sandboxRef.current;
828
+ const path = selectedPathRef.current;
829
+ const text = bufferRef.current;
830
+ if (!sb || !path) return;
831
+ if (!dirtyRef.current) return;
832
+ setSaveStatus("saving");
833
+ try {
834
+ await sb.fs.writeFile(path, text);
835
+ await new Promise((r) => setTimeout(r, 500));
836
+ setSavedText(text);
837
+ setSaveStatus("idle");
838
+ } catch {
839
+ setSaveStatus("error");
840
+ }
841
+ }, [readOnly]);
842
+ const editorExtensions = useMemo5(
843
+ () => {
844
+ const base = [
845
+ keymap.of([
846
+ {
847
+ key: "Mod-s",
848
+ preventDefault: true,
849
+ run: () => {
850
+ void save();
851
+ return true;
852
+ }
853
+ }
854
+ ])
855
+ ];
856
+ return extensions ? [...base, ...extensions] : base;
857
+ },
858
+ [save, extensions]
859
+ );
860
+ const lang = languageProp ? languageProp : selectedPath ? guessLanguage(selectedPath) : "plaintext";
861
+ const filename = selectedPath ? selectedPath.split("/").filter(Boolean).pop() ?? selectedPath : null;
862
+ const headerLabel = selectedPath ? /* @__PURE__ */ jsx11("span", { className: "font-mono", title: selectedPath, children: filename }) : headerStartSlot ? null : /* @__PURE__ */ jsx11("span", { children: "Select a file" });
863
+ return /* @__PURE__ */ jsxs5("div", { className: `flex h-full w-full flex-col ${className ?? ""}`.trim(), children: [
864
+ !hideHeader && /* @__PURE__ */ jsxs5("div", { className: "flex flex-none items-center justify-between border-b px-3 py-2 text-xs", children: [
865
+ /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1.5 text-muted-foreground", children: [
866
+ headerStartSlot,
867
+ headerLabel
868
+ ] }),
869
+ selectedPath && !readOnly && /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-1", children: [
870
+ /* @__PURE__ */ jsx11(
871
+ Button,
872
+ {
873
+ size: "sm",
874
+ onClick: () => void save(),
875
+ className: "h-9 px-4 text-sm md:h-8 md:px-3 md:text-xs",
876
+ children: saveStatus === "saving" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
877
+ /* @__PURE__ */ jsx11(Loader, { size: 14 }),
878
+ "Saving..."
879
+ ] }) : "Save"
880
+ }
881
+ ),
882
+ /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
883
+ /* @__PURE__ */ jsx11(
884
+ DropdownMenuTrigger,
885
+ {
886
+ render: /* @__PURE__ */ jsx11(
887
+ Button,
888
+ {
889
+ size: "sm",
890
+ variant: "ghost",
891
+ "aria-label": "File actions",
892
+ className: "size-10 p-0 md:size-8"
893
+ }
894
+ ),
895
+ children: /* @__PURE__ */ jsx11(MoreHorizontalIcon, { className: "size-4" })
896
+ }
897
+ ),
898
+ /* @__PURE__ */ jsx11(DropdownMenuContent, { align: "end", children: /* @__PURE__ */ jsx11(
899
+ DropdownMenuItem,
900
+ {
901
+ onClick: () => void deleteFile(),
902
+ className: "text-destructive focus:text-destructive",
903
+ children: "Delete"
904
+ }
905
+ ) })
906
+ ] })
907
+ ] })
908
+ ] }),
909
+ /* @__PURE__ */ jsx11("div", { className: "flex-1 min-h-0 overflow-auto", children: selectedPath ? /* @__PURE__ */ jsx11(
910
+ CodeEditor,
911
+ {
912
+ value: buffer,
913
+ onChange: handleEditorChange,
914
+ language: lang,
915
+ theme,
916
+ basicSetup,
917
+ readOnly: readOnly || loadingPath === selectedPath,
918
+ extensions: editorExtensions,
919
+ height: "100%",
920
+ className: "h-full text-sm"
921
+ },
922
+ selectedPath
923
+ ) : emptyState ?? /* @__PURE__ */ jsx11("div", { className: "flex h-full w-full items-center justify-center text-muted-foreground text-sm", children: "Select a file from the menu" }) })
924
+ ] });
925
+ }
926
+
927
+ // src/editor/sandbox-ide.tsx
928
+ import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
929
+ function SandboxIDE({
930
+ sandbox,
931
+ defaultExpanded,
932
+ hideTree = false,
933
+ hideViewer = false,
934
+ hideBorder = false,
935
+ className,
936
+ style,
937
+ ...codeProps
938
+ }) {
939
+ if (hideViewer) {
940
+ return /* @__PURE__ */ jsx12(
941
+ SandboxFileTree,
942
+ {
943
+ sandbox,
944
+ defaultExpanded,
945
+ className
946
+ }
947
+ );
948
+ }
949
+ if (hideTree) {
950
+ return /* @__PURE__ */ jsx12(
951
+ SandboxCodeEditor,
952
+ {
953
+ sandbox,
954
+ className,
955
+ ...codeProps
956
+ }
957
+ );
958
+ }
959
+ const frameClasses = hideBorder ? "flex h-full w-full flex-col md:flex-row overflow-hidden bg-background" : "flex h-full w-full flex-col md:flex-row overflow-hidden rounded-lg border bg-background";
960
+ const mobileTrigger = /* @__PURE__ */ jsx12(
961
+ SandboxFileTree,
962
+ {
963
+ sandbox,
964
+ defaultExpanded,
965
+ display: "dropdown",
966
+ className: "md:hidden -ml-1"
967
+ }
968
+ );
969
+ return /* @__PURE__ */ jsxs6("div", { className: `${frameClasses} ${className ?? ""}`.trim(), style, children: [
970
+ /* @__PURE__ */ jsx12("div", { className: "hidden md:block w-64 shrink-0 overflow-auto border-r", children: /* @__PURE__ */ jsx12(SandboxFileTree, { sandbox, defaultExpanded }) }),
971
+ /* @__PURE__ */ jsx12("div", { className: "flex-1 min-w-0 overflow-hidden", children: /* @__PURE__ */ jsx12(
972
+ SandboxCodeEditor,
973
+ {
974
+ sandbox,
975
+ headerStartSlot: mobileTrigger,
976
+ ...codeProps
977
+ }
978
+ ) })
979
+ ] });
980
+ }
981
+ export {
982
+ CodeEditor,
983
+ FileTree,
984
+ FileTreeFile,
985
+ FileTreeFolder,
986
+ SandboxCodeEditor,
987
+ SandboxFileTree,
988
+ SandboxIDE
989
+ };
990
+ //# sourceMappingURL=editor.js.map