@browsernode/elements 0.0.1 → 0.0.2
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/dist/editor.js
CHANGED
|
@@ -230,6 +230,7 @@ import {
|
|
|
230
230
|
} from "@browsernode/react";
|
|
231
231
|
import { esbuild } from "@browsernode/esbuild-wasm";
|
|
232
232
|
import { nextjs } from "@browsernode/nextjs";
|
|
233
|
+
import { vite } from "@browsernode/sandbox/vite";
|
|
233
234
|
import { useSandbox } from "@browsernode/react";
|
|
234
235
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
235
236
|
var ElementsContext = createContext2(null);
|
package/dist/editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/editor/sandbox-file-tree.tsx","../src/primitives/ui/collapsible.tsx","../src/primitives/lib/utils.ts","../src/editor/primitives/file-tree.tsx","../src/provider/sandbox-provider.tsx","../src/primitives/ui/button.tsx","../src/primitives/ui/popover.tsx","../src/editor/internal/tree.tsx","../src/editor/sandbox-code-editor.tsx","../src/editor/primitives/code-editor.tsx","../src/primitives/ui/dropdown-menu.tsx","../src/primitives/ui/loading.tsx","../src/editor/internal/language.ts","../src/editor/sandbox-ide.tsx"],"sourcesContent":["// `<SandboxFileTree>` — file tree only. Reads `selectedPath` /\n// `setSelectedPath` from `useElementsContext`. Subscribes to\n// `sandbox.fs` change events so the tree mirrors mutations.\n//\n// `display=\"dropdown\"` collapses the tree behind a folder-icon\n// `<Popover>` trigger — useful for mobile / narrow side panels.\n\nimport { useEffect, useMemo, useState, type ReactNode } from 'react';\nimport { MenuIcon } from 'lucide-react';\nimport type { Sandbox } from '@browsernode/sandbox';\nimport { FileTree } from './primitives/file-tree';\nimport { useElementsContext, useSandbox } from '../provider/sandbox-provider';\nimport { Button } from '../primitives/ui/button';\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '../primitives/ui/popover';\nimport {\n buildTree,\n defaultExpansion,\n isFile,\n renderTree,\n} from './internal/tree';\n\nexport interface SandboxFileTreeProps {\n /** Override the sandbox from the surrounding `<SandboxProvider>`. */\n sandbox?: Sandbox | null;\n /** Initial folders to expand. Defaults to common roots when present. */\n defaultExpanded?: Set<string>;\n /**\n * Called when a file is selected. Fires *in addition* to updating the\n * elements context's `selectedPath`.\n */\n onSelect?: (path: string) => void;\n /**\n * Render mode:\n * • `\"tree\"` (default) — full inline tree, expects a parent that\n * gives it height to scroll within\n * • `\"dropdown\"` — folder-icon button that opens a popover with the\n * tree inside; selecting a file closes the popover\n */\n display?: 'tree' | 'dropdown';\n /**\n * Trigger contents (dropdown variant). Defaults to a hamburger icon\n * + \"Select file\" label.\n */\n triggerLabel?: ReactNode;\n className?: string;\n}\n\nexport function SandboxFileTree({\n sandbox: sandboxProp,\n defaultExpanded,\n onSelect,\n display = 'tree',\n triggerLabel,\n className,\n}: SandboxFileTreeProps) {\n const elementsCtx = useElementsContext();\n const sandboxState = useSandbox();\n const sandbox = sandboxProp ?? sandboxState.sandbox;\n\n const [files, setFiles] = useState<string[]>(() =>\n sandbox ? sandbox.fs.list() : [],\n );\n const [open, setOpen] = useState(false);\n\n const selectedPath = elementsCtx?.selectedPath ?? null;\n const setSelectedPath = elementsCtx?.setSelectedPath;\n\n useEffect(() => {\n if (!sandbox) return;\n setFiles(sandbox.fs.list());\n return sandbox.fs.on('change', () => setFiles(sandbox.fs.list()));\n }, [sandbox]);\n\n const tree = useMemo(() => buildTree(files), [files]);\n\n const handleSelect = (path: string) => {\n if (!isFile(path, files)) return;\n setSelectedPath?.(path);\n onSelect?.(path);\n if (display === 'dropdown') setOpen(false);\n };\n\n const treeNode = (\n <FileTree\n defaultExpanded={defaultExpanded ?? defaultExpansion(files)}\n onSelect={handleSelect}\n selectedPath={selectedPath ?? undefined}\n className={`h-full w-full overflow-auto rounded-none border-0 bg-transparent ${className ?? ''}`.trim()}\n >\n {renderTree(tree)}\n </FileTree>\n );\n\n if (display === 'dropdown') {\n // Default trigger contents adapt to selection state: with no file\n // selected, the button reads \"[☰] Select a file\" so the empty\n // state has a single self-explanatory affordance. Once a file is\n // selected, the button collapses to the icon only — the surrounding\n // header (or whatever the consumer composes) is responsible for\n // showing the filename next to it.\n const defaultLabel = selectedPath ? (\n <MenuIcon className=\"size-4\" />\n ) : (\n <>\n <MenuIcon className=\"size-4\" />\n <span>Select a file</span>\n </>\n );\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label=\"Select file\"\n className={`h-8 gap-2 px-2 text-xs font-normal ${className ?? ''}`.trim()}\n />\n }\n >\n {triggerLabel ?? defaultLabel}\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"w-72 p-0 max-h-[26rem] flex flex-col overflow-hidden\"\n >\n {treeNode}\n </PopoverContent>\n </Popover>\n );\n }\n\n return treeNode;\n}\n","\"use client\"\n\nimport { Collapsible as CollapsiblePrimitive } from \"@base-ui/react/collapsible\"\n\nfunction Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {\n return <CollapsiblePrimitive.Root data-slot=\"collapsible\" {...props} />\n}\n\nfunction CollapsibleTrigger({ ...props }: CollapsiblePrimitive.Trigger.Props) {\n return (\n <CollapsiblePrimitive.Trigger data-slot=\"collapsible-trigger\" {...props} />\n )\n}\n\nfunction CollapsibleContent({ ...props }: CollapsiblePrimitive.Panel.Props) {\n return (\n <CollapsiblePrimitive.Panel data-slot=\"collapsible-content\" {...props} />\n )\n}\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent }\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","\"use client\";\n\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"../../primitives/ui/collapsible\";\nimport { cn } from \"../../primitives/lib/utils\";\nimport {\n ChevronRightIcon,\n FileIcon,\n FolderIcon,\n FolderOpenIcon,\n} from \"lucide-react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from \"react\";\n\ninterface FileTreeContextType {\n expandedPaths: Set<string>;\n togglePath: (path: string) => void;\n selectedPath?: string;\n onSelect?: (path: string) => void;\n}\n\n// Default noop for context default value\n// oxlint-disable-next-line eslint(no-empty-function)\nconst noop = () => {};\n\nconst FileTreeContext = createContext<FileTreeContextType>({\n // oxlint-disable-next-line eslint-plugin-unicorn(no-new-builtin)\n expandedPaths: new Set(),\n togglePath: noop,\n});\n\nexport type FileTreeProps = Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> & {\n expanded?: Set<string>;\n defaultExpanded?: Set<string>;\n selectedPath?: string;\n onSelect?: (path: string) => void;\n onExpandedChange?: (expanded: Set<string>) => void;\n};\n\nexport const FileTree = ({\n expanded: controlledExpanded,\n defaultExpanded = new Set(),\n selectedPath,\n onSelect,\n onExpandedChange,\n className,\n children,\n ...props\n}: FileTreeProps) => {\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n const expandedPaths = controlledExpanded ?? internalExpanded;\n\n const togglePath = useCallback(\n (path: string) => {\n const newExpanded = new Set(expandedPaths);\n if (newExpanded.has(path)) {\n newExpanded.delete(path);\n } else {\n newExpanded.add(path);\n }\n setInternalExpanded(newExpanded);\n onExpandedChange?.(newExpanded);\n },\n [expandedPaths, onExpandedChange]\n );\n\n const contextValue = useMemo(\n () => ({ expandedPaths, onSelect, selectedPath, togglePath }),\n [expandedPaths, onSelect, selectedPath, togglePath]\n );\n\n return (\n <FileTreeContext.Provider value={contextValue}>\n <div\n className={cn(\n \"rounded-lg border bg-background font-mono text-sm\",\n className\n )}\n role=\"tree\"\n {...props}\n >\n <div className=\"p-2\">{children}</div>\n </div>\n </FileTreeContext.Provider>\n );\n};\n\nexport type FileTreeIconProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const FileTreeIcon = ({\n className,\n children,\n ...props\n}: FileTreeIconProps) => (\n <span className={cn(\"shrink-0\", className)} {...props}>\n {children}\n </span>\n);\n\nexport type FileTreeNameProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const FileTreeName = ({\n className,\n children,\n ...props\n}: FileTreeNameProps) => (\n <span className={cn(\"truncate\", className)} {...props}>\n {children}\n </span>\n);\n\ninterface FileTreeFolderContextType {\n path: string;\n name: string;\n isExpanded: boolean;\n}\n\nconst FileTreeFolderContext = createContext<FileTreeFolderContextType>({\n isExpanded: false,\n name: \"\",\n path: \"\",\n});\n\nexport type FileTreeFolderProps = HTMLAttributes<HTMLDivElement> & {\n path: string;\n name: string;\n};\n\nexport const FileTreeFolder = ({\n path,\n name,\n className,\n children,\n ...props\n}: FileTreeFolderProps) => {\n const { expandedPaths, togglePath, selectedPath, onSelect } =\n useContext(FileTreeContext);\n const isExpanded = expandedPaths.has(path);\n const isSelected = selectedPath === path;\n\n const handleOpenChange = useCallback(() => {\n togglePath(path);\n }, [togglePath, path]);\n\n const handleSelect = useCallback(() => {\n onSelect?.(path);\n }, [onSelect, path]);\n\n const folderContextValue = useMemo(\n () => ({ isExpanded, name, path }),\n [isExpanded, name, path]\n );\n\n return (\n <FileTreeFolderContext.Provider value={folderContextValue}>\n <Collapsible onOpenChange={handleOpenChange} open={isExpanded}>\n <div\n className={cn(\"\", className)}\n role=\"treeitem\"\n tabIndex={0}\n {...props}\n >\n <div\n className={cn(\n \"flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50\",\n isSelected && \"bg-muted\"\n )}\n >\n <CollapsibleTrigger render={<button className=\"flex shrink-0 cursor-pointer items-center border-none bg-transparent p-0\" type=\"button\" />}><ChevronRightIcon\n className={cn(\n \"size-4 shrink-0 text-muted-foreground transition-transform\",\n isExpanded && \"rotate-90\"\n )}\n /></CollapsibleTrigger>\n <button\n className=\"flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left\"\n onClick={() => {\n handleSelect();\n togglePath(path);\n }}\n type=\"button\"\n >\n <FileTreeIcon>\n {isExpanded ? (\n <FolderOpenIcon className=\"size-4 text-blue-500\" />\n ) : (\n <FolderIcon className=\"size-4 text-blue-500\" />\n )}\n </FileTreeIcon>\n <FileTreeName>{name}</FileTreeName>\n </button>\n </div>\n <CollapsibleContent>\n <div className=\"ml-4 border-l pl-2\">{children}</div>\n </CollapsibleContent>\n </div>\n </Collapsible>\n </FileTreeFolderContext.Provider>\n );\n};\n\ninterface FileTreeFileContextType {\n path: string;\n name: string;\n}\n\nconst FileTreeFileContext = createContext<FileTreeFileContextType>({\n name: \"\",\n path: \"\",\n});\n\nexport type FileTreeFileProps = HTMLAttributes<HTMLDivElement> & {\n path: string;\n name: string;\n icon?: ReactNode;\n};\n\nexport const FileTreeFile = ({\n path,\n name,\n icon,\n className,\n children,\n ...props\n}: FileTreeFileProps) => {\n const { selectedPath, onSelect } = useContext(FileTreeContext);\n const isSelected = selectedPath === path;\n\n const handleClick = useCallback(() => {\n onSelect?.(path);\n }, [onSelect, path]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n onSelect?.(path);\n }\n },\n [onSelect, path]\n );\n\n const fileContextValue = useMemo(() => ({ name, path }), [name, path]);\n\n return (\n <FileTreeFileContext.Provider value={fileContextValue}>\n <div\n className={cn(\n \"flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50\",\n isSelected && \"bg-muted\",\n className\n )}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n role=\"treeitem\"\n tabIndex={0}\n {...props}\n >\n {children ?? (\n <>\n {/* Spacer for alignment */}\n <span className=\"size-4 shrink-0\" />\n <FileTreeIcon>\n {icon ?? <FileIcon className=\"size-4 text-muted-foreground\" />}\n </FileTreeIcon>\n <FileTreeName>{name}</FileTreeName>\n </>\n )}\n </div>\n </FileTreeFileContext.Provider>\n );\n};\n\nexport type FileTreeActionsProps = HTMLAttributes<HTMLDivElement>;\n\nconst stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();\n\nexport const FileTreeActions = ({\n className,\n children,\n ...props\n}: FileTreeActionsProps) => (\n <div\n className={cn(\"ml-auto flex items-center gap-1\", className)}\n onClick={stopPropagation}\n onKeyDown={stopPropagation}\n role=\"group\"\n {...props}\n >\n {children}\n </div>\n);\n","// `<SandboxProvider>` — thin wrapper around @browsernode/react's\n// `<SandboxRuntime>` (the headless engine binding) that adds\n// elements-specific extras (theme, selectedPath, openTabs, activePanel)\n// and resolves the `framework` string (\"nextjs\" → nextjs()) plus the\n// default bundler.\n//\n// Lifecycle/sandbox management is delegated to @browsernode/react entirely.\n// Components inside elements should:\n// • read the sandbox via `useSandbox()` (re-exported from @browsernode/react)\n// • read elements extras via `useElementsContext()`\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n SandboxRuntime,\n type UseSandboxOptions,\n} from '@browsernode/react';\nimport { esbuild } from '@browsernode/esbuild-wasm';\nimport { nextjs } from '@browsernode/nextjs';\nimport type {\n BundlerAdapter,\n FrameworkAdapter,\n} from '@browsernode/sandbox';\n\nexport { useSandbox } from '@browsernode/react';\n\nexport type SandboxPanel = 'left' | 'top' | 'center' | 'bottom';\n\n/**\n * Resolved color scheme for elements that need light/dark variants\n * (e.g. `<CodeEditor>`'s syntax theme). Pass the resolved value from your\n * theme system — e.g. `next-themes`' `useTheme().resolvedTheme`. Defaults\n * to `'light'`.\n */\nexport type SandboxTheme = 'light' | 'dark';\n\nexport interface SandboxTab {\n path: string;\n label?: string;\n}\n\n/** Elements-specific extras: theme, file selection, open tabs. */\nexport interface ElementsContextValue {\n selectedPath: string | null;\n setSelectedPath(path: string | null): void;\n\n openTabs: SandboxTab[];\n openTab(tab: SandboxTab | string): void;\n closeTab(path: string): void;\n\n activePanel: SandboxPanel;\n setActivePanel(panel: SandboxPanel): void;\n\n theme: SandboxTheme;\n}\n\nconst ElementsContext = createContext<ElementsContextValue | null>(null);\n\nexport type SandboxProviderFramework = FrameworkAdapter | 'nextjs';\n\ninterface SandboxProviderBaseProps {\n children: ReactNode;\n initialActivePanel?: SandboxPanel;\n initialOpenTabs?: readonly (SandboxTab | string)[];\n initialSelectedPath?: string | null;\n theme?: SandboxTheme;\n}\n\nexport interface SandboxProviderProps\n extends SandboxProviderBaseProps,\n Omit<UseSandboxOptions, 'framework' | 'bundler'> {\n framework: SandboxProviderFramework;\n bundler?: BundlerAdapter;\n}\n\nfunction toTab(t: SandboxTab | string): SandboxTab {\n return typeof t === 'string' ? { path: t } : t;\n}\n\nfunction resolveFramework(framework: SandboxProviderFramework): FrameworkAdapter {\n if (framework === 'nextjs') return nextjs();\n if (typeof framework === 'string') {\n throw new Error(`Unsupported SandboxProvider framework \"${framework}\".`);\n }\n return framework;\n}\n\nexport function SandboxProvider({ children, ...props }: SandboxProviderProps) {\n const {\n initialActivePanel,\n initialOpenTabs,\n initialSelectedPath,\n theme,\n framework,\n bundler,\n ...sandboxOptions\n } = props;\n\n const options = useMemo<UseSandboxOptions>(\n () => ({\n ...sandboxOptions,\n framework: resolveFramework(framework),\n bundler: bundler ?? esbuild(),\n }),\n // The sandbox is created once on mount (managed by <SandboxRuntime>'s\n // useEffect deps); listing only framework/bundler here keeps the\n // ref-stable options object the way callers expect.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [framework, bundler],\n );\n\n return (\n <SandboxRuntime options={options}>\n <ElementsExtrasProvider\n initialActivePanel={initialActivePanel}\n initialOpenTabs={initialOpenTabs}\n initialSelectedPath={initialSelectedPath}\n theme={theme}\n >\n {children}\n </ElementsExtrasProvider>\n </SandboxRuntime>\n );\n}\n\ninterface ElementsExtrasProviderProps extends SandboxProviderBaseProps {}\n\nfunction ElementsExtrasProvider({\n children,\n initialActivePanel = 'center',\n initialOpenTabs = [],\n initialSelectedPath = null,\n theme = 'light',\n}: ElementsExtrasProviderProps) {\n const [selectedPath, setSelectedPath] = useState<string | null>(initialSelectedPath);\n const [openTabs, setOpenTabs] = useState<SandboxTab[]>(() =>\n initialOpenTabs.map(toTab),\n );\n const [activePanel, setActivePanel] = useState<SandboxPanel>(initialActivePanel);\n\n const openTab = useCallback((t: SandboxTab | string) => {\n const tab = toTab(t);\n setOpenTabs((prev) => {\n if (prev.some((x) => x.path === tab.path)) return prev;\n return [...prev, tab];\n });\n setSelectedPath(tab.path);\n }, []);\n\n const closeTab = useCallback((path: string) => {\n setOpenTabs((prev) => {\n const next = prev.filter((t) => t.path !== path);\n setSelectedPath((cur) => {\n if (cur !== path) return cur;\n const idx = prev.findIndex((t) => t.path === path);\n const fallback = next[idx - 1] ?? next[idx] ?? next[0] ?? null;\n return fallback?.path ?? null;\n });\n return next;\n });\n }, []);\n\n const extras = useMemo<ElementsContextValue>(\n () => ({\n selectedPath,\n setSelectedPath,\n openTabs,\n openTab,\n closeTab,\n activePanel,\n setActivePanel,\n theme,\n }),\n [selectedPath, openTabs, openTab, closeTab, activePanel, theme],\n );\n\n return <ElementsContext.Provider value={extras}>{children}</ElementsContext.Provider>;\n}\n\n/** Read elements-specific state (theme, selectedPath, openTabs). */\nexport function useElementsContext(): ElementsContextValue | null {\n return useContext(ElementsContext);\n}\n\nexport function useElementsContextOrThrow(): ElementsContextValue {\n const ctx = useContext(ElementsContext);\n if (!ctx) {\n throw new Error(\n 'useElementsContext() must be called inside <SandboxProvider> from @browsernode/elements.',\n );\n }\n return ctx;\n}\n","import { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../lib/utils\"\n\nconst buttonVariants = cva(\n \"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\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n outline:\n \"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\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"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\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n 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\",\n 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\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n icon: \"size-8\",\n \"icon-xs\":\n \"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\":\n \"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import * as React from \"react\"\nimport { Popover as PopoverPrimitive } from \"@base-ui/react/popover\"\n\nimport { cn } from \"../lib/utils\"\n\nfunction Popover({ ...props }: PopoverPrimitive.Root.Props) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n alignOffset = 0,\n side = \"bottom\",\n sideOffset = 4,\n ...props\n}: PopoverPrimitive.Popup.Props &\n Pick<\n PopoverPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <PopoverPrimitive.Popup\n data-slot=\"popover-content\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Positioner>\n </PopoverPrimitive.Portal>\n )\n}\n\nfunction PopoverHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"popover-header\"\n className={cn(\"flex flex-col gap-0.5 text-sm\", className)}\n {...props}\n />\n )\n}\n\nfunction PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {\n return (\n <PopoverPrimitive.Title\n data-slot=\"popover-title\"\n className={cn(\"font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction PopoverDescription({\n className,\n ...props\n}: PopoverPrimitive.Description.Props) {\n return (\n <PopoverPrimitive.Description\n data-slot=\"popover-description\"\n className={cn(\"text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Popover,\n PopoverContent,\n PopoverDescription,\n PopoverHeader,\n PopoverTitle,\n PopoverTrigger,\n}\n","// Shared tree builders for SandboxIDEFiles. Consumes a flat list of\n// absolute paths from `sandbox.fs.list()` and produces nodes the\n// FileTree primitive renders.\n\nimport type { ReactNode } from 'react';\nimport { FileTreeFile, FileTreeFolder } from '../primitives/file-tree';\n\ninterface TreeNode {\n name: string;\n path: string;\n /** null = file leaf. */\n children: Map<string, TreeNode> | null;\n}\n\nexport function buildTree(paths: string[]): TreeNode {\n const root: TreeNode = { name: '', path: '', children: new Map() };\n for (const path of paths) {\n const parts = path.split('/').filter(Boolean);\n let cur = root;\n for (let i = 0; i < parts.length; i++) {\n const name = parts[i]!;\n const isLeaf = i === parts.length - 1;\n // Tree paths are absolute (`/src/app/page.tsx`) so they match\n // `sandbox.fs.list()` output and `selectedPath` flows through\n // `fs.readFile` consistently.\n const childPath = '/' + parts.slice(0, i + 1).join('/');\n if (!cur.children) break;\n let child = cur.children.get(name);\n if (!child) {\n child = { name, path: childPath, children: isLeaf ? null : new Map() };\n cur.children.set(name, child);\n }\n if (!isLeaf && child.children) cur = child;\n else if (!isLeaf && !child.children) break; // path collision\n }\n }\n return root;\n}\n\nexport function renderTree(node: TreeNode): ReactNode {\n if (!node.children) return null;\n // Folders first, then files; alphabetical within each group.\n const entries = Array.from(node.children.values()).sort((a, b) => {\n const aFolder = a.children !== null;\n const bFolder = b.children !== null;\n if (aFolder !== bFolder) return aFolder ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n return entries.map((entry) =>\n entry.children ? (\n <FileTreeFolder key={entry.path} name={entry.name} path={entry.path}>\n {renderTree(entry)}\n </FileTreeFolder>\n ) : (\n <FileTreeFile key={entry.path} name={entry.name} path={entry.path} />\n ),\n );\n}\n\nexport function isFile(path: string, files: string[]): boolean {\n return files.includes(path);\n}\n\nexport function defaultExpansion(files: string[]): Set<string> {\n const roots = ['src', 'app', 'pages', 'components'];\n const expanded = new Set<string>();\n for (const root of roots) {\n const abs = '/' + root;\n if (files.some((f) => f === abs || f.startsWith(`${abs}/`))) {\n expanded.add(abs);\n }\n }\n return expanded;\n}\n","// `<SandboxCodeEditor>` — header chrome (filename + Save + More dropdown)\n// + a buffered CodeMirror editor. Reads `selectedPath` from elements\n// context; loads file contents on selection change; persists via\n// `sandbox.fs.writeFile` on Save (button or Cmd/Ctrl+S).\n//\n// CodeMirror knobs (theme, basicSetup, extensions, language) are passed\n// straight through to the underlying `<CodeEditor>` so callers can tune\n// the editor without dropping down a level.\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { MoreHorizontalIcon } from 'lucide-react';\nimport type { Extension } from '@codemirror/state';\nimport { keymap } from '@codemirror/view';\nimport type { ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport type { Sandbox } from '@browsernode/sandbox';\nimport {\n CodeEditor,\n type CodeEditorLanguage,\n type CodeEditorTheme,\n} from './primitives/code-editor';\nimport { Button } from '../primitives/ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../primitives/ui/dropdown-menu';\nimport { Loader } from '../primitives/ui/loading';\nimport { useElementsContext, useSandbox } from '../provider/sandbox-provider';\nimport { guessLanguage } from './internal/language';\n\nexport interface SandboxCodeEditorProps {\n /** Override the sandbox from the surrounding `<SandboxProvider>`. */\n sandbox?: Sandbox | null;\n /** Disable saves (Save button hidden, Cmd-S no-op). Default false. */\n readOnly?: boolean;\n /** CodeMirror theme override (forwarded to `<CodeEditor>`). */\n theme?: CodeEditorTheme;\n /** CodeMirror basic-setup overrides (line numbers, fold gutter, etc.). */\n basicSetup?: ReactCodeMirrorProps['basicSetup'];\n /** Extra CodeMirror extensions appended after the language ones. */\n extensions?: Extension[];\n /** Force a CodeMirror language regardless of file extension. */\n language?: CodeEditorLanguage;\n /** Hide the file header (filename + dirty dot + Save + More). */\n hideHeader?: boolean;\n /** Custom empty state when no file is selected. */\n emptyState?: ReactNode;\n /**\n * Slot rendered inside the header, immediately after the filename and\n * before the Save button. Used by `<SandboxIDELayout>` to inject the\n * mobile dropdown trigger; consumers can use it for any leading chrome.\n */\n headerStartSlot?: ReactNode;\n className?: string;\n}\n\ntype SaveStatus = 'idle' | 'saving' | 'saved' | 'error';\n\nexport function SandboxCodeEditor({\n sandbox: sandboxProp,\n readOnly = false,\n theme,\n basicSetup,\n extensions,\n language: languageProp,\n hideHeader = false,\n emptyState,\n headerStartSlot,\n className,\n}: SandboxCodeEditorProps) {\n const elementsCtx = useElementsContext();\n const sandboxState = useSandbox();\n const sandbox = sandboxProp ?? sandboxState.sandbox;\n\n const selectedPath = elementsCtx?.selectedPath ?? null;\n const setSelectedPath = elementsCtx?.setSelectedPath;\n\n const [savedText, setSavedText] = useState<string | null>(null);\n const [buffer, setBuffer] = useState<string>('');\n const [loadingPath, setLoadingPath] = useState<string | null>(null);\n const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle');\n\n // Path the editor's current `buffer` was loaded from. Used to ignore\n // stale onChange callbacks during file-switch (CodeMirror's controlled\n // value briefly lags one frame).\n const loadedPathRef = useRef<string | null>(null);\n const savedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Refs for stable callbacks (Cmd-S keymap, delete handler).\n const sandboxRef = useRef(sandbox);\n const selectedPathRef = useRef(selectedPath);\n const bufferRef = useRef(buffer);\n const dirtyRef = useRef(false);\n sandboxRef.current = sandbox;\n selectedPathRef.current = selectedPath;\n bufferRef.current = buffer;\n\n useEffect(() => {\n if (!sandbox || !selectedPath) {\n setSavedText(null);\n setBuffer('');\n loadedPathRef.current = null;\n return;\n }\n setLoadingPath(selectedPath);\n setSaveStatus('idle');\n let cancelled = false;\n sandbox.fs\n .readFile(selectedPath)\n .then((c) => {\n if (cancelled) return;\n setSavedText(c);\n setBuffer(c);\n loadedPathRef.current = selectedPath;\n setLoadingPath(null);\n })\n .catch(() => {\n if (cancelled) return;\n const fallback = `// Could not read ${selectedPath}`;\n setSavedText(fallback);\n setBuffer(fallback);\n loadedPathRef.current = null;\n setLoadingPath(null);\n });\n return () => {\n cancelled = true;\n };\n }, [sandbox, selectedPath]);\n\n useEffect(() => {\n return () => {\n if (savedTimerRef.current) {\n clearTimeout(savedTimerRef.current);\n savedTimerRef.current = null;\n }\n };\n }, [selectedPath]);\n\n const handleEditorChange = useCallback(\n (next: string) => {\n setBuffer(next);\n if (readOnly) return;\n if (!selectedPath) return;\n // Drop changes fired before the load has settled on this path.\n if (loadedPathRef.current !== selectedPath) return;\n },\n [readOnly, selectedPath],\n );\n\n const dirty = !readOnly && savedText !== null && buffer !== savedText;\n dirtyRef.current = dirty;\n\n const deleteFile = useCallback(async () => {\n if (readOnly) return;\n const sb = sandboxRef.current;\n const path = selectedPathRef.current;\n if (!sb || !path) return;\n try {\n await sb.fs.rm(path);\n setSelectedPath?.(null);\n } catch {\n // Surfaces via sandbox.on('error') if anyone's listening.\n }\n }, [readOnly, setSelectedPath]);\n\n const save = useCallback(async () => {\n if (readOnly) return;\n const sb = sandboxRef.current;\n const path = selectedPathRef.current;\n const text = bufferRef.current;\n if (!sb || !path) return;\n if (!dirtyRef.current) return;\n // The in-memory write resolves the same microtask, so React would\n // batch this with the 'saved' set below and never paint the spinner.\n // The minimum-duration delay below holds the spinner visible long\n // enough to register visually.\n setSaveStatus('saving');\n try {\n await sb.fs.writeFile(path, text);\n await new Promise((r) => setTimeout(r, 500));\n setSavedText(text);\n setSaveStatus('idle');\n } catch {\n setSaveStatus('error');\n }\n }, [readOnly]);\n\n // Cmd/Ctrl+S keybinding. Stable extension array so we don't rebuild\n // CodeMirror on every keystroke.\n const editorExtensions = useMemo<Extension[]>(\n () => {\n const base = [\n keymap.of([\n {\n key: 'Mod-s',\n preventDefault: true,\n run: () => {\n void save();\n return true;\n },\n },\n ]),\n ];\n return extensions ? [...base, ...extensions] : base;\n },\n [save, extensions],\n );\n\n const lang: CodeEditorLanguage = languageProp\n ? languageProp\n : selectedPath\n ? guessLanguage(selectedPath)\n : 'plaintext';\n\n // Always render the outer column + header, even with no file selected,\n // so callers' `headerStartSlot` (typically the file-tree dropdown\n // trigger) stays reachable. Otherwise the user would be locked out of\n // the picker on mobile.\n //\n // When a slot is provided AND no file is selected, the slot owns the\n // empty-state messaging (e.g. the dropdown trigger reads \"Select a\n // file\"). We don't add a separate label so the text isn't duplicated.\n // Show just the basename in the header — full paths get long fast and\n // crowd out the Save/More buttons. Hover/title still exposes the full\n // path for orientation.\n const filename = selectedPath\n ? selectedPath.split('/').filter(Boolean).pop() ?? selectedPath\n : null;\n const headerLabel = selectedPath ? (\n <span className=\"font-mono\" title={selectedPath}>\n {filename}\n </span>\n ) : headerStartSlot ? null : (\n <span>Select a file</span>\n );\n\n return (\n <div className={`flex h-full w-full flex-col ${className ?? ''}`.trim()}>\n {!hideHeader && (\n <div className=\"flex flex-none items-center justify-between border-b px-3 py-2 text-xs\">\n <div className=\"flex items-center gap-1.5 text-muted-foreground\">\n {headerStartSlot}\n {headerLabel}\n </div>\n {selectedPath && !readOnly && (\n <div className=\"flex items-center gap-1\">\n <Button\n size=\"sm\"\n onClick={() => void save()}\n className=\"h-9 px-4 text-sm md:h-8 md:px-3 md:text-xs\"\n >\n {saveStatus === 'saving' ? (\n <>\n <Loader size={14} />\n Saving...\n </>\n ) : (\n 'Save'\n )}\n </Button>\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label=\"File actions\"\n className=\"size-10 p-0 md:size-8\"\n />\n }\n >\n <MoreHorizontalIcon className=\"size-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n onClick={() => void deleteFile()}\n className=\"text-destructive focus:text-destructive\"\n >\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )}\n </div>\n )}\n <div className=\"flex-1 min-h-0 overflow-auto\">\n {selectedPath ? (\n <CodeEditor\n key={selectedPath}\n value={buffer}\n onChange={handleEditorChange}\n language={lang}\n theme={theme}\n basicSetup={basicSetup}\n readOnly={readOnly || loadingPath === selectedPath}\n extensions={editorExtensions}\n height=\"100%\"\n className=\"h-full text-sm\"\n />\n ) : (\n emptyState ?? (\n <div className=\"flex h-full w-full items-center justify-center text-muted-foreground text-sm\">\n Select a file from the menu\n </div>\n )\n )}\n </div>\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport CodeMirror, {\n EditorView,\n type Extension,\n type ReactCodeMirrorProps,\n} from '@uiw/react-codemirror';\nimport { javascript } from '@codemirror/lang-javascript';\nimport { css } from '@codemirror/lang-css';\nimport { html } from '@codemirror/lang-html';\nimport { json } from '@codemirror/lang-json';\nimport { markdown } from '@codemirror/lang-markdown';\nimport { useElementsContext } from '../../provider/sandbox-provider';\n\nexport type CodeEditorLanguage =\n | 'typescript'\n | 'tsx'\n | 'javascript'\n | 'jsx'\n | 'css'\n | 'html'\n | 'json'\n | 'markdown'\n | 'plaintext';\n\nexport type CodeEditorTheme = 'light' | 'dark' | Extension;\n\nexport interface CodeEditorProps\n extends Omit<\n ReactCodeMirrorProps,\n 'value' | 'onChange' | 'extensions' | 'theme'\n > {\n value: string;\n onChange?: (next: string) => void;\n language?: CodeEditorLanguage;\n /**\n * Editor color scheme. If omitted, falls back to `<SandboxProvider>`'s\n * `theme` (or `'light'` when no provider is mounted). Pass an\n * `Extension` to fully override CodeMirror's theme system.\n */\n theme?: CodeEditorTheme;\n /** Extra CodeMirror extensions appended to the language-derived ones. */\n extensions?: Extension[];\n className?: string;\n}\n\n/**\n * `<CodeEditor>` — thin CodeMirror 6 wrapper. Pass `value` + `onChange`\n * for controlled editing; `language` selects the syntax extension.\n *\n * The host is responsible for debouncing writes back to disk; this\n * component fires `onChange` for every keystroke.\n */\nexport function CodeEditor({\n value,\n onChange,\n language = 'plaintext',\n theme,\n extensions: extraExtensions,\n className,\n basicSetup,\n ...rest\n}: CodeEditorProps) {\n const ctx = useElementsContext();\n const resolvedTheme: CodeEditorTheme = theme ?? ctx?.theme ?? 'light';\n\n const extensions = useMemo<Extension[]>(() => {\n const langExt = languageExtension(language);\n const wrap = EditorView.lineWrapping;\n const base: Extension[] = [wrap];\n if (langExt) base.push(langExt);\n return extraExtensions ? [...base, ...extraExtensions] : base;\n }, [language, extraExtensions]);\n\n return (\n <CodeMirror\n value={value}\n onChange={onChange}\n extensions={extensions}\n theme={resolvedTheme}\n basicSetup={\n basicSetup ?? {\n lineNumbers: true,\n highlightActiveLine: true,\n highlightActiveLineGutter: true,\n foldGutter: true,\n autocompletion: true,\n bracketMatching: true,\n closeBrackets: true,\n indentOnInput: true,\n searchKeymap: true,\n }\n }\n className={className}\n {...rest}\n />\n );\n}\n\nfunction languageExtension(lang: CodeEditorLanguage): Extension | null {\n switch (lang) {\n case 'typescript':\n return javascript({ typescript: true });\n case 'tsx':\n return javascript({ typescript: true, jsx: true });\n case 'javascript':\n return javascript();\n case 'jsx':\n return javascript({ jsx: true });\n case 'css':\n return css();\n case 'html':\n return html();\n case 'json':\n return json();\n case 'markdown':\n return markdown();\n case 'plaintext':\n default:\n return null;\n }\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\n\nimport { cn } from \"../lib/utils\"\nimport { ChevronRightIcon, CheckIcon } from \"lucide-react\"\n\nfunction DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {\n return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {\n return <MenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n}\n\nfunction DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {\n return <MenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />\n}\n\nfunction DropdownMenuContent({\n align = \"start\",\n alignOffset = 0,\n side = \"bottom\",\n sideOffset = 4,\n className,\n ...props\n}: MenuPrimitive.Popup.Props &\n Pick<\n MenuPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner\n className=\"isolate z-50 outline-none\"\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n >\n <MenuPrimitive.Popup\n data-slot=\"dropdown-menu-content\"\n 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 )}\n {...props}\n />\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {\n return <MenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: MenuPrimitive.GroupLabel.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.GroupLabel\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n \"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: MenuPrimitive.Item.Props & {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}) {\n return (\n <MenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {\n return <MenuPrimitive.SubmenuRoot data-slot=\"dropdown-menu-sub\" {...props} />\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: MenuPrimitive.SubmenuTrigger.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.SubmenuTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"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-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto\" />\n </MenuPrimitive.SubmenuTrigger>\n )\n}\n\nfunction DropdownMenuSubContent({\n align = \"start\",\n alignOffset = -3,\n side = \"right\",\n sideOffset = 0,\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuContent>) {\n return (\n <DropdownMenuContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\"w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-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\", className )}\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n inset,\n ...props\n}: MenuPrimitive.CheckboxItem.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n data-inset={inset}\n className={cn(\n \"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-checkbox-item-indicator\"\n >\n <MenuPrimitive.CheckboxItemIndicator>\n <CheckIcon\n />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n )\n}\n\nfunction DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {\n return (\n <MenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n inset,\n ...props\n}: MenuPrimitive.RadioItem.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n data-inset={inset}\n className={cn(\n \"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-radio-item-indicator\"\n >\n <MenuPrimitive.RadioItemIndicator>\n <CheckIcon\n />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: MenuPrimitive.Separator.Props) {\n return (\n <MenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../lib/utils';\n\ninterface LoaderIconProps {\n size?: number;\n}\n\nconst LoaderIcon = ({ size = 16 }: LoaderIconProps) => (\n <svg\n height={size}\n strokeLinejoin=\"round\"\n style={{ color: 'currentcolor' }}\n viewBox=\"0 0 16 16\"\n width={size}\n >\n <title>Loader</title>\n <g clipPath=\"url(#clip0_2393_1490)\">\n <path d=\"M8 0V4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path\n d=\"M8 16V12\"\n opacity=\"0.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M3.29773 1.52783L5.64887 4.7639\"\n opacity=\"0.9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M12.7023 1.52783L10.3511 4.7639\"\n opacity=\"0.1\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M12.7023 14.472L10.3511 11.236\"\n opacity=\"0.4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M3.29773 14.472L5.64887 11.236\"\n opacity=\"0.6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M15.6085 5.52783L11.8043 6.7639\"\n opacity=\"0.2\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M0.391602 10.472L4.19583 9.23598\"\n opacity=\"0.7\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M15.6085 10.4722L11.8043 9.2361\"\n opacity=\"0.3\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M0.391602 5.52783L4.19583 6.7639\"\n opacity=\"0.8\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2393_1490\">\n <rect fill=\"white\" height=\"16\" width=\"16\" />\n </clipPath>\n </defs>\n </svg>\n);\n\nexport type LoaderProps = HTMLAttributes<HTMLDivElement> & {\n size?: number;\n};\n\nexport const Loader = ({ className, size = 16, ...props }: LoaderProps) => (\n <div\n className={cn(\n 'inline-flex animate-spin items-center justify-center',\n className,\n )}\n {...props}\n >\n <LoaderIcon size={size} />\n </div>\n);\n","// File-extension → CodeMirror language id. Kept as a tiny static map;\n// CodeEditor handles the language extension for each id.\n\nimport type { CodeEditorLanguage } from '../primitives/code-editor';\n\nconst EXT_TO_LANG: Record<string, CodeEditorLanguage> = {\n ts: 'typescript',\n tsx: 'tsx',\n js: 'javascript',\n jsx: 'jsx',\n mjs: 'javascript',\n cjs: 'javascript',\n json: 'json',\n md: 'markdown',\n mdx: 'markdown',\n css: 'css',\n scss: 'css',\n html: 'html',\n htm: 'html',\n};\n\nexport function guessLanguage(path: string): CodeEditorLanguage {\n const m = path.match(/\\.([^.]+)$/);\n if (!m) return 'plaintext';\n const ext = m[1]!.toLowerCase();\n return EXT_TO_LANG[ext] ?? 'plaintext';\n}\n","// `<SandboxIDE>` — responsive composition of `<SandboxFileTree>` and\n// `<SandboxCodeEditor>`.\n//\n// • md+ side-by-side: file tree as a 64-wide left column.\n// • below md stacked: a hamburger-icon trigger sits inside the\n// code-editor header next to the filename, opening a\n// popover with the tree (via\n// `<SandboxFileTree display=\"dropdown\" />`).\n//\n// CSS-driven (Tailwind's `md:` prefix); no JS resize listeners. Both\n// trees stay mounted across breakpoint changes — both are bound to the\n// same `selectedPath` in elements context, so selection is consistent.\n\nimport { type CSSProperties } from 'react';\nimport type { Sandbox } from '@browsernode/sandbox';\nimport { SandboxFileTree } from './sandbox-file-tree';\nimport {\n SandboxCodeEditor,\n type SandboxCodeEditorProps,\n} from './sandbox-code-editor';\n\nexport interface SandboxIDEProps\n extends Omit<SandboxCodeEditorProps, 'headerStartSlot' | 'className'> {\n /** Override the sandbox from the surrounding `<SandboxProvider>`. */\n sandbox?: Sandbox | null;\n /** Initial folders to expand (forwarded to `<SandboxFileTree>`). */\n defaultExpanded?: Set<string>;\n /** Hide the file tree entirely (editor-only layout). */\n hideTree?: boolean;\n /** Hide the code editor entirely (tree-only layout). */\n hideViewer?: boolean;\n /**\n * Drop the rounded-lg + border on the outer wrapper. Use when embedded\n * inside a host frame that already provides chrome (e.g. inside\n * `<Sandbox>`).\n */\n hideBorder?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function SandboxIDE({\n sandbox,\n defaultExpanded,\n hideTree = false,\n hideViewer = false,\n hideBorder = false,\n className,\n style,\n ...codeProps\n}: SandboxIDEProps) {\n // Tree-only layout — just render files directly.\n if (hideViewer) {\n return (\n <SandboxFileTree\n sandbox={sandbox}\n defaultExpanded={defaultExpanded}\n className={className}\n />\n );\n }\n\n // Editor-only layout — just render code, no tree (mobile or otherwise).\n if (hideTree) {\n return (\n <SandboxCodeEditor\n sandbox={sandbox}\n className={className}\n {...codeProps}\n />\n );\n }\n\n const frameClasses = hideBorder\n ? 'flex h-full w-full flex-col md:flex-row overflow-hidden bg-background'\n : 'flex h-full w-full flex-col md:flex-row overflow-hidden rounded-lg border bg-background';\n\n // Mobile-only file-picker trigger lives inside the code-editor header,\n // collapsing the would-be \"dropdown row\" into the same row as the\n // filename. Hidden at md+ where the sidebar tree is the picker. The\n // default trigger label adapts to selection state — \"[☰] Select a\n // file\" when empty, just \"[☰]\" when a file is loaded.\n const mobileTrigger = (\n <SandboxFileTree\n sandbox={sandbox}\n defaultExpanded={defaultExpanded}\n display=\"dropdown\"\n className=\"md:hidden -ml-1\"\n />\n );\n\n return (\n <div className={`${frameClasses} ${className ?? ''}`.trim()} style={style}>\n {/* Desktop-only: sidebar tree on the left. Hidden below md. Block\n (not flex) so the tree fills the column width to the divider. */}\n <div className=\"hidden md:block w-64 shrink-0 overflow-auto border-r\">\n <SandboxFileTree sandbox={sandbox} defaultExpanded={defaultExpanded} />\n </div>\n\n <div className=\"flex-1 min-w-0 overflow-hidden\">\n <SandboxCodeEditor\n sandbox={sandbox}\n headerStartSlot={mobileTrigger}\n {...codeProps}\n />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useMemo","useState","jsx","createContext","useCallback","useContext","useMemo","useState","jsx","useContext","jsx","jsx","jsx","Fragment","jsx","jsxs","useState","useMemo","useCallback","useEffect","useMemo","useState","useMemo","jsx","useMemo","ChevronRightIcon","jsx","jsxs","jsx","jsx","jsx","jsxs","Fragment","jsx","jsxs","useState","useEffect","useCallback","useMemo","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/editor/sandbox-file-tree.tsx","../src/primitives/ui/collapsible.tsx","../src/primitives/lib/utils.ts","../src/editor/primitives/file-tree.tsx","../src/provider/sandbox-provider.tsx","../src/primitives/ui/button.tsx","../src/primitives/ui/popover.tsx","../src/editor/internal/tree.tsx","../src/editor/sandbox-code-editor.tsx","../src/editor/primitives/code-editor.tsx","../src/primitives/ui/dropdown-menu.tsx","../src/primitives/ui/loading.tsx","../src/editor/internal/language.ts","../src/editor/sandbox-ide.tsx"],"sourcesContent":["// `<SandboxFileTree>` — file tree only. Reads `selectedPath` /\n// `setSelectedPath` from `useElementsContext`. Subscribes to\n// `sandbox.fs` change events so the tree mirrors mutations.\n//\n// `display=\"dropdown\"` collapses the tree behind a folder-icon\n// `<Popover>` trigger — useful for mobile / narrow side panels.\n\nimport { useEffect, useMemo, useState, type ReactNode } from 'react';\nimport { MenuIcon } from 'lucide-react';\nimport type { Sandbox } from '@browsernode/sandbox';\nimport { FileTree } from './primitives/file-tree';\nimport { useElementsContext, useSandbox } from '../provider/sandbox-provider';\nimport { Button } from '../primitives/ui/button';\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from '../primitives/ui/popover';\nimport {\n buildTree,\n defaultExpansion,\n isFile,\n renderTree,\n} from './internal/tree';\n\nexport interface SandboxFileTreeProps {\n /** Override the sandbox from the surrounding `<SandboxProvider>`. */\n sandbox?: Sandbox | null;\n /** Initial folders to expand. Defaults to common roots when present. */\n defaultExpanded?: Set<string>;\n /**\n * Called when a file is selected. Fires *in addition* to updating the\n * elements context's `selectedPath`.\n */\n onSelect?: (path: string) => void;\n /**\n * Render mode:\n * • `\"tree\"` (default) — full inline tree, expects a parent that\n * gives it height to scroll within\n * • `\"dropdown\"` — folder-icon button that opens a popover with the\n * tree inside; selecting a file closes the popover\n */\n display?: 'tree' | 'dropdown';\n /**\n * Trigger contents (dropdown variant). Defaults to a hamburger icon\n * + \"Select file\" label.\n */\n triggerLabel?: ReactNode;\n className?: string;\n}\n\nexport function SandboxFileTree({\n sandbox: sandboxProp,\n defaultExpanded,\n onSelect,\n display = 'tree',\n triggerLabel,\n className,\n}: SandboxFileTreeProps) {\n const elementsCtx = useElementsContext();\n const sandboxState = useSandbox();\n const sandbox = sandboxProp ?? sandboxState.sandbox;\n\n const [files, setFiles] = useState<string[]>(() =>\n sandbox ? sandbox.fs.list() : [],\n );\n const [open, setOpen] = useState(false);\n\n const selectedPath = elementsCtx?.selectedPath ?? null;\n const setSelectedPath = elementsCtx?.setSelectedPath;\n\n useEffect(() => {\n if (!sandbox) return;\n setFiles(sandbox.fs.list());\n return sandbox.fs.on('change', () => setFiles(sandbox.fs.list()));\n }, [sandbox]);\n\n const tree = useMemo(() => buildTree(files), [files]);\n\n const handleSelect = (path: string) => {\n if (!isFile(path, files)) return;\n setSelectedPath?.(path);\n onSelect?.(path);\n if (display === 'dropdown') setOpen(false);\n };\n\n const treeNode = (\n <FileTree\n defaultExpanded={defaultExpanded ?? defaultExpansion(files)}\n onSelect={handleSelect}\n selectedPath={selectedPath ?? undefined}\n className={`h-full w-full overflow-auto rounded-none border-0 bg-transparent ${className ?? ''}`.trim()}\n >\n {renderTree(tree)}\n </FileTree>\n );\n\n if (display === 'dropdown') {\n // Default trigger contents adapt to selection state: with no file\n // selected, the button reads \"[☰] Select a file\" so the empty\n // state has a single self-explanatory affordance. Once a file is\n // selected, the button collapses to the icon only — the surrounding\n // header (or whatever the consumer composes) is responsible for\n // showing the filename next to it.\n const defaultLabel = selectedPath ? (\n <MenuIcon className=\"size-4\" />\n ) : (\n <>\n <MenuIcon className=\"size-4\" />\n <span>Select a file</span>\n </>\n );\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger\n render={\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label=\"Select file\"\n className={`h-8 gap-2 px-2 text-xs font-normal ${className ?? ''}`.trim()}\n />\n }\n >\n {triggerLabel ?? defaultLabel}\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"w-72 p-0 max-h-[26rem] flex flex-col overflow-hidden\"\n >\n {treeNode}\n </PopoverContent>\n </Popover>\n );\n }\n\n return treeNode;\n}\n","\"use client\"\n\nimport { Collapsible as CollapsiblePrimitive } from \"@base-ui/react/collapsible\"\n\nfunction Collapsible({ ...props }: CollapsiblePrimitive.Root.Props) {\n return <CollapsiblePrimitive.Root data-slot=\"collapsible\" {...props} />\n}\n\nfunction CollapsibleTrigger({ ...props }: CollapsiblePrimitive.Trigger.Props) {\n return (\n <CollapsiblePrimitive.Trigger data-slot=\"collapsible-trigger\" {...props} />\n )\n}\n\nfunction CollapsibleContent({ ...props }: CollapsiblePrimitive.Panel.Props) {\n return (\n <CollapsiblePrimitive.Panel data-slot=\"collapsible-content\" {...props} />\n )\n}\n\nexport { Collapsible, CollapsibleTrigger, CollapsibleContent }\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","\"use client\";\n\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from \"../../primitives/ui/collapsible\";\nimport { cn } from \"../../primitives/lib/utils\";\nimport {\n ChevronRightIcon,\n FileIcon,\n FolderIcon,\n FolderOpenIcon,\n} from \"lucide-react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n} from \"react\";\n\ninterface FileTreeContextType {\n expandedPaths: Set<string>;\n togglePath: (path: string) => void;\n selectedPath?: string;\n onSelect?: (path: string) => void;\n}\n\n// Default noop for context default value\n// oxlint-disable-next-line eslint(no-empty-function)\nconst noop = () => {};\n\nconst FileTreeContext = createContext<FileTreeContextType>({\n // oxlint-disable-next-line eslint-plugin-unicorn(no-new-builtin)\n expandedPaths: new Set(),\n togglePath: noop,\n});\n\nexport type FileTreeProps = Omit<HTMLAttributes<HTMLDivElement>, \"onSelect\"> & {\n expanded?: Set<string>;\n defaultExpanded?: Set<string>;\n selectedPath?: string;\n onSelect?: (path: string) => void;\n onExpandedChange?: (expanded: Set<string>) => void;\n};\n\nexport const FileTree = ({\n expanded: controlledExpanded,\n defaultExpanded = new Set(),\n selectedPath,\n onSelect,\n onExpandedChange,\n className,\n children,\n ...props\n}: FileTreeProps) => {\n const [internalExpanded, setInternalExpanded] = useState(defaultExpanded);\n const expandedPaths = controlledExpanded ?? internalExpanded;\n\n const togglePath = useCallback(\n (path: string) => {\n const newExpanded = new Set(expandedPaths);\n if (newExpanded.has(path)) {\n newExpanded.delete(path);\n } else {\n newExpanded.add(path);\n }\n setInternalExpanded(newExpanded);\n onExpandedChange?.(newExpanded);\n },\n [expandedPaths, onExpandedChange]\n );\n\n const contextValue = useMemo(\n () => ({ expandedPaths, onSelect, selectedPath, togglePath }),\n [expandedPaths, onSelect, selectedPath, togglePath]\n );\n\n return (\n <FileTreeContext.Provider value={contextValue}>\n <div\n className={cn(\n \"rounded-lg border bg-background font-mono text-sm\",\n className\n )}\n role=\"tree\"\n {...props}\n >\n <div className=\"p-2\">{children}</div>\n </div>\n </FileTreeContext.Provider>\n );\n};\n\nexport type FileTreeIconProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const FileTreeIcon = ({\n className,\n children,\n ...props\n}: FileTreeIconProps) => (\n <span className={cn(\"shrink-0\", className)} {...props}>\n {children}\n </span>\n);\n\nexport type FileTreeNameProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const FileTreeName = ({\n className,\n children,\n ...props\n}: FileTreeNameProps) => (\n <span className={cn(\"truncate\", className)} {...props}>\n {children}\n </span>\n);\n\ninterface FileTreeFolderContextType {\n path: string;\n name: string;\n isExpanded: boolean;\n}\n\nconst FileTreeFolderContext = createContext<FileTreeFolderContextType>({\n isExpanded: false,\n name: \"\",\n path: \"\",\n});\n\nexport type FileTreeFolderProps = HTMLAttributes<HTMLDivElement> & {\n path: string;\n name: string;\n};\n\nexport const FileTreeFolder = ({\n path,\n name,\n className,\n children,\n ...props\n}: FileTreeFolderProps) => {\n const { expandedPaths, togglePath, selectedPath, onSelect } =\n useContext(FileTreeContext);\n const isExpanded = expandedPaths.has(path);\n const isSelected = selectedPath === path;\n\n const handleOpenChange = useCallback(() => {\n togglePath(path);\n }, [togglePath, path]);\n\n const handleSelect = useCallback(() => {\n onSelect?.(path);\n }, [onSelect, path]);\n\n const folderContextValue = useMemo(\n () => ({ isExpanded, name, path }),\n [isExpanded, name, path]\n );\n\n return (\n <FileTreeFolderContext.Provider value={folderContextValue}>\n <Collapsible onOpenChange={handleOpenChange} open={isExpanded}>\n <div\n className={cn(\"\", className)}\n role=\"treeitem\"\n tabIndex={0}\n {...props}\n >\n <div\n className={cn(\n \"flex w-full items-center gap-1 rounded px-2 py-1 text-left transition-colors hover:bg-muted/50\",\n isSelected && \"bg-muted\"\n )}\n >\n <CollapsibleTrigger render={<button className=\"flex shrink-0 cursor-pointer items-center border-none bg-transparent p-0\" type=\"button\" />}><ChevronRightIcon\n className={cn(\n \"size-4 shrink-0 text-muted-foreground transition-transform\",\n isExpanded && \"rotate-90\"\n )}\n /></CollapsibleTrigger>\n <button\n className=\"flex min-w-0 flex-1 cursor-pointer items-center gap-1 border-none bg-transparent p-0 text-left\"\n onClick={() => {\n handleSelect();\n togglePath(path);\n }}\n type=\"button\"\n >\n <FileTreeIcon>\n {isExpanded ? (\n <FolderOpenIcon className=\"size-4 text-blue-500\" />\n ) : (\n <FolderIcon className=\"size-4 text-blue-500\" />\n )}\n </FileTreeIcon>\n <FileTreeName>{name}</FileTreeName>\n </button>\n </div>\n <CollapsibleContent>\n <div className=\"ml-4 border-l pl-2\">{children}</div>\n </CollapsibleContent>\n </div>\n </Collapsible>\n </FileTreeFolderContext.Provider>\n );\n};\n\ninterface FileTreeFileContextType {\n path: string;\n name: string;\n}\n\nconst FileTreeFileContext = createContext<FileTreeFileContextType>({\n name: \"\",\n path: \"\",\n});\n\nexport type FileTreeFileProps = HTMLAttributes<HTMLDivElement> & {\n path: string;\n name: string;\n icon?: ReactNode;\n};\n\nexport const FileTreeFile = ({\n path,\n name,\n icon,\n className,\n children,\n ...props\n}: FileTreeFileProps) => {\n const { selectedPath, onSelect } = useContext(FileTreeContext);\n const isSelected = selectedPath === path;\n\n const handleClick = useCallback(() => {\n onSelect?.(path);\n }, [onSelect, path]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n onSelect?.(path);\n }\n },\n [onSelect, path]\n );\n\n const fileContextValue = useMemo(() => ({ name, path }), [name, path]);\n\n return (\n <FileTreeFileContext.Provider value={fileContextValue}>\n <div\n className={cn(\n \"flex cursor-pointer items-center gap-1 rounded px-2 py-1 transition-colors hover:bg-muted/50\",\n isSelected && \"bg-muted\",\n className\n )}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n role=\"treeitem\"\n tabIndex={0}\n {...props}\n >\n {children ?? (\n <>\n {/* Spacer for alignment */}\n <span className=\"size-4 shrink-0\" />\n <FileTreeIcon>\n {icon ?? <FileIcon className=\"size-4 text-muted-foreground\" />}\n </FileTreeIcon>\n <FileTreeName>{name}</FileTreeName>\n </>\n )}\n </div>\n </FileTreeFileContext.Provider>\n );\n};\n\nexport type FileTreeActionsProps = HTMLAttributes<HTMLDivElement>;\n\nconst stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();\n\nexport const FileTreeActions = ({\n className,\n children,\n ...props\n}: FileTreeActionsProps) => (\n <div\n className={cn(\"ml-auto flex items-center gap-1\", className)}\n onClick={stopPropagation}\n onKeyDown={stopPropagation}\n role=\"group\"\n {...props}\n >\n {children}\n </div>\n);\n","// `<SandboxProvider>` — thin wrapper around @browsernode/react's\n// `<SandboxRuntime>` (the headless engine binding) that adds\n// elements-specific extras (theme, selectedPath, openTabs, activePanel)\n// and resolves the `framework` string (\"nextjs\" → nextjs()) plus the\n// default bundler.\n//\n// Lifecycle/sandbox management is delegated to @browsernode/react entirely.\n// Components inside elements should:\n// • read the sandbox via `useSandbox()` (re-exported from @browsernode/react)\n// • read elements extras via `useElementsContext()`\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n SandboxRuntime,\n type UseSandboxOptions,\n} from '@browsernode/react';\nimport { esbuild } from '@browsernode/esbuild-wasm';\nimport { nextjs } from '@browsernode/nextjs';\nimport { vite } from '@browsernode/sandbox/vite';\nimport type {\n BundlerAdapter,\n FrameworkAdapter,\n} from '@browsernode/sandbox';\n\nexport { useSandbox } from '@browsernode/react';\n\nexport type SandboxPanel = 'left' | 'top' | 'center' | 'bottom';\n\n/**\n * Resolved color scheme for elements that need light/dark variants\n * (e.g. `<CodeEditor>`'s syntax theme). Pass the resolved value from your\n * theme system — e.g. `next-themes`' `useTheme().resolvedTheme`. Defaults\n * to `'light'`.\n */\nexport type SandboxTheme = 'light' | 'dark';\n\nexport interface SandboxTab {\n path: string;\n label?: string;\n}\n\n/** Elements-specific extras: theme, file selection, open tabs. */\nexport interface ElementsContextValue {\n selectedPath: string | null;\n setSelectedPath(path: string | null): void;\n\n openTabs: SandboxTab[];\n openTab(tab: SandboxTab | string): void;\n closeTab(path: string): void;\n\n activePanel: SandboxPanel;\n setActivePanel(panel: SandboxPanel): void;\n\n theme: SandboxTheme;\n}\n\nconst ElementsContext = createContext<ElementsContextValue | null>(null);\n\nexport type SandboxProviderFramework = FrameworkAdapter | 'nextjs' | 'vite';\n\ninterface SandboxProviderBaseProps {\n children: ReactNode;\n initialActivePanel?: SandboxPanel;\n initialOpenTabs?: readonly (SandboxTab | string)[];\n initialSelectedPath?: string | null;\n theme?: SandboxTheme;\n}\n\nexport interface SandboxProviderProps\n extends SandboxProviderBaseProps,\n Omit<UseSandboxOptions, 'framework' | 'bundler'> {\n framework: SandboxProviderFramework;\n bundler?: BundlerAdapter;\n}\n\nfunction toTab(t: SandboxTab | string): SandboxTab {\n return typeof t === 'string' ? { path: t } : t;\n}\n\nfunction resolveFramework(framework: SandboxProviderFramework): FrameworkAdapter {\n if (framework === 'nextjs') return nextjs();\n if (framework === 'vite') return vite();\n if (typeof framework === 'string') {\n throw new Error(`Unsupported SandboxProvider framework \"${framework}\".`);\n }\n return framework;\n}\n\nexport function SandboxProvider({ children, ...props }: SandboxProviderProps) {\n const {\n initialActivePanel,\n initialOpenTabs,\n initialSelectedPath,\n theme,\n framework,\n bundler,\n ...sandboxOptions\n } = props;\n\n const options = useMemo<UseSandboxOptions>(\n () => ({\n ...sandboxOptions,\n framework: resolveFramework(framework),\n bundler: bundler ?? esbuild(),\n }),\n // The sandbox is created once on mount (managed by <SandboxRuntime>'s\n // useEffect deps); listing only framework/bundler here keeps the\n // ref-stable options object the way callers expect.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [framework, bundler],\n );\n\n return (\n <SandboxRuntime options={options}>\n <ElementsExtrasProvider\n initialActivePanel={initialActivePanel}\n initialOpenTabs={initialOpenTabs}\n initialSelectedPath={initialSelectedPath}\n theme={theme}\n >\n {children}\n </ElementsExtrasProvider>\n </SandboxRuntime>\n );\n}\n\ninterface ElementsExtrasProviderProps extends SandboxProviderBaseProps {}\n\nfunction ElementsExtrasProvider({\n children,\n initialActivePanel = 'center',\n initialOpenTabs = [],\n initialSelectedPath = null,\n theme = 'light',\n}: ElementsExtrasProviderProps) {\n const [selectedPath, setSelectedPath] = useState<string | null>(initialSelectedPath);\n const [openTabs, setOpenTabs] = useState<SandboxTab[]>(() =>\n initialOpenTabs.map(toTab),\n );\n const [activePanel, setActivePanel] = useState<SandboxPanel>(initialActivePanel);\n\n const openTab = useCallback((t: SandboxTab | string) => {\n const tab = toTab(t);\n setOpenTabs((prev) => {\n if (prev.some((x) => x.path === tab.path)) return prev;\n return [...prev, tab];\n });\n setSelectedPath(tab.path);\n }, []);\n\n const closeTab = useCallback((path: string) => {\n setOpenTabs((prev) => {\n const next = prev.filter((t) => t.path !== path);\n setSelectedPath((cur) => {\n if (cur !== path) return cur;\n const idx = prev.findIndex((t) => t.path === path);\n const fallback = next[idx - 1] ?? next[idx] ?? next[0] ?? null;\n return fallback?.path ?? null;\n });\n return next;\n });\n }, []);\n\n const extras = useMemo<ElementsContextValue>(\n () => ({\n selectedPath,\n setSelectedPath,\n openTabs,\n openTab,\n closeTab,\n activePanel,\n setActivePanel,\n theme,\n }),\n [selectedPath, openTabs, openTab, closeTab, activePanel, theme],\n );\n\n return <ElementsContext.Provider value={extras}>{children}</ElementsContext.Provider>;\n}\n\n/** Read elements-specific state (theme, selectedPath, openTabs). */\nexport function useElementsContext(): ElementsContextValue | null {\n return useContext(ElementsContext);\n}\n\nexport function useElementsContextOrThrow(): ElementsContextValue {\n const ctx = useContext(ElementsContext);\n if (!ctx) {\n throw new Error(\n 'useElementsContext() must be called inside <SandboxProvider> from @browsernode/elements.',\n );\n }\n return ctx;\n}\n","import { Button as ButtonPrimitive } from \"@base-ui/react/button\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../lib/utils\"\n\nconst buttonVariants = cva(\n \"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\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground [a]:hover:bg-primary/80\",\n outline:\n \"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\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground\",\n ghost:\n \"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50\",\n destructive:\n \"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\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default:\n \"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n 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\",\n 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\",\n lg: \"h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2\",\n icon: \"size-8\",\n \"icon-xs\":\n \"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n \"icon-sm\":\n \"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg\",\n \"icon-lg\": \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n ...props\n}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {\n return (\n <ButtonPrimitive\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import * as React from \"react\"\nimport { Popover as PopoverPrimitive } from \"@base-ui/react/popover\"\n\nimport { cn } from \"../lib/utils\"\n\nfunction Popover({ ...props }: PopoverPrimitive.Root.Props) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\n\nfunction PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\n\nfunction PopoverContent({\n className,\n align = \"center\",\n alignOffset = 0,\n side = \"bottom\",\n sideOffset = 4,\n ...props\n}: PopoverPrimitive.Popup.Props &\n Pick<\n PopoverPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <PopoverPrimitive.Popup\n data-slot=\"popover-content\"\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n </PopoverPrimitive.Positioner>\n </PopoverPrimitive.Portal>\n )\n}\n\nfunction PopoverHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n return (\n <div\n data-slot=\"popover-header\"\n className={cn(\"flex flex-col gap-0.5 text-sm\", className)}\n {...props}\n />\n )\n}\n\nfunction PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {\n return (\n <PopoverPrimitive.Title\n data-slot=\"popover-title\"\n className={cn(\"font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction PopoverDescription({\n className,\n ...props\n}: PopoverPrimitive.Description.Props) {\n return (\n <PopoverPrimitive.Description\n data-slot=\"popover-description\"\n className={cn(\"text-muted-foreground\", className)}\n {...props}\n />\n )\n}\n\nexport {\n Popover,\n PopoverContent,\n PopoverDescription,\n PopoverHeader,\n PopoverTitle,\n PopoverTrigger,\n}\n","// Shared tree builders for SandboxIDEFiles. Consumes a flat list of\n// absolute paths from `sandbox.fs.list()` and produces nodes the\n// FileTree primitive renders.\n\nimport type { ReactNode } from 'react';\nimport { FileTreeFile, FileTreeFolder } from '../primitives/file-tree';\n\ninterface TreeNode {\n name: string;\n path: string;\n /** null = file leaf. */\n children: Map<string, TreeNode> | null;\n}\n\nexport function buildTree(paths: string[]): TreeNode {\n const root: TreeNode = { name: '', path: '', children: new Map() };\n for (const path of paths) {\n const parts = path.split('/').filter(Boolean);\n let cur = root;\n for (let i = 0; i < parts.length; i++) {\n const name = parts[i]!;\n const isLeaf = i === parts.length - 1;\n // Tree paths are absolute (`/src/app/page.tsx`) so they match\n // `sandbox.fs.list()` output and `selectedPath` flows through\n // `fs.readFile` consistently.\n const childPath = '/' + parts.slice(0, i + 1).join('/');\n if (!cur.children) break;\n let child = cur.children.get(name);\n if (!child) {\n child = { name, path: childPath, children: isLeaf ? null : new Map() };\n cur.children.set(name, child);\n }\n if (!isLeaf && child.children) cur = child;\n else if (!isLeaf && !child.children) break; // path collision\n }\n }\n return root;\n}\n\nexport function renderTree(node: TreeNode): ReactNode {\n if (!node.children) return null;\n // Folders first, then files; alphabetical within each group.\n const entries = Array.from(node.children.values()).sort((a, b) => {\n const aFolder = a.children !== null;\n const bFolder = b.children !== null;\n if (aFolder !== bFolder) return aFolder ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n return entries.map((entry) =>\n entry.children ? (\n <FileTreeFolder key={entry.path} name={entry.name} path={entry.path}>\n {renderTree(entry)}\n </FileTreeFolder>\n ) : (\n <FileTreeFile key={entry.path} name={entry.name} path={entry.path} />\n ),\n );\n}\n\nexport function isFile(path: string, files: string[]): boolean {\n return files.includes(path);\n}\n\nexport function defaultExpansion(files: string[]): Set<string> {\n const roots = ['src', 'app', 'pages', 'components'];\n const expanded = new Set<string>();\n for (const root of roots) {\n const abs = '/' + root;\n if (files.some((f) => f === abs || f.startsWith(`${abs}/`))) {\n expanded.add(abs);\n }\n }\n return expanded;\n}\n","// `<SandboxCodeEditor>` — header chrome (filename + Save + More dropdown)\n// + a buffered CodeMirror editor. Reads `selectedPath` from elements\n// context; loads file contents on selection change; persists via\n// `sandbox.fs.writeFile` on Save (button or Cmd/Ctrl+S).\n//\n// CodeMirror knobs (theme, basicSetup, extensions, language) are passed\n// straight through to the underlying `<CodeEditor>` so callers can tune\n// the editor without dropping down a level.\n\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { MoreHorizontalIcon } from 'lucide-react';\nimport type { Extension } from '@codemirror/state';\nimport { keymap } from '@codemirror/view';\nimport type { ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport type { Sandbox } from '@browsernode/sandbox';\nimport {\n CodeEditor,\n type CodeEditorLanguage,\n type CodeEditorTheme,\n} from './primitives/code-editor';\nimport { Button } from '../primitives/ui/button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n} from '../primitives/ui/dropdown-menu';\nimport { Loader } from '../primitives/ui/loading';\nimport { useElementsContext, useSandbox } from '../provider/sandbox-provider';\nimport { guessLanguage } from './internal/language';\n\nexport interface SandboxCodeEditorProps {\n /** Override the sandbox from the surrounding `<SandboxProvider>`. */\n sandbox?: Sandbox | null;\n /** Disable saves (Save button hidden, Cmd-S no-op). Default false. */\n readOnly?: boolean;\n /** CodeMirror theme override (forwarded to `<CodeEditor>`). */\n theme?: CodeEditorTheme;\n /** CodeMirror basic-setup overrides (line numbers, fold gutter, etc.). */\n basicSetup?: ReactCodeMirrorProps['basicSetup'];\n /** Extra CodeMirror extensions appended after the language ones. */\n extensions?: Extension[];\n /** Force a CodeMirror language regardless of file extension. */\n language?: CodeEditorLanguage;\n /** Hide the file header (filename + dirty dot + Save + More). */\n hideHeader?: boolean;\n /** Custom empty state when no file is selected. */\n emptyState?: ReactNode;\n /**\n * Slot rendered inside the header, immediately after the filename and\n * before the Save button. Used by `<SandboxIDELayout>` to inject the\n * mobile dropdown trigger; consumers can use it for any leading chrome.\n */\n headerStartSlot?: ReactNode;\n className?: string;\n}\n\ntype SaveStatus = 'idle' | 'saving' | 'saved' | 'error';\n\nexport function SandboxCodeEditor({\n sandbox: sandboxProp,\n readOnly = false,\n theme,\n basicSetup,\n extensions,\n language: languageProp,\n hideHeader = false,\n emptyState,\n headerStartSlot,\n className,\n}: SandboxCodeEditorProps) {\n const elementsCtx = useElementsContext();\n const sandboxState = useSandbox();\n const sandbox = sandboxProp ?? sandboxState.sandbox;\n\n const selectedPath = elementsCtx?.selectedPath ?? null;\n const setSelectedPath = elementsCtx?.setSelectedPath;\n\n const [savedText, setSavedText] = useState<string | null>(null);\n const [buffer, setBuffer] = useState<string>('');\n const [loadingPath, setLoadingPath] = useState<string | null>(null);\n const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle');\n\n // Path the editor's current `buffer` was loaded from. Used to ignore\n // stale onChange callbacks during file-switch (CodeMirror's controlled\n // value briefly lags one frame).\n const loadedPathRef = useRef<string | null>(null);\n const savedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Refs for stable callbacks (Cmd-S keymap, delete handler).\n const sandboxRef = useRef(sandbox);\n const selectedPathRef = useRef(selectedPath);\n const bufferRef = useRef(buffer);\n const dirtyRef = useRef(false);\n sandboxRef.current = sandbox;\n selectedPathRef.current = selectedPath;\n bufferRef.current = buffer;\n\n useEffect(() => {\n if (!sandbox || !selectedPath) {\n setSavedText(null);\n setBuffer('');\n loadedPathRef.current = null;\n return;\n }\n setLoadingPath(selectedPath);\n setSaveStatus('idle');\n let cancelled = false;\n sandbox.fs\n .readFile(selectedPath)\n .then((c) => {\n if (cancelled) return;\n setSavedText(c);\n setBuffer(c);\n loadedPathRef.current = selectedPath;\n setLoadingPath(null);\n })\n .catch(() => {\n if (cancelled) return;\n const fallback = `// Could not read ${selectedPath}`;\n setSavedText(fallback);\n setBuffer(fallback);\n loadedPathRef.current = null;\n setLoadingPath(null);\n });\n return () => {\n cancelled = true;\n };\n }, [sandbox, selectedPath]);\n\n useEffect(() => {\n return () => {\n if (savedTimerRef.current) {\n clearTimeout(savedTimerRef.current);\n savedTimerRef.current = null;\n }\n };\n }, [selectedPath]);\n\n const handleEditorChange = useCallback(\n (next: string) => {\n setBuffer(next);\n if (readOnly) return;\n if (!selectedPath) return;\n // Drop changes fired before the load has settled on this path.\n if (loadedPathRef.current !== selectedPath) return;\n },\n [readOnly, selectedPath],\n );\n\n const dirty = !readOnly && savedText !== null && buffer !== savedText;\n dirtyRef.current = dirty;\n\n const deleteFile = useCallback(async () => {\n if (readOnly) return;\n const sb = sandboxRef.current;\n const path = selectedPathRef.current;\n if (!sb || !path) return;\n try {\n await sb.fs.rm(path);\n setSelectedPath?.(null);\n } catch {\n // Surfaces via sandbox.on('error') if anyone's listening.\n }\n }, [readOnly, setSelectedPath]);\n\n const save = useCallback(async () => {\n if (readOnly) return;\n const sb = sandboxRef.current;\n const path = selectedPathRef.current;\n const text = bufferRef.current;\n if (!sb || !path) return;\n if (!dirtyRef.current) return;\n // The in-memory write resolves the same microtask, so React would\n // batch this with the 'saved' set below and never paint the spinner.\n // The minimum-duration delay below holds the spinner visible long\n // enough to register visually.\n setSaveStatus('saving');\n try {\n await sb.fs.writeFile(path, text);\n await new Promise((r) => setTimeout(r, 500));\n setSavedText(text);\n setSaveStatus('idle');\n } catch {\n setSaveStatus('error');\n }\n }, [readOnly]);\n\n // Cmd/Ctrl+S keybinding. Stable extension array so we don't rebuild\n // CodeMirror on every keystroke.\n const editorExtensions = useMemo<Extension[]>(\n () => {\n const base = [\n keymap.of([\n {\n key: 'Mod-s',\n preventDefault: true,\n run: () => {\n void save();\n return true;\n },\n },\n ]),\n ];\n return extensions ? [...base, ...extensions] : base;\n },\n [save, extensions],\n );\n\n const lang: CodeEditorLanguage = languageProp\n ? languageProp\n : selectedPath\n ? guessLanguage(selectedPath)\n : 'plaintext';\n\n // Always render the outer column + header, even with no file selected,\n // so callers' `headerStartSlot` (typically the file-tree dropdown\n // trigger) stays reachable. Otherwise the user would be locked out of\n // the picker on mobile.\n //\n // When a slot is provided AND no file is selected, the slot owns the\n // empty-state messaging (e.g. the dropdown trigger reads \"Select a\n // file\"). We don't add a separate label so the text isn't duplicated.\n // Show just the basename in the header — full paths get long fast and\n // crowd out the Save/More buttons. Hover/title still exposes the full\n // path for orientation.\n const filename = selectedPath\n ? selectedPath.split('/').filter(Boolean).pop() ?? selectedPath\n : null;\n const headerLabel = selectedPath ? (\n <span className=\"font-mono\" title={selectedPath}>\n {filename}\n </span>\n ) : headerStartSlot ? null : (\n <span>Select a file</span>\n );\n\n return (\n <div className={`flex h-full w-full flex-col ${className ?? ''}`.trim()}>\n {!hideHeader && (\n <div className=\"flex flex-none items-center justify-between border-b px-3 py-2 text-xs\">\n <div className=\"flex items-center gap-1.5 text-muted-foreground\">\n {headerStartSlot}\n {headerLabel}\n </div>\n {selectedPath && !readOnly && (\n <div className=\"flex items-center gap-1\">\n <Button\n size=\"sm\"\n onClick={() => void save()}\n className=\"h-9 px-4 text-sm md:h-8 md:px-3 md:text-xs\"\n >\n {saveStatus === 'saving' ? (\n <>\n <Loader size={14} />\n Saving...\n </>\n ) : (\n 'Save'\n )}\n </Button>\n <DropdownMenu>\n <DropdownMenuTrigger\n render={\n <Button\n size=\"sm\"\n variant=\"ghost\"\n aria-label=\"File actions\"\n className=\"size-10 p-0 md:size-8\"\n />\n }\n >\n <MoreHorizontalIcon className=\"size-4\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem\n onClick={() => void deleteFile()}\n className=\"text-destructive focus:text-destructive\"\n >\n Delete\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </div>\n )}\n </div>\n )}\n <div className=\"flex-1 min-h-0 overflow-auto\">\n {selectedPath ? (\n <CodeEditor\n key={selectedPath}\n value={buffer}\n onChange={handleEditorChange}\n language={lang}\n theme={theme}\n basicSetup={basicSetup}\n readOnly={readOnly || loadingPath === selectedPath}\n extensions={editorExtensions}\n height=\"100%\"\n className=\"h-full text-sm\"\n />\n ) : (\n emptyState ?? (\n <div className=\"flex h-full w-full items-center justify-center text-muted-foreground text-sm\">\n Select a file from the menu\n </div>\n )\n )}\n </div>\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport CodeMirror, {\n EditorView,\n type Extension,\n type ReactCodeMirrorProps,\n} from '@uiw/react-codemirror';\nimport { javascript } from '@codemirror/lang-javascript';\nimport { css } from '@codemirror/lang-css';\nimport { html } from '@codemirror/lang-html';\nimport { json } from '@codemirror/lang-json';\nimport { markdown } from '@codemirror/lang-markdown';\nimport { useElementsContext } from '../../provider/sandbox-provider';\n\nexport type CodeEditorLanguage =\n | 'typescript'\n | 'tsx'\n | 'javascript'\n | 'jsx'\n | 'css'\n | 'html'\n | 'json'\n | 'markdown'\n | 'plaintext';\n\nexport type CodeEditorTheme = 'light' | 'dark' | Extension;\n\nexport interface CodeEditorProps\n extends Omit<\n ReactCodeMirrorProps,\n 'value' | 'onChange' | 'extensions' | 'theme'\n > {\n value: string;\n onChange?: (next: string) => void;\n language?: CodeEditorLanguage;\n /**\n * Editor color scheme. If omitted, falls back to `<SandboxProvider>`'s\n * `theme` (or `'light'` when no provider is mounted). Pass an\n * `Extension` to fully override CodeMirror's theme system.\n */\n theme?: CodeEditorTheme;\n /** Extra CodeMirror extensions appended to the language-derived ones. */\n extensions?: Extension[];\n className?: string;\n}\n\n/**\n * `<CodeEditor>` — thin CodeMirror 6 wrapper. Pass `value` + `onChange`\n * for controlled editing; `language` selects the syntax extension.\n *\n * The host is responsible for debouncing writes back to disk; this\n * component fires `onChange` for every keystroke.\n */\nexport function CodeEditor({\n value,\n onChange,\n language = 'plaintext',\n theme,\n extensions: extraExtensions,\n className,\n basicSetup,\n ...rest\n}: CodeEditorProps) {\n const ctx = useElementsContext();\n const resolvedTheme: CodeEditorTheme = theme ?? ctx?.theme ?? 'light';\n\n const extensions = useMemo<Extension[]>(() => {\n const langExt = languageExtension(language);\n const wrap = EditorView.lineWrapping;\n const base: Extension[] = [wrap];\n if (langExt) base.push(langExt);\n return extraExtensions ? [...base, ...extraExtensions] : base;\n }, [language, extraExtensions]);\n\n return (\n <CodeMirror\n value={value}\n onChange={onChange}\n extensions={extensions}\n theme={resolvedTheme}\n basicSetup={\n basicSetup ?? {\n lineNumbers: true,\n highlightActiveLine: true,\n highlightActiveLineGutter: true,\n foldGutter: true,\n autocompletion: true,\n bracketMatching: true,\n closeBrackets: true,\n indentOnInput: true,\n searchKeymap: true,\n }\n }\n className={className}\n {...rest}\n />\n );\n}\n\nfunction languageExtension(lang: CodeEditorLanguage): Extension | null {\n switch (lang) {\n case 'typescript':\n return javascript({ typescript: true });\n case 'tsx':\n return javascript({ typescript: true, jsx: true });\n case 'javascript':\n return javascript();\n case 'jsx':\n return javascript({ jsx: true });\n case 'css':\n return css();\n case 'html':\n return html();\n case 'json':\n return json();\n case 'markdown':\n return markdown();\n case 'plaintext':\n default:\n return null;\n }\n}\n","\"use client\"\n\nimport * as React from \"react\"\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\n\nimport { cn } from \"../lib/utils\"\nimport { ChevronRightIcon, CheckIcon } from \"lucide-react\"\n\nfunction DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {\n return <MenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\n\nfunction DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {\n return <MenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n}\n\nfunction DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {\n return <MenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />\n}\n\nfunction DropdownMenuContent({\n align = \"start\",\n alignOffset = 0,\n side = \"bottom\",\n sideOffset = 4,\n className,\n ...props\n}: MenuPrimitive.Popup.Props &\n Pick<\n MenuPrimitive.Positioner.Props,\n \"align\" | \"alignOffset\" | \"side\" | \"sideOffset\"\n >) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner\n className=\"isolate z-50 outline-none\"\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n >\n <MenuPrimitive.Popup\n data-slot=\"dropdown-menu-content\"\n 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 )}\n {...props}\n />\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n )\n}\n\nfunction DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {\n return <MenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n}\n\nfunction DropdownMenuLabel({\n className,\n inset,\n ...props\n}: MenuPrimitive.GroupLabel.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.GroupLabel\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(\n \"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: MenuPrimitive.Item.Props & {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}) {\n return (\n <MenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"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\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {\n return <MenuPrimitive.SubmenuRoot data-slot=\"dropdown-menu-sub\" {...props} />\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: MenuPrimitive.SubmenuTrigger.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.SubmenuTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"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-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto\" />\n </MenuPrimitive.SubmenuTrigger>\n )\n}\n\nfunction DropdownMenuSubContent({\n align = \"start\",\n alignOffset = -3,\n side = \"right\",\n sideOffset = 0,\n className,\n ...props\n}: React.ComponentProps<typeof DropdownMenuContent>) {\n return (\n <DropdownMenuContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\"w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 data-[side=bottom]:slide-in-from-top-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\", className )}\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuCheckboxItem({\n className,\n children,\n checked,\n inset,\n ...props\n}: MenuPrimitive.CheckboxItem.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n data-inset={inset}\n className={cn(\n \"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-checkbox-item-indicator\"\n >\n <MenuPrimitive.CheckboxItemIndicator>\n <CheckIcon\n />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n )\n}\n\nfunction DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {\n return (\n <MenuPrimitive.RadioGroup\n data-slot=\"dropdown-menu-radio-group\"\n {...props}\n />\n )\n}\n\nfunction DropdownMenuRadioItem({\n className,\n children,\n inset,\n ...props\n}: MenuPrimitive.RadioItem.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n data-inset={inset}\n className={cn(\n \"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span\n className=\"pointer-events-none absolute right-2 flex items-center justify-center\"\n data-slot=\"dropdown-menu-radio-item-indicator\"\n >\n <MenuPrimitive.RadioItemIndicator>\n <CheckIcon\n />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n )\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: MenuPrimitive.Separator.Props) {\n return (\n <MenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n )\n}\n\nfunction DropdownMenuShortcut({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(\n \"ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n","import type { HTMLAttributes } from 'react';\nimport { cn } from '../lib/utils';\n\ninterface LoaderIconProps {\n size?: number;\n}\n\nconst LoaderIcon = ({ size = 16 }: LoaderIconProps) => (\n <svg\n height={size}\n strokeLinejoin=\"round\"\n style={{ color: 'currentcolor' }}\n viewBox=\"0 0 16 16\"\n width={size}\n >\n <title>Loader</title>\n <g clipPath=\"url(#clip0_2393_1490)\">\n <path d=\"M8 0V4\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n <path\n d=\"M8 16V12\"\n opacity=\"0.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M3.29773 1.52783L5.64887 4.7639\"\n opacity=\"0.9\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M12.7023 1.52783L10.3511 4.7639\"\n opacity=\"0.1\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M12.7023 14.472L10.3511 11.236\"\n opacity=\"0.4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M3.29773 14.472L5.64887 11.236\"\n opacity=\"0.6\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M15.6085 5.52783L11.8043 6.7639\"\n opacity=\"0.2\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M0.391602 10.472L4.19583 9.23598\"\n opacity=\"0.7\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M15.6085 10.4722L11.8043 9.2361\"\n opacity=\"0.3\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n <path\n d=\"M0.391602 5.52783L4.19583 6.7639\"\n opacity=\"0.8\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n />\n </g>\n <defs>\n <clipPath id=\"clip0_2393_1490\">\n <rect fill=\"white\" height=\"16\" width=\"16\" />\n </clipPath>\n </defs>\n </svg>\n);\n\nexport type LoaderProps = HTMLAttributes<HTMLDivElement> & {\n size?: number;\n};\n\nexport const Loader = ({ className, size = 16, ...props }: LoaderProps) => (\n <div\n className={cn(\n 'inline-flex animate-spin items-center justify-center',\n className,\n )}\n {...props}\n >\n <LoaderIcon size={size} />\n </div>\n);\n","// File-extension → CodeMirror language id. Kept as a tiny static map;\n// CodeEditor handles the language extension for each id.\n\nimport type { CodeEditorLanguage } from '../primitives/code-editor';\n\nconst EXT_TO_LANG: Record<string, CodeEditorLanguage> = {\n ts: 'typescript',\n tsx: 'tsx',\n js: 'javascript',\n jsx: 'jsx',\n mjs: 'javascript',\n cjs: 'javascript',\n json: 'json',\n md: 'markdown',\n mdx: 'markdown',\n css: 'css',\n scss: 'css',\n html: 'html',\n htm: 'html',\n};\n\nexport function guessLanguage(path: string): CodeEditorLanguage {\n const m = path.match(/\\.([^.]+)$/);\n if (!m) return 'plaintext';\n const ext = m[1]!.toLowerCase();\n return EXT_TO_LANG[ext] ?? 'plaintext';\n}\n","// `<SandboxIDE>` — responsive composition of `<SandboxFileTree>` and\n// `<SandboxCodeEditor>`.\n//\n// • md+ side-by-side: file tree as a 64-wide left column.\n// • below md stacked: a hamburger-icon trigger sits inside the\n// code-editor header next to the filename, opening a\n// popover with the tree (via\n// `<SandboxFileTree display=\"dropdown\" />`).\n//\n// CSS-driven (Tailwind's `md:` prefix); no JS resize listeners. Both\n// trees stay mounted across breakpoint changes — both are bound to the\n// same `selectedPath` in elements context, so selection is consistent.\n\nimport { type CSSProperties } from 'react';\nimport type { Sandbox } from '@browsernode/sandbox';\nimport { SandboxFileTree } from './sandbox-file-tree';\nimport {\n SandboxCodeEditor,\n type SandboxCodeEditorProps,\n} from './sandbox-code-editor';\n\nexport interface SandboxIDEProps\n extends Omit<SandboxCodeEditorProps, 'headerStartSlot' | 'className'> {\n /** Override the sandbox from the surrounding `<SandboxProvider>`. */\n sandbox?: Sandbox | null;\n /** Initial folders to expand (forwarded to `<SandboxFileTree>`). */\n defaultExpanded?: Set<string>;\n /** Hide the file tree entirely (editor-only layout). */\n hideTree?: boolean;\n /** Hide the code editor entirely (tree-only layout). */\n hideViewer?: boolean;\n /**\n * Drop the rounded-lg + border on the outer wrapper. Use when embedded\n * inside a host frame that already provides chrome (e.g. inside\n * `<Sandbox>`).\n */\n hideBorder?: boolean;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function SandboxIDE({\n sandbox,\n defaultExpanded,\n hideTree = false,\n hideViewer = false,\n hideBorder = false,\n className,\n style,\n ...codeProps\n}: SandboxIDEProps) {\n // Tree-only layout — just render files directly.\n if (hideViewer) {\n return (\n <SandboxFileTree\n sandbox={sandbox}\n defaultExpanded={defaultExpanded}\n className={className}\n />\n );\n }\n\n // Editor-only layout — just render code, no tree (mobile or otherwise).\n if (hideTree) {\n return (\n <SandboxCodeEditor\n sandbox={sandbox}\n className={className}\n {...codeProps}\n />\n );\n }\n\n const frameClasses = hideBorder\n ? 'flex h-full w-full flex-col md:flex-row overflow-hidden bg-background'\n : 'flex h-full w-full flex-col md:flex-row overflow-hidden rounded-lg border bg-background';\n\n // Mobile-only file-picker trigger lives inside the code-editor header,\n // collapsing the would-be \"dropdown row\" into the same row as the\n // filename. Hidden at md+ where the sidebar tree is the picker. The\n // default trigger label adapts to selection state — \"[☰] Select a\n // file\" when empty, just \"[☰]\" when a file is loaded.\n const mobileTrigger = (\n <SandboxFileTree\n sandbox={sandbox}\n defaultExpanded={defaultExpanded}\n display=\"dropdown\"\n className=\"md:hidden -ml-1\"\n />\n );\n\n return (\n <div className={`${frameClasses} ${className ?? ''}`.trim()} style={style}>\n {/* Desktop-only: sidebar tree on the left. Hidden below md. Block\n (not flex) so the tree fills the column width to the divider. */}\n <div className=\"hidden md:block w-64 shrink-0 overflow-auto border-r\">\n <SandboxFileTree sandbox={sandbox} defaultExpanded={defaultExpanded} />\n </div>\n\n <div className=\"flex-1 min-w-0 overflow-hidden\">\n <SandboxCodeEditor\n sandbox={sandbox}\n headerStartSlot={mobileTrigger}\n {...codeProps}\n />\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useMemo","useState","jsx","createContext","useCallback","useContext","useMemo","useState","jsx","useContext","jsx","jsx","jsx","Fragment","jsx","jsxs","useState","useMemo","useCallback","useEffect","useMemo","useState","useMemo","jsx","useMemo","ChevronRightIcon","jsx","jsxs","jsx","jsx","jsx","jsxs","Fragment","jsx","jsxs","useState","useEffect","useCallback","useMemo","jsx","jsxs"]}
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@browsernode/react";
|
|
12
12
|
import { esbuild } from "@browsernode/esbuild-wasm";
|
|
13
13
|
import { nextjs } from "@browsernode/nextjs";
|
|
14
|
+
import { vite } from "@browsernode/sandbox/vite";
|
|
14
15
|
import { useSandbox } from "@browsernode/react";
|
|
15
16
|
import { jsx } from "react/jsx-runtime";
|
|
16
17
|
var ElementsContext = createContext(null);
|
|
@@ -19,6 +20,7 @@ function toTab(t) {
|
|
|
19
20
|
}
|
|
20
21
|
function resolveFramework(framework) {
|
|
21
22
|
if (framework === "nextjs") return nextjs();
|
|
23
|
+
if (framework === "vite") return vite();
|
|
22
24
|
if (typeof framework === "string") {
|
|
23
25
|
throw new Error(`Unsupported SandboxProvider framework "${framework}".`);
|
|
24
26
|
}
|