@joycostudio/studio 0.1.3 → 0.1.4

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/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/react/studio.tsx","../package.json","../src/client/studio.ts","../src/react/hooks.ts","../src/react/inspector.tsx","../src/react/theme.ts","../src/react/tool-icon.tsx","../src/react/ui/button.tsx","../src/react/ui/utils.ts","../src/react/ui/kbd.tsx","../src/react/ui/tooltip.tsx","../src/react/ui/panel.tsx","../src/react/surface.tsx","../src/react/logo.tsx","../src/react/pinned-tools.ts","../src/react/preview-canvas.tsx","../src/react/canvas-toolbar.tsx","../src/react/session-flag.ts","../src/react/ui/sidebar.tsx","../src/react/ui/hooks/use-mobile.ts","../src/react/ui/sheet.tsx","../src/react/command-menu.tsx","../src/react/ui/command.tsx","../src/react/select.tsx","../src/react/ui/input.tsx"],"sourcesContent":["import {\n ChevronLeft,\n ChevronRight,\n LoaderCircle,\n PanelLeftClose,\n PanelLeftOpen,\n Pin,\n PlugZap,\n Unplug,\n type LucideIcon,\n} from 'lucide-react'\nimport { useEffect, useRef, useState, type ComponentPropsWithRef, type ComponentType } from 'react'\nimport { version } from '../../package.json'\nimport type { Connection } from '../client/bridge'\nimport { postCompare, type Studio as StudioClient } from '../client/studio'\nimport { useStudio } from './hooks'\nimport { Inspector } from './inspector'\nimport { Logo } from './logo'\nimport { usePinnedTools } from './pinned-tools'\nimport { PreviewCanvas } from './preview-canvas'\nimport { useSessionFlag } from './session-flag'\nimport { ToolIcon } from './tool-icon'\nimport { Button } from './ui/button'\nimport { Kbd, KbdGroup } from './ui/kbd'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarProvider,\n useSidebar,\n} from './ui/sidebar'\nimport { Hint } from './ui/tooltip'\nimport { Panel } from './ui/panel'\nimport { cn } from './ui/utils'\n\nconst CONNECTION: Record<Connection['phase'], { icon: LucideIcon; tone: string; label: string }> = {\n connected: { icon: PlugZap, tone: 'text-success', label: 'Runtime connected' },\n connecting: { icon: LoaderCircle, tone: 'text-warning animate-spin', label: 'Connecting to runtime' },\n offline: { icon: Unplug, tone: 'text-destructive', label: 'Runtime offline' },\n local: { icon: Unplug, tone: 'text-faint', label: 'No runtime' },\n}\n\n/** Bottom of the sidebar: runtime status and the collapse toggle, both readable as icons when collapsed. */\nfunction StudioFooter({ connection }: { connection: Connection }) {\n const { state, toggleSidebar } = useSidebar()\n const { icon: Status, tone, label } = CONNECTION[connection.phase]\n const Toggle = state === 'expanded' ? PanelLeftClose : PanelLeftOpen\n return (\n <SidebarFooter>\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton tooltip={label} className=\"cursor-default hover:bg-transparent active:bg-transparent\">\n <Status className={tone} />\n <span className=\"text-clip! group-data-[collapsible=icon]:hidden\">{label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n <SidebarMenuItem>\n <SidebarMenuButton\n aria-label={`${state === 'expanded' ? 'Collapse' : 'Expand'} sidebar`}\n tooltip={`${state === 'expanded' ? 'Collapse' : 'Expand'} sidebar`}\n onClick={toggleSidebar}\n >\n <Toggle />\n <span className=\"text-clip! group-data-[collapsible=icon]:hidden\">Collapse</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarFooter>\n )\n}\n\n/** ⌘/Ctrl shortcuts: B toggles both panels, S saves, K opens the host's tool menu. */\nconst SHORTCUTS = new Set(['b', 's', 'k'])\n/** Hold to show the saved config instead of the draft (Lightroom's before/after key). */\nconst COMPARE_KEY = '\\\\'\n\n// Duck-typed: keys pressed in the preview target the iframe window's own Element class.\nconst editable = (target: EventTarget | null) =>\n !!(target as Partial<Element> | null)?.matches?.('input, textarea, select, [contenteditable]')\n\n/** ⌘/Ctrl+Z undoes; ⌘/Ctrl+Y or ⌘/Ctrl+Shift+Z redoes. Text fields keep their own native undo. */\nconst historyAction = (event: KeyboardEvent) => {\n if (!(event.metaKey || event.ctrlKey) || event.altKey || editable(event.target)) return null\n const key = event.key.toLowerCase()\n return key === 'z' ? (event.shiftKey ? 'redo' : 'undo') : key === 'y' ? 'redo' : null\n}\n\nconst isShortcut = (event: KeyboardEvent) =>\n ((event.metaKey || event.ctrlKey) && SHORTCUTS.has(event.key.toLowerCase())) ||\n (event.key === COMPARE_KEY && !editable(event.target)) ||\n !!historyAction(event)\n\n/**\n * Keys pressed inside the preview go to the iframe's window, not Studio's. Re-dispatch Studio's\n * shortcuts on the parent window so they work wherever focus is (same-origin previews only).\n */\nfunction forwardShortcuts(frame: HTMLIFrameElement) {\n const forward = (event: KeyboardEvent) => {\n if (event.defaultPrevented || !isShortcut(event)) return\n event.preventDefault()\n window.dispatchEvent(new KeyboardEvent(event.type, event))\n }\n try {\n frame.contentWindow?.addEventListener('keydown', forward)\n frame.contentWindow?.addEventListener('keyup', forward)\n } catch {\n // Cross-origin preview: its keys stay its own.\n }\n}\n\nexport interface StudioProps {\n studio: StudioClient\n /** Forward the iframe ref and native props to preserve Studio shortcuts and compare. */\n previewComponent?: ComponentType<ComponentPropsWithRef<'iframe'>> | 'iframe'\n /** Resolve config paths using the host's editor URL or source browser. */\n getConfigFileHref?: (file: string) => string\n}\n\n/** The /studio route: every registered tool, its preview, and its Tweakpane inspector. */\nexport function Studio({ studio, previewComponent, getConfigFileHref }: StudioProps) {\n useStudio(studio)\n const { tools, pinned, togglePin } = usePinnedTools(studio)\n // Connection and draft state only exist in the browser; skip SSR so hydration never disagrees.\n const [mounted, setMounted] = useState(false)\n // Layout survives a refresh in this tab: each hidden panel and the expanded canvas.\n const [sidebarHidden, setSidebarHidden] = useSessionFlag('joyco-studio:sidebar-hidden')\n const [inspectorHidden, setInspectorHidden] = useSessionFlag('joyco-studio:inspector-hidden')\n const [canvasExpanded, setCanvasExpanded] = useSessionFlag('joyco-studio:canvas-expanded')\n const [selected, setSelected] = useState<string | undefined>(studio.definitions[0]?.id)\n const preview = useRef<HTMLIFrameElement>(null)\n const definition = studio.definitions.find((tool) => tool.id === selected)\n // Preview-only tools have no handle, so nothing below compares, undoes, or inspects them.\n const handle = studio.tools.find((tool) => tool.definition.id === selected)\n const Preview = previewComponent ?? (definition?.previewLayout === 'custom' ? 'iframe' : PreviewCanvas)\n // Preview-only tools have no inspector to show, whatever its flag says.\n const hidden = { left: sidebarHidden, right: inspectorHidden || !handle }\n const show = { left: () => setSidebarHidden(false), right: () => setInspectorHidden(false) }\n const layout = useRef(hidden)\n layout.current = hidden\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.isComposing || event.altKey || !(event.metaKey || event.ctrlKey)) return\n if (event.key.toLowerCase() !== 'b') return\n event.preventDefault()\n if (event.repeat) return\n // Hidden panels stay mounted to preserve controls, but must release keyboard focus.\n const active = document.activeElement\n if (\n active instanceof HTMLElement &&\n active.closest('[data-slot=\"sidebar-container\"], [data-slot=\"studio-inspector\"]')\n ) {\n active.blur()\n preview.current?.focus()\n }\n // Hide whatever is open; with both hidden, bring both back.\n const hide = !layout.current.left || !layout.current.right\n setSidebarHidden(hide)\n setInspectorHidden(hide)\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [])\n\n /** Compare here and in the preview iframe, which runs its own studio client. */\n const compare = (showSaved: boolean) => {\n if (!handle) return\n handle.compare(showSaved)\n postCompare(preview.current?.contentWindow, handle.definition.id, showSaved)\n }\n\n // Switching tools mid-compare must not leave the previous one showing its saved config.\n useEffect(() => () => handle?.compare(false), [handle])\n\n // Listeners live for the whole mount; they read the current tool through a ref so a re-render\n // (which comparing itself causes) never tears them down mid-hold.\n const current = useRef({ handle, compare })\n current.current = { handle, compare }\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== COMPARE_KEY || editable(event.target) || event.repeat) return\n event.preventDefault()\n const { handle, compare } = current.current\n compare(event.type === 'keydown' && !!handle?.dirty)\n }\n const release = () => current.current.compare(false)\n addEventListener('keydown', onKey)\n addEventListener('keyup', onKey)\n addEventListener('blur', release)\n return () => {\n release()\n removeEventListener('keydown', onKey)\n removeEventListener('keyup', onKey)\n removeEventListener('blur', release)\n }\n }, [])\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n const action = event.defaultPrevented ? null : historyAction(event)\n if (!action) return\n event.preventDefault()\n current.current.handle?.[action]()\n }\n addEventListener('keydown', onKey)\n return () => removeEventListener('keydown', onKey)\n }, [])\n\n useEffect(() => {\n const fromHash = () => {\n const id = decodeURIComponent(location.hash.slice(1))\n if (studio.definitions.some((tool) => tool.id === id)) setSelected(id)\n }\n setMounted(true)\n fromHash()\n addEventListener('hashchange', fromHash)\n return () => removeEventListener('hashchange', fromHash)\n }, [studio])\n\n if (!mounted) return null\n // shadcn's sidebar persists its state in a cookie; Studio renders client-only, so read it here.\n const sidebarOpen = !document.cookie.split('; ').includes('sidebar_state=false')\n\n return (\n <SidebarProvider\n defaultOpen={sidebarOpen}\n data-preview-layout={previewComponent ? 'canvas' : (definition?.previewLayout ?? 'canvas')}\n data-sidebar-panel={hidden.left ? 'hidden' : 'shown'}\n className=\"studio-workspace relative h-svh min-h-0 overflow-hidden text-xs\"\n >\n {definition?.preview ? (\n <Preview\n data-slot=\"studio-preview\"\n ref={preview}\n key={definition.id}\n src={definition.preview}\n title={definition.title ?? definition.id}\n onLoad={(event) => forwardShortcuts(event.currentTarget)}\n {...(Preview === PreviewCanvas && { expanded: canvasExpanded, onExpandedChange: setCanvasExpanded })}\n />\n ) : (\n <div className=\"absolute inset-0 grid place-items-center text-faint\">\n {definition ? 'This tool has no preview' : 'No tools registered'}\n </div>\n )}\n\n {(['left', 'right'] as const)\n .filter((side) => hidden[side] && (side === 'left' || handle))\n .map((side) => {\n const Chevron = side === 'left' ? ChevronRight : ChevronLeft\n const label = side === 'left' ? 'Show tools' : 'Show inspector'\n return (\n <div\n key={side}\n data-slot=\"studio-panel-edge\"\n data-side={side}\n className={cn('group/edge absolute inset-y-0 z-20 w-8', side === 'left' ? 'left-0' : 'right-0')}\n >\n <Hint\n side={side === 'left' ? 'right' : 'left'}\n sideOffset={8}\n className=\"flex items-center gap-2\"\n content={\n <>\n {label} <span className=\"text-faint\">· both</span>\n <KbdGroup>\n <Kbd>⌘/Ctrl</Kbd>\n <Kbd>B</Kbd>\n </KbdGroup>\n </>\n }\n >\n <Panel asChild>\n <Button\n data-slot=\"studio-panel-reveal\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={label}\n onClick={show[side]}\n className={cn(\n 'absolute top-1/2 h-16 w-6 -translate-y-1/2 cursor-pointer px-0 text-sidebar-foreground opacity-0 transition-[translate,opacity] duration-200 ease-out hover:bg-sidebar/95 hover:text-foreground focus:translate-x-0 focus:opacity-100 group-hover/edge:translate-x-0 group-hover/edge:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-x-0 [@media(hover:none)]:opacity-100',\n side === 'left'\n ? 'left-1 -translate-x-[calc(100%+0.25rem)]'\n : 'right-1 translate-x-[calc(100%+0.25rem)]',\n )}\n >\n <Chevron aria-hidden />\n </Button>\n </Panel>\n </Hint>\n </div>\n )\n })}\n\n <Sidebar\n collapsible=\"icon\"\n variant=\"floating\"\n inert={hidden.left}\n aria-hidden={hidden.left}\n className={cn(\n 'transition-[left,right,width,translate] duration-200 ease-out motion-reduce:transition-none',\n hidden.left && '-translate-x-[calc(100%+1rem)]',\n )}\n >\n {/* Expanded, the logo starts on the tool icons' left edge (16px). Collapsed, it centers on their\n 24px axis: 24px minus half the 14px-tall mark's width (352:144). Padding animates with the\n sidebar's own 200ms width transition, so the logo slides instead of jumping. */}\n <SidebarHeader className=\"h-10 flex-row items-center overflow-hidden py-0 pr-0 pl-4 transition-[padding] duration-200 ease-out group-data-[collapsible=icon]:pl-[calc(1.5rem-0.875rem*352/144/2)] motion-reduce:transition-none\">\n <span className=\"flex items-center gap-2.5 text-foreground\">\n {/* Fixed height, width follows the mark's aspect ratio. */}\n <Logo className=\"h-3.5 w-auto shrink-0\" />\n <strong className=\"tracking-[0.08em] whitespace-nowrap\">STUDIO</strong>\n <span data-slot=\"studio-version\" className=\"text-[10px] text-faint group-data-[collapsible=icon]:hidden\">\n v{version}\n </span>\n </span>\n </SidebarHeader>\n\n <SidebarContent>\n <SidebarGroup>\n <SidebarMenu>\n {tools.map((tool) => {\n const title = tool.title ?? tool.id\n const isPinned = pinned.has(tool.id)\n const { state, dirty } = studio.tools.find((handle) => handle.definition.id === tool.id) ?? {}\n const pinLabel = `${isPinned ? 'Unpin' : 'Pin'} ${title}`\n return (\n <SidebarMenuItem key={tool.id}>\n <SidebarMenuButton\n isActive={tool.id === selected}\n tooltip={title}\n onClick={() => (location.hash = tool.id)}\n >\n <span className=\"relative\">\n <ToolIcon icon={tool.icon} className=\"size-4\" />\n {dirty && (\n <span\n aria-label={state?.conflict ? 'Changed on disk' : 'Unsaved'}\n className={cn(\n 'absolute -top-0.5 -right-0.5 size-1.5 rounded-full',\n state?.conflict ? 'bg-destructive' : 'bg-warning',\n )}\n />\n )}\n </span>\n {/* Gone the moment the sidebar collapses; clipped (not ellipsized) while it expands. */}\n <span className=\"text-clip! group-data-[collapsible=icon]:hidden\">{title}</span>\n </SidebarMenuButton>\n <Hint content={pinLabel} side=\"right\">\n <SidebarMenuAction\n type=\"button\"\n aria-label={pinLabel}\n aria-pressed={isPinned}\n showOnHover={!isPinned}\n onClick={() => togglePin(tool.id)}\n className={cn(\n 'cursor-pointer [&>svg]:size-3 [@media(hover:none)]:opacity-100',\n isPinned && 'text-sidebar-primary',\n )}\n >\n <Pin aria-hidden fill={isPinned ? 'currentColor' : 'none'} />\n </SidebarMenuAction>\n </Hint>\n </SidebarMenuItem>\n )\n })}\n </SidebarMenu>\n </SidebarGroup>\n </SidebarContent>\n <StudioFooter connection={studio.connection} />\n </Sidebar>\n\n {handle && (\n <Panel asChild>\n <aside\n data-slot=\"studio-inspector\"\n inert={hidden.right}\n aria-hidden={hidden.right}\n className={cn(\n 'absolute inset-y-2 right-2 z-10 flex w-(--studio-inspector-width) flex-col gap-1 p-1 transition-transform duration-200 ease-out motion-reduce:transition-none',\n hidden.right && 'translate-x-[calc(100%+1rem)]',\n )}\n >\n <Inspector\n key={handle.definition.id}\n studio={studio}\n handle={handle}\n onCompare={compare}\n fileHref={getConfigFileHref?.(handle.definition.file)}\n />\n </aside>\n </Panel>\n )}\n </SidebarProvider>\n )\n}\n","{\n \"name\": \"@joycostudio/studio\",\n \"version\": \"0.1.3\",\n \"description\": \"Plug project-specific tools into a /studio route, a floating debug pane, and MCP agents.\",\n \"type\": \"module\",\n \"license\": \"ISC\",\n \"author\": \"joyco.studio\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/joyco-studio/studio.git\",\n \"directory\": \"packages/studio\"\n },\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org\",\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\"\n ],\n \"bin\": {\n \"studio\": \"./dist/cli.js\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"./client\": {\n \"types\": \"./dist/client.d.ts\",\n \"default\": \"./dist/client.js\"\n },\n \"./react\": {\n \"types\": \"./dist/react.d.ts\",\n \"default\": \"./dist/react.js\"\n },\n \"./runtime\": {\n \"types\": \"./dist/runtime.d.ts\",\n \"default\": \"./dist/runtime.js\"\n },\n \"./styles.css\": \"./dist/styles.css\",\n \"./command-menu.css\": \"./dist/command-menu.css\"\n },\n \"scripts\": {\n \"build\": \"tsup && tailwindcss -i src/react/styles.css -o dist/styles.css --minify && tailwindcss -i src/react/command-menu.css -o dist/command-menu.css --minify\",\n \"dev\": \"pnpm run --parallel \\\"/^dev:/\\\"\",\n \"test\": \"vitest run\",\n \"test:browser\": \"STUDIO_TEST_BROWSER=1 vitest run test/browser-sync.test.ts\",\n \"test:capture\": \"STUDIO_TEST_CAPTURE=1 vitest run test/capture.test.ts\",\n \"typecheck\": \"tsc --noEmit\",\n \"dev:js\": \"tsup --watch\",\n \"dev:css\": \"tailwindcss -i src/react/styles.css -o dist/styles.css --watch=always\",\n \"dev:command-css\": \"tailwindcss -i src/react/command-menu.css -o dist/command-menu.css --watch=always\"\n },\n \"dependencies\": {\n \"@modelcontextprotocol/node\": \"^2.1.1\",\n \"@modelcontextprotocol/server\": \"^2.3.1\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"cmdk\": \"^1.1.1\",\n \"cn\": \"^0.4.0\",\n \"jiti\": \"^2.7.0\",\n \"lucide\": \"^1.55.0\",\n \"lucide-react\": \"^1.55.0\",\n \"playwright\": \"^1.64.0\",\n \"radix-ui\": \"^1.8.0\",\n \"tailwind-merge\": \"^3.7.0\",\n \"ws\": \"^8.22.0\",\n \"zod\": \"^4.6.6\"\n },\n \"peerDependencies\": {\n \"@joycostudio/xyz\": \"^1.4.0\",\n \"react\": \">=18\",\n \"tweakpane\": \"^4.0.5\"\n },\n \"peerDependenciesMeta\": {\n \"react\": {\n \"optional\": true\n },\n \"tweakpane\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@joycostudio/xyz\": \"^1.4.0\",\n \"@modelcontextprotocol/client\": \"^2.3.1\",\n \"@tailwindcss/cli\": \"^4.3.3\",\n \"@tweakpane/core\": \"^2.0.5\",\n \"@types/node\": \"^24.19.2\",\n \"@types/react\": \"^19.3.0\",\n \"@types/ws\": \"^8.18.2\",\n \"react\": \"^19.3.0\",\n \"tailwindcss\": \"^4.3.3\",\n \"tsup\": \"^8.5.1\",\n \"tw-animate-css\": \"^1.4.0\",\n \"tweakpane\": \"^4.0.5\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^5.0.3\"\n },\n \"sideEffects\": [\n \"*.css\"\n ]\n}\n","import {\n button,\n type DebugDefinition,\n type DebugField,\n type DebugFolder,\n type DebugSchema,\n schemaValues,\n} from '@joycostudio/xyz/debug'\nimport { changedPaths } from '../core/diff'\nimport type { ToolState } from '../core/protocol'\nimport { error, type Result } from '../core/result'\nimport { hasConfig, type StudioTool, type ToolDefinition } from '../core/tool'\nimport { connectBridge, type BridgeClient, type Connection } from './bridge'\nimport { connectBrowserSync } from './browser-sync'\nimport { createHistory, writePath } from './history'\nimport { assignDeep, live } from './live'\n\nexport type ToolHandle<TConfig extends object = any> = {\n readonly definition: ToolDefinition<TConfig>\n /** The live config. Writes sync to same-origin pages and, when connected, the runtime. */\n readonly config: TConfig\n /** Runtime-owned state; null until the runtime answers (always null without one). */\n readonly state: ToolState<TConfig> | null\n /** Bumps on every config change. Handy as a React snapshot. */\n readonly version: number\n /** Called after every config change, local or remote. */\n subscribe(listener: (config: TConfig) => void): () => void\n /** The tool's Xyz schema bound to the live config. */\n controls(): DebugSchema\n /** Xyz `Debuggable`: `debugManager.register(handle)` mounts this tool in the app's floating pane. */\n debug(): DebugFolder\n /** The config on disk: the runtime's saved value or, until one answers, the bundled `initial`. */\n readonly saved: TConfig\n /** Dotted paths where the draft differs from `saved`. Tracked locally, so it works without a runtime too. */\n readonly changes: string[]\n /** The draft differs from `saved`. */\n readonly dirty: boolean\n /** True while `compare(true)` shows the saved config in place of the draft. */\n readonly comparing: boolean\n /**\n * Temporarily show `saved` (true) or go back to the draft (false). Local only: nothing\n * reaches the runtime, and edits made while comparing are dropped when it ends.\n */\n compare(showSaved: boolean): void\n /** True when `undo()` has an edit made on this page to step back through. */\n readonly canUndo: boolean\n readonly canRedo: boolean\n /**\n * Step back through edits made on this page (a slider drag counts as one), then sync the result like any\n * other edit. Only the leaves each edit changed are restored. Returns false with nothing to undo or while comparing.\n */\n undo(): boolean\n redo(): boolean\n save(options?: { force?: boolean }): Promise<Result<ToolState<TConfig>>>\n discard(): Promise<Result<ToolState<TConfig>>>\n}\n\nexport type Studio = {\n /** Every registered tool in order, including preview-only ones. */\n readonly definitions: readonly StudioTool[]\n /** A handle per tool with a config. Preview-only tools have none. */\n readonly tools: readonly ToolHandle[]\n tool<TConfig extends object>(definition: ToolDefinition<TConfig>): ToolHandle<TConfig>\n readonly connection: Connection\n /** Bumps on connection or any tool state change. */\n readonly version: number\n subscribe(listener: () => void): () => void\n close(): void\n}\n\nexport type StudioOptions = {\n tools: readonly StudioTool[]\n /**\n * Runtime bridge URL (e.g. `ws://127.0.0.1:5179`). Omit or pass false for browser-only syncing, as in production.\n * Only browsers connect, so a module-scope `createStudio` is safe to evaluate during SSR.\n */\n runtime?: string | false\n}\n\nconst COMPARE_MESSAGE = 'joyco-studio:compare'\ntype CompareMessage = { type: typeof COMPARE_MESSAGE; tool: string; showSaved: boolean }\n\n/** Make the studio running in `target` (e.g. a preview iframe) compare `tool` as well. */\nexport function postCompare(target: Window | null | undefined, tool: string, showSaved: boolean) {\n const message: CompareMessage = { type: COMPARE_MESSAGE, tool, showSaved }\n target?.postMessage(message, location.origin)\n}\n\n/** Mark every value control live so a pane registered with `registerFrame` reflects remote edits. */\nfunction liveSchema(schema: DebugSchema): DebugSchema {\n return Object.fromEntries(\n Object.entries(schema).map(([key, field]): [string, DebugField] => {\n if (field.kind === 'button') return [key, field]\n if (field.kind === 'folder')\n return [\n key,\n { ...field, definition: { ...field.definition, schema: () => liveSchema(field.definition.schema()) } },\n ]\n return [key, { ...field, live: true }]\n }),\n )\n}\n\n/**\n * Xyz `extend` for a folder bound to `handle.controls()` (optionally followed by more fields, as in `debug()`):\n * double-clicking a slider resets it to its saved value.\n */\nexport function resetSlidersOnDoubleClick(handle: ToolHandle): NonNullable<DebugDefinition['extend']> {\n return (folder, { fields }) => {\n const sliders = fields().filter(({ field }) => field.kind === 'slider')\n const onDoubleClick = (event: MouseEvent) => {\n // Double-clicking the number input selects its text instead.\n if (handle.comparing || (event.target as Element).closest('input')) return\n const slider = sliders.find(({ blade }) => blade.element.contains(event.target as Node))\n if (slider?.field.kind !== 'slider') return\n const saved = slider.path.reduce<unknown>(\n (values, key) => (values as Record<string, unknown> | undefined)?.[key],\n schemaValues(handle.definition.controls(structuredClone(handle.saved))),\n )\n if (typeof saved === 'number') slider.field.write(saved)\n }\n folder.element.addEventListener('dblclick', onDoubleClick)\n return () => folder.element.removeEventListener('dblclick', onDoubleClick)\n }\n}\n\n/** A `registerFrame` for Xyz's `DebugManager` / `bindDebugSchema`: refreshes live controls every animation frame. */\nexport function everyFrame(refresh: () => void) {\n let frame = requestAnimationFrame(function tick() {\n refresh()\n frame = requestAnimationFrame(tick)\n })\n return () => cancelAnimationFrame(frame)\n}\n\n/** One studio per runtime URL (or local tool set) per page; replace HMR instances without leaking transports. */\nconst instances: Map<string, Studio> = ((globalThis as { __joycoStudio?: Map<string, Studio> }).__joycoStudio ??=\n new Map())\n\nexport function createStudio({ tools, runtime }: StudioOptions): Studio {\n const instanceKey = runtime || JSON.stringify(tools.map(({ id, file }) => [id, file]).sort())\n let bridge: BridgeClient | null = null\n let connection: Connection = { phase: runtime ? 'connecting' : 'local' }\n let version = 0\n const studioListeners = new Set<() => void>()\n const touch = () => {\n version++\n for (const listener of studioListeners) listener()\n }\n\n const createHandle = <TConfig extends object>(definition: ToolDefinition<TConfig>) => {\n const raw = structuredClone(definition.initial)\n const listeners = new Set<(config: TConfig) => void>()\n let pushing: Promise<unknown> = Promise.resolve()\n let scheduled = false\n /** The draft to restore while comparing; null when showing the draft. */\n let stashed: TConfig | null = null\n const history = createHistory()\n /** A copy of `raw` as of the last change, so the next local edit can be diffed against it. */\n let snapshot = structuredClone(raw)\n\n const changed = () => {\n snapshot = structuredClone(raw)\n handle.version++\n for (const listener of listeners) listener(handle.config)\n touch()\n }\n const adopt = (state: ToolState) => {\n handle.state = state as ToolState<TConfig>\n touch()\n }\n const receive = (state: ToolState) => {\n if (stashed) stashed = structuredClone(state.draft.value) as TConfig\n else assignDeep(raw as Record<string, unknown>, state.draft.value as Record<string, unknown>)\n adopt(state)\n if (!stashed) changed()\n browserSync?.publish(state.draft.value as TConfig)\n }\n const resync = async () => {\n const result = await bridge?.request('tool.get', { tool: definition.id })\n if (result?.ok) receive(result.data)\n }\n const push = () => {\n if (scheduled || !bridge) return\n scheduled = true\n pushing = Promise.resolve().then(async () => {\n scheduled = false\n const result = await bridge?.request('tool.update', { tool: definition.id, value: raw })\n if (!result) return\n if (result.ok) adopt(result.data)\n else if (result.error !== 'runtime_unavailable') {\n console.warn(`[studio] ${definition.id}: ${result.message ?? result.error}`)\n await resync()\n }\n })\n }\n\n const edited = () => {\n changed()\n if (!stashed) {\n browserSync?.publish(raw)\n push()\n }\n }\n const restore = (patch: ReturnType<typeof history.undo>) => {\n if (!patch) return false\n for (const { path, value } of patch) writePath(raw as Record<string, unknown>, path, value)\n edited()\n return true\n }\n\n const handle = {\n definition,\n config: live(raw, () => {\n if (!stashed) history.record(snapshot, raw)\n edited()\n }),\n state: null as ToolState<TConfig> | null,\n version: 0,\n get saved(): TConfig {\n return handle.state?.saved.value ?? definition.initial\n },\n get changes() {\n return changedPaths(handle.saved, stashed ?? raw)\n },\n get dirty() {\n return handle.changes.length > 0\n },\n comparing: false,\n compare(showSaved: boolean) {\n if (showSaved === handle.comparing) return\n if (showSaved) stashed = structuredClone(raw)\n const next = showSaved ? handle.saved : stashed!\n assignDeep(raw as Record<string, unknown>, next as Record<string, unknown>)\n if (!showSaved) stashed = null\n handle.comparing = showSaved\n changed()\n },\n get canUndo() {\n return history.canUndo\n },\n get canRedo() {\n return history.canRedo\n },\n undo: () => !stashed && restore(history.undo()),\n redo: () => !stashed && restore(history.redo()),\n subscribe(listener: (config: TConfig) => void) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n controls: () => definition.controls(handle.config),\n debug(): DebugFolder {\n const actions: DebugSchema = runtime\n ? {\n save: button('Save', () => handle.save().then(fail), 'Saved ✓'),\n discard: button('Discard', () => handle.discard().then(fail), 'Discarded'),\n }\n : {}\n return {\n title: definition.title ?? definition.id,\n schema: () => ({ ...liveSchema(handle.controls()), ...actions }),\n extend: resetSlidersOnDoubleClick(handle),\n }\n },\n async save({ force = false } = {}) {\n if (!bridge) return error('runtime_unavailable')\n await pushing\n const revision = handle.state?.draft.revision\n if (revision === undefined) return error('runtime_unavailable')\n const result = await bridge.request('tool.save', { tool: definition.id, revision, force })\n if (result.ok) adopt(result.data)\n return result as Result<ToolState<TConfig>>\n },\n async discard() {\n if (!bridge) return error('runtime_unavailable')\n await pushing\n const before = snapshot\n const result = await bridge.request('tool.discard', { tool: definition.id })\n if (result.ok) {\n receive(result.data)\n // Discarding is undoable, as its own step.\n if (!stashed) history.record(before, raw, { merge: false })\n }\n return result as Result<ToolState<TConfig>>\n },\n receive,\n resync,\n close: () => browserSync?.close(),\n }\n const browserSync = connectBrowserSync(definition, runtime, {\n enabled: () => connection.phase !== 'connected',\n receive(value) {\n if (stashed) {\n // The shown saved config stays put, but `changes` and `dirty` read the new draft.\n stashed = value\n touch()\n } else {\n assignDeep(raw as Record<string, unknown>, value as Record<string, unknown>)\n changed()\n }\n },\n })\n return handle\n }\n\n const handles = new Map(tools.filter(hasConfig).map((definition) => [definition.id, createHandle(definition)]))\n\n // /studio asks its same-origin preview iframe to compare too (see `postCompare`).\n const onMessage = (event: MessageEvent) => {\n const message = event.data as CompareMessage | undefined\n if (event.origin !== location.origin || message?.type !== COMPARE_MESSAGE) return\n handles.get(message.tool)?.compare(message.showSaved)\n }\n if (typeof window !== 'undefined') window.addEventListener?.('message', onMessage)\n\n if (runtime && typeof window !== 'undefined') {\n bridge = connectBridge(runtime, {\n state: (state) => handles.get(state.tool)?.receive(state),\n connection(next) {\n connection = next\n touch()\n if (next.phase === 'connected') for (const handle of handles.values()) void handle.resync()\n },\n })\n }\n\n const studio: Studio = {\n definitions: tools,\n tools: [...handles.values()],\n tool<TConfig extends object>(definition: ToolDefinition<TConfig>) {\n const handle = handles.get(definition.id)\n if (!handle) throw new Error(`[studio] tool \"${definition.id}\" was not passed to createStudio`)\n return handle as unknown as ToolHandle<TConfig>\n },\n get connection() {\n return connection\n },\n get version() {\n return version\n },\n subscribe(listener) {\n studioListeners.add(listener)\n return () => void studioListeners.delete(listener)\n },\n close() {\n bridge?.close()\n for (const handle of handles.values()) handle.close()\n studioListeners.clear()\n if (typeof window !== 'undefined') window.removeEventListener?.('message', onMessage)\n if (instances.get(instanceKey) === studio) instances.delete(instanceKey)\n },\n }\n if (typeof window !== 'undefined') {\n instances.get(instanceKey)?.close()\n instances.set(instanceKey, studio)\n }\n return studio\n}\n\nfunction fail(result: Result<unknown>) {\n if (!result.ok) throw new Error(result.message ?? result.error)\n}\n","import { useSyncExternalStore } from 'react'\nimport type { Studio, ToolHandle } from '../client/studio'\n\n/** Re-render on connection and tool state changes. */\nexport function useStudio(studio: Studio) {\n useSyncExternalStore(\n studio.subscribe,\n () => studio.version,\n () => 0,\n )\n return studio\n}\n\n/** The tool's live config; re-renders on every change, local or remote. */\nexport function useToolConfig<TConfig extends object>(handle: ToolHandle<TConfig>) {\n useSyncExternalStore(\n handle.subscribe,\n () => handle.version,\n () => 0,\n )\n return handle.config\n}\n","import { bindDebugSchema } from '@joycostudio/xyz/debug'\nimport { SquareSplitHorizontal } from 'lucide-react'\nimport { useEffect, useRef, useState } from 'react'\nimport { resetSlidersOnDoubleClick, type Studio, type ToolHandle } from '../client/studio'\nimport type { Result } from '../core/result'\nimport { useStudio } from './hooks'\nimport { tweakpaneTheme } from './theme'\nimport { ToolIcon } from './tool-icon'\nimport { Button } from './ui/button'\nimport { Kbd, KbdGroup } from './ui/kbd'\nimport { Hint } from './ui/tooltip'\nimport { PanelContent, PanelFooter, PanelHeader } from './ui/panel'\n\nfunction describe(studio: Studio, handle: ToolHandle) {\n const { state } = handle\n if (handle.comparing) return { tone: 'text-sky-400', text: 'Showing saved' }\n if (studio.connection.phase !== 'connected') return { tone: 'text-faint', text: 'Not persisting' }\n if (!state) return { tone: 'text-destructive', text: 'Restart studio dev' }\n if (state.conflict) return { tone: 'text-destructive', text: 'Changed on disk' }\n if (state.dirty) return { tone: 'text-warning', text: 'Unsaved' }\n return { tone: 'text-success', text: state.saved.hash ? 'Saved' : 'Not on disk yet' }\n}\n\n/** The tool's Tweakpane controls, framed by the Studio's own status and save/discard actions. */\nexport function Inspector({\n studio,\n handle,\n onCompare,\n fileHref,\n}: {\n studio: Studio\n handle: ToolHandle\n /** Show the saved config (true) or the draft (false), in the preview as well. */\n onCompare: (showSaved: boolean) => void\n fileHref?: string\n}) {\n useStudio(studio)\n const container = useRef<HTMLDivElement>(null)\n const pane = useRef<{ disabled: boolean } | null>(null)\n const [failure, setFailure] = useState<string | null>(null)\n\n const run = (action: Promise<Result<unknown>>) =>\n void action.then((result) => setFailure(result.ok ? null : (result.message ?? result.error)))\n const save = (force = false) => run(handle.save({ force }))\n\n useEffect(() => {\n let disposed = false\n let teardown = () => {}\n void import('tweakpane').then(({ Pane }) => {\n if (disposed || !container.current) return\n const instance = new Pane({ container: container.current })\n pane.current = instance\n const bound = bindDebugSchema(instance, {\n schema: () => handle.controls(),\n extend: resetSlidersOnDoubleClick(handle),\n })\n const unsubscribe = handle.subscribe(() => bound.refresh())\n teardown = () => {\n unsubscribe()\n bound.dispose()\n instance.dispose()\n pane.current = null\n }\n })\n return () => {\n disposed = true\n teardown()\n }\n }, [handle])\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 's' || !(event.metaKey || event.ctrlKey)) return\n event.preventDefault()\n if (handle.state?.dirty) save()\n }\n addEventListener('keydown', onKeyDown)\n return () => removeEventListener('keydown', onKeyDown)\n })\n\n // While comparing, the controls show the saved config: read-only, so nothing edits the wrong version.\n useEffect(() => {\n if (pane.current) pane.current.disabled = handle.comparing\n })\n\n const { definition, state } = handle\n const ConfigFile = fileHref ? 'a' : 'span'\n const status = describe(studio, handle)\n const editable = studio.connection.phase === 'connected' && !!state?.dirty && !handle.comparing\n // Shown like the controls' labels: `vignette.amount` reads as \"Vignette › Amount\".\n const changes = handle.changes.map((path) =>\n path\n .split('.')\n .map((key) => key.charAt(0).toUpperCase() + key.slice(1))\n .join(' › '),\n )\n\n return (\n <>\n <PanelHeader>\n <strong className=\"flex min-w-0 items-center gap-2 text-foreground\">\n <ToolIcon icon={definition.icon} className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\" title={definition.title ?? definition.id}>\n {definition.title ?? definition.id}\n </span>\n </strong>\n <div className=\"mt-1 flex items-center gap-3 pl-5.5 text-[11px]\">\n <ConfigFile\n data-slot=\"studio-config-file\"\n className=\"min-w-0 flex-1 truncate text-muted-foreground\"\n href={fileHref}\n title={fileHref ? `Open ${definition.file}` : definition.file}\n >\n {definition.file}\n </ConfigFile>\n <span\n className={`flex shrink-0 items-center gap-1.5 ${status.tone}`}\n title={state ? `Draft revision ${state.draft.revision}` : undefined}\n >\n <span aria-hidden=\"true\" className=\"size-1.5 rounded-full bg-current\" />\n {status.text}\n </span>\n </div>\n </PanelHeader>\n\n <PanelContent ref={container} data-slot=\"studio-controls\" style={tweakpaneTheme} />\n\n <PanelFooter>\n {failure && <div className=\"text-destructive\">{failure}</div>}\n {changes.length > 0 && (\n <div className=\"truncate text-muted-foreground\" title={changes.join(', ')}>\n {changes.length} changed: <span className=\"text-foreground\">{changes.join(', ')}</span>\n </div>\n )}\n <div className=\"flex gap-2\">\n <Hint\n className=\"flex items-center gap-2\"\n content={\n <>\n Hold to compare with saved <Kbd>{'\\\\'}</Kbd>\n </>\n }\n >\n <Button\n variant=\"secondary\"\n size=\"icon-sm\"\n aria-label=\"Hold to compare with saved\"\n aria-pressed={handle.comparing}\n disabled={!handle.dirty && !handle.comparing}\n className=\"shrink-0 aria-pressed:bg-primary aria-pressed:text-primary-foreground\"\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId)\n onCompare(true)\n }}\n onPointerUp={() => onCompare(false)}\n onPointerCancel={() => onCompare(false)}\n >\n <SquareSplitHorizontal />\n </Button>\n </Hint>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n className=\"flex-1\"\n disabled={!editable}\n onClick={() => run(handle.discard())}\n >\n Discard\n </Button>\n {state?.conflict ? (\n <Button variant=\"destructive\" size=\"sm\" className=\"flex-1\" onClick={() => save(true)}>\n Overwrite file\n </Button>\n ) : (\n <Button size=\"sm\" className=\"flex-1\" disabled={!editable} onClick={() => save()}>\n Save\n <KbdGroup>\n <Kbd>⌘</Kbd>\n <Kbd>S</Kbd>\n </KbdGroup>\n </Button>\n )}\n </div>\n </PanelFooter>\n </>\n )\n}\n","import type { CSSProperties } from 'react'\n\n/** Tweakpane reads its theme from inherited custom properties; point them at the Studio palette in styles.css. */\nexport const tweakpaneTheme = {\n '--tp-base-background-color': 'transparent',\n '--tp-base-shadow-color': 'transparent',\n '--tp-base-border-radius': '0px',\n '--tp-base-font-family': 'var(--studio-font)',\n '--tp-blade-border-radius': 'var(--radius)',\n '--tp-blade-horizontal-padding': '4px',\n '--tp-blade-value-width': '168px',\n '--tp-container-horizontal-padding': '8px',\n '--tp-container-vertical-padding': '6px',\n '--tp-container-unit-size': '22px',\n '--tp-container-unit-spacing': '6px',\n '--tp-container-background-color': 'var(--card)',\n '--tp-container-background-color-hover': 'var(--field)',\n '--tp-container-background-color-focus': 'var(--field-hover)',\n '--tp-container-background-color-active': 'var(--field-active)',\n '--tp-container-foreground-color': 'var(--muted-foreground)',\n '--tp-input-background-color': 'var(--field)',\n '--tp-input-background-color-hover': 'var(--field-hover)',\n '--tp-input-background-color-focus': 'var(--field-active)',\n '--tp-input-background-color-active': 'var(--field-active)',\n '--tp-input-foreground-color': 'var(--foreground)',\n // Buttons and slider knobs: lighter than fields so the knob reads against the track.\n '--tp-button-background-color': 'var(--knob)',\n '--tp-button-background-color-hover': 'var(--knob-hover)',\n '--tp-button-background-color-focus': 'var(--knob-hover)',\n '--tp-button-background-color-active': 'var(--muted-foreground)',\n '--tp-button-foreground-color': 'var(--foreground)',\n '--tp-groove-foreground-color': 'var(--border)',\n '--tp-label-foreground-color': 'var(--muted-foreground)',\n '--tp-monitor-background-color': 'var(--card)',\n '--tp-monitor-foreground-color': 'var(--muted-foreground)',\n} as CSSProperties\n","import { SlidersHorizontal } from 'lucide'\nimport type { SVGProps } from 'react'\nimport type { ToolIcon as ToolIconData } from '../core/tool'\n\nconst camel = (name: string) => name.replace(/-([a-z])/g, (_, char: string) => char.toUpperCase())\n\n/** Render a tool's icon data as a Lucide-style stroke icon; tools without one get a generic sliders icon. */\nexport function ToolIcon({ icon = SlidersHorizontal, ...props }: { icon?: ToolIconData } & SVGProps<SVGSVGElement>) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n {...props}\n >\n {icon.map(([Tag, attrs], index) => {\n const Element = Tag as 'path'\n return (\n <Element\n key={index}\n {...Object.fromEntries(Object.entries(attrs).map(([name, value]) => [camel(name), value]))}\n />\n )\n })}\n </svg>\n )\n}\n","import * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/react/ui/utils'\nimport { Slot } from 'radix-ui'\n\nconst buttonVariants = cva(\n \"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 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 hover:bg-primary/90',\n destructive:\n 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40',\n outline:\n 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2 has-[>svg]:px-3',\n xs: \"h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5',\n lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',\n icon: 'size-9',\n 'icon-xs': \"size-6 rounded-md [&_svg:not([class*='size-'])]:size-3\",\n 'icon-sm': 'size-8',\n 'icon-lg': 'size-10',\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 asChild = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot.Root : 'button'\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\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","import type * as React from 'react'\nimport { cn } from '@/react/ui/utils'\n\nfunction Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {\n return (\n <kbd\n data-slot=\"kbd\"\n className={cn(\n 'bg-muted text-muted-foreground border-border pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm border border-b-2 px-1 font-mono text-xs font-normal select-none',\n \"[&_svg:not([class*='size-'])]:size-3\",\n '[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction KbdGroup({ className, ...props }: React.ComponentProps<'span'>) {\n return <span data-slot=\"kbd-group\" className={cn('inline-flex items-center gap-1', className)} {...props} />\n}\n\nexport { Kbd, KbdGroup }\n","import * as React from 'react'\nimport { cn } from '@/react/ui/utils'\nimport { Tooltip as TooltipPrimitive } from 'radix-ui'\n\nfunction TooltipProvider({ delayDuration = 0, ...props }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {\n return <TooltipPrimitive.Provider data-slot=\"tooltip-provider\" delayDuration={delayDuration} {...props} />\n}\n\nfunction Tooltip({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Root>) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n}\n\nfunction TooltipTrigger({ ...props }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\nfunction TooltipContent({\n className,\n sideOffset = 0,\n children,\n ...props\n}: React.ComponentProps<typeof TooltipPrimitive.Content>) {\n return (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n data-slot=\"tooltip-content\"\n sideOffset={sideOffset}\n className={cn(\n 'z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 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-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',\n className,\n )}\n {...props}\n >\n {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground\" />\n </TooltipPrimitive.Content>\n </TooltipPrimitive.Portal>\n )\n}\n\n/** Compose a hint around an existing control without adding a DOM wrapper. */\nfunction Hint({\n children,\n content,\n ...props\n}: Omit<React.ComponentProps<typeof TooltipContent>, 'children' | 'content'> & {\n children: React.ReactElement\n content: React.ReactNode\n}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>{children}</TooltipTrigger>\n <TooltipContent {...props}>{content}</TooltipContent>\n </Tooltip>\n )\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, Hint }\n","import { Slot } from 'radix-ui'\nimport { forwardRef, type ComponentProps, type ComponentPropsWithoutRef } from 'react'\nimport { cn } from './utils'\nimport { StudioSurface } from '../surface'\n\n/** Shared floating surface. Layout and visibility belong to the caller. */\nexport const Panel = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'> & { asChild?: boolean }>(function Panel(\n { className, asChild = false, ...props },\n ref,\n) {\n const Comp = asChild ? Slot.Root : 'div'\n return (\n <Comp\n ref={ref}\n data-slot=\"panel\"\n className={cn(\n 'rounded-lg border border-sidebar-border bg-sidebar/85 shadow-xl shadow-black/40 backdrop-blur-xl',\n className,\n )}\n {...props}\n />\n )\n})\n\n/** Raised sections sit inside the panel's 4px padding with concentric corners. */\nexport function PanelHeader({ className, ...props }: ComponentProps<'header'>) {\n return (\n <StudioSurface asChild className={cn('px-3 pt-2.5 pb-2', className)}>\n <header data-slot=\"panel-header\" {...props} />\n </StudioSurface>\n )\n}\n\nexport const PanelContent = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'>>(function PanelContent(\n { className, ...props },\n ref,\n) {\n return (\n <div\n ref={ref}\n data-slot=\"panel-content\"\n className={cn('min-h-0 flex-1 overflow-auto px-1 py-1.5', className)}\n {...props}\n />\n )\n})\n\nexport function PanelFooter({ className, ...props }: ComponentProps<'footer'>) {\n return (\n <StudioSurface asChild className={cn('grid gap-2 p-2', className)}>\n <footer data-slot=\"panel-footer\" {...props} />\n </StudioSurface>\n )\n}\n","import { Slot } from 'radix-ui'\nimport { forwardRef, type ComponentPropsWithoutRef } from 'react'\nimport { cn } from './ui/utils'\n\n/** The inset card surface shared by canvas headers, toolbars, and detail panels. */\nexport const StudioSurface = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'> & { asChild?: boolean }>(\n function StudioSurface({ asChild = false, className, ...props }, ref) {\n const Comp = asChild ? Slot.Root : 'div'\n return <Comp ref={ref} data-slot=\"studio-surface\" className={cn('studio-surface', className)} {...props} />\n },\n)\n\nexport const StudioToolbar = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'>>(function StudioToolbar(\n { className, ...props },\n ref,\n) {\n return <StudioSurface ref={ref} role=\"group\" className={cn('studio-toolbar', className)} {...props} />\n})\n","import type { SVGProps } from 'react'\n\n/** The JOYCO stretched iso mark (r2.joyco.studio/brand/iso-stretched.svg), without the © glyph that vanishes at UI sizes. */\nexport function Logo(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 352 144\" fill=\"currentColor\" aria-label=\"JOYCO\" role=\"img\" {...props}>\n <path d=\"M328 96L280 144H0V40H176V112H192V24H0V0H352V24H328V96Z\" />\n </svg>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { Studio } from '../client/studio'\n\nconst STORAGE_KEY = 'joyco-studio:pinned-tools'\nconst CHANGE_EVENT = 'joyco-studio:pins-changed'\n\nfunction readPins(): string[] {\n try {\n const value: unknown = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]')\n return Array.isArray(value) ? value.filter((id): id is string => typeof id === 'string') : []\n } catch {\n return []\n }\n}\n\n/** Browser-local preferences shared by the sidebar, command menu, and other tabs. */\nexport function usePinnedTools(studio: Studio) {\n const [pins, setPins] = useState<string[]>([])\n\n useEffect(() => {\n setPins(readPins())\n const onChange = (event: Event) => setPins((event as CustomEvent<string[]>).detail)\n const onStorage = (event: StorageEvent) => {\n if (event.key === STORAGE_KEY || event.key === null) setPins(readPins())\n }\n window.addEventListener(CHANGE_EVENT, onChange)\n window.addEventListener('storage', onStorage)\n return () => {\n window.removeEventListener(CHANGE_EVENT, onChange)\n window.removeEventListener('storage', onStorage)\n }\n }, [])\n\n const pinned = new Set(pins)\n // Keep registration order within each group, and never reorder the client's tool registry.\n const tools = [...studio.definitions].sort((a, b) => Number(pinned.has(b.id)) - Number(pinned.has(a.id)))\n\n const togglePin = (id: string) => {\n const next = pinned.has(id) ? pins.filter((pin) => pin !== id) : [...pins, id]\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(next))\n } catch {\n // Pinning still works for mounted views when browser storage is unavailable.\n }\n window.dispatchEvent(new CustomEvent(CHANGE_EVENT, { detail: next }))\n }\n\n return { tools, pinned, togglePin }\n}\n","import { RotateCw } from 'lucide-react'\nimport { forwardRef, useImperativeHandle, useRef, useState, type ComponentPropsWithoutRef, type ReactNode } from 'react'\nimport { CanvasToolbar } from './canvas-toolbar'\n\nexport interface PreviewCanvasProps extends ComponentPropsWithoutRef<'iframe'> {\n expanded?: boolean\n onExpandedChange?: (expanded: boolean) => void\n onReload?: () => void\n toolbar?: ReactNode\n}\n\n/** Expands the same iframe in place. Native iframe props and the ref reach the iframe. */\nexport const PreviewCanvas = forwardRef<HTMLIFrameElement, PreviewCanvasProps>(function PreviewCanvas(\n { title = 'Preview', expanded: controlled, onExpandedChange, onReload, toolbar, ...props },\n ref,\n) {\n const [localExpanded, setExpanded] = useState(false)\n const expanded = controlled ?? localExpanded\n const frame = useRef<HTMLIFrameElement>(null)\n useImperativeHandle(ref, () => frame.current!, [])\n\n return (\n <section\n className=\"studio-preview-canvas\"\n data-slot=\"preview-canvas\"\n data-expanded={expanded || undefined}\n aria-label={`${title} canvas`}\n >\n <CanvasToolbar\n label=\"Preview canvas\"\n expanded={expanded}\n onToggle={() => {\n setExpanded(!expanded)\n onExpandedChange?.(!expanded)\n }}\n >\n <button\n type=\"button\"\n aria-label=\"Reload preview\"\n title=\"Reload preview\"\n onClick={() => {\n onReload?.()\n if (frame.current) frame.current.src = frame.current.src\n }}\n >\n <RotateCw size={14} strokeWidth={1.5} aria-hidden />\n </button>\n <div className=\"studio-preview-source\">{toolbar ?? <span className=\"studio-preview-title\">{title}</span>}</div>\n </CanvasToolbar>\n <iframe {...props} ref={frame} title={title} />\n </section>\n )\n})\n","import { Maximize, Minimize, Pin, PinOff } from 'lucide-react'\nimport { useState, type ReactNode } from 'react'\nimport { StudioToolbar } from './surface'\n\nexport interface CanvasToolbarProps {\n label: string\n expanded?: boolean\n onToggle?: () => void\n children?: ReactNode\n}\n\n/** Pinned by default; auto-hide preserves pointer, keyboard, open-menu, and touch access. */\nexport function CanvasToolbar({ label, expanded = false, onToggle, children }: CanvasToolbarProps) {\n const [ghost, setGhost] = useState(false)\n const ExpandIcon = expanded ? Minimize : Maximize\n const PinIcon = ghost ? PinOff : Pin\n\n return (\n <div\n className=\"studio-canvas-toolbar\"\n data-slot=\"canvas-toolbar\"\n data-expanded={expanded || undefined}\n data-ghost={(!expanded && ghost) || undefined}\n role=\"group\"\n aria-label={label}\n >\n <StudioToolbar className=\"studio-canvas-actions\">\n {children}\n {onToggle && (\n <div className=\"studio-canvas-toggle\">\n <button data-slot=\"toolbar-action\" type=\"button\" aria-pressed={expanded} onClick={onToggle}>\n <ExpandIcon size={14} strokeWidth={1.5} aria-hidden />\n {expanded ? 'Contain canvas' : 'Expand'}\n </button>\n </div>\n )}\n {!expanded && (\n <button\n type=\"button\"\n aria-label={`Auto-hide ${label.toLowerCase()} header`}\n aria-pressed={ghost}\n title={ghost ? 'Pin header' : 'Auto-hide header'}\n onClick={() => setGhost(!ghost)}\n >\n <PinIcon size={14} strokeWidth={1.5} aria-hidden />\n </button>\n )}\n </StudioToolbar>\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\n\n/** A boolean that survives reloads in this tab. Reads storage on first render, so render it client-only. */\nexport function useSessionFlag(key: string) {\n const [value, setValue] = useState(() => {\n try {\n return sessionStorage.getItem(key) === 'true'\n } catch {\n return false\n }\n })\n\n useEffect(() => {\n try {\n sessionStorage.setItem(key, String(value))\n } catch {\n // The flag still works for this mount when browser storage is unavailable.\n }\n }, [key, value])\n\n return [value, setValue] as const\n}\n","'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/react/ui/utils'\nimport { Slot } from 'radix-ui'\n\nimport { useIsMobile } from '@/react/ui/hooks/use-mobile'\nimport { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/react/ui/sheet'\nimport { Hint, TooltipContent, TooltipProvider } from '@/react/ui/tooltip'\nimport { Panel } from './panel'\n\nconst SIDEBAR_COOKIE_NAME = 'sidebar_state'\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7\nconst SIDEBAR_WIDTH = '16rem'\nconst SIDEBAR_WIDTH_MOBILE = '18rem'\nconst SIDEBAR_WIDTH_ICON = '3rem'\n\ntype SidebarContextProps = {\n state: 'expanded' | 'collapsed'\n open: boolean\n setOpen: (open: boolean) => void\n openMobile: boolean\n setOpenMobile: (open: boolean) => void\n isMobile: boolean\n toggleSidebar: () => void\n}\n\nconst SidebarContext = React.createContext<SidebarContextProps | null>(null)\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext)\n if (!context) {\n throw new Error('useSidebar must be used within a SidebarProvider.')\n }\n\n return context\n}\n\nfunction SidebarProvider({\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n className,\n style,\n children,\n ...props\n}: React.ComponentProps<'div'> & {\n defaultOpen?: boolean\n open?: boolean\n onOpenChange?: (open: boolean) => void\n}) {\n const isMobile = useIsMobile()\n const [openMobile, setOpenMobile] = React.useState(false)\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen)\n const open = openProp ?? _open\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === 'function' ? value(open) : value\n if (setOpenProp) {\n setOpenProp(openState)\n } else {\n _setOpen(openState)\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n },\n [setOpenProp, open],\n )\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)\n }, [isMobile, setOpen, setOpenMobile])\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? 'expanded' : 'collapsed'\n\n const contextValue = React.useMemo<SidebarContextProps>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],\n )\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <TooltipProvider delayDuration={0}>\n <div\n data-slot=\"sidebar-wrapper\"\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,\n ...style,\n } as React.CSSProperties\n }\n className={cn('group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar', className)}\n {...props}\n >\n {children}\n </div>\n </TooltipProvider>\n </SidebarContext.Provider>\n )\n}\n\nfunction Sidebar({\n side = 'left',\n variant = 'sidebar',\n collapsible = 'offcanvas',\n className,\n children,\n ...props\n}: React.ComponentProps<'div'> & {\n side?: 'left' | 'right'\n variant?: 'sidebar' | 'floating' | 'inset'\n collapsible?: 'offcanvas' | 'icon' | 'none'\n}) {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n const Surface = variant === 'floating' ? Panel : 'div'\n\n if (collapsible === 'none') {\n return (\n <div\n data-slot=\"sidebar\"\n className={cn('flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground', className)}\n {...props}\n >\n {children}\n </div>\n )\n }\n\n if (isMobile) {\n return (\n <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>\n <SheetContent\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar\"\n data-mobile=\"true\"\n className=\"w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n <SheetHeader className=\"sr-only\">\n <SheetTitle>Sidebar</SheetTitle>\n <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n </SheetHeader>\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </SheetContent>\n </Sheet>\n )\n }\n\n return (\n <div\n className=\"group peer hidden text-sidebar-foreground md:block\"\n data-state={state}\n data-collapsible={state === 'collapsed' ? collapsible : ''}\n data-variant={variant}\n data-side={side}\n data-slot=\"sidebar\"\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n data-slot=\"sidebar-gap\"\n className={cn(\n 'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',\n 'group-data-[collapsible=offcanvas]:w-0',\n 'group-data-[side=right]:rotate-180',\n variant === 'floating' || variant === 'inset'\n ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'\n : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',\n )}\n />\n <div\n data-slot=\"sidebar-container\"\n className={cn(\n 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',\n side === 'left'\n ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'\n : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',\n // Adjust the padding for floating and inset variants.\n variant === 'floating' || variant === 'inset'\n ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'\n : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',\n className,\n )}\n {...props}\n >\n <Surface\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar-inner\"\n className={cn('flex h-full w-full flex-col', variant !== 'floating' && 'bg-sidebar')}\n >\n {children}\n </Surface>\n </div>\n </div>\n )\n}\n\nfunction SidebarHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-header\"\n data-sidebar=\"header\"\n className={cn('flex flex-col gap-2 p-2', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-footer\"\n data-sidebar=\"footer\"\n className={cn('flex flex-col gap-2 p-2', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-content\"\n data-sidebar=\"content\"\n className={cn(\n 'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction SidebarGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-group\"\n data-sidebar=\"group\"\n className={cn('relative flex w-full min-w-0 flex-col p-2', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarMenu({ className, ...props }: React.ComponentProps<'ul'>) {\n return (\n <ul\n data-slot=\"sidebar-menu\"\n data-sidebar=\"menu\"\n className={cn('flex w-full min-w-0 flex-col gap-1', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>) {\n return (\n <li\n data-slot=\"sidebar-menu-item\"\n data-sidebar=\"menu-item\"\n className={cn('group/menu-item relative', className)}\n {...props}\n />\n )\n}\n\nconst sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n outline:\n 'bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]',\n },\n size: {\n default: 'h-8 text-sm',\n sm: 'h-7 text-xs',\n lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nfunction SidebarMenuButton({\n asChild = false,\n isActive = false,\n variant = 'default',\n size = 'default',\n tooltip,\n className,\n ...props\n}: React.ComponentProps<'button'> & {\n asChild?: boolean\n isActive?: boolean\n tooltip?: string | React.ComponentProps<typeof TooltipContent>\n} & VariantProps<typeof sidebarMenuButtonVariants>) {\n const Comp = asChild ? Slot.Root : 'button'\n const { isMobile, state } = useSidebar()\n\n const button = (\n <Comp\n data-slot=\"sidebar-menu-button\"\n data-sidebar=\"menu-button\"\n data-size={size}\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size }), className)}\n {...props}\n />\n )\n\n if (!tooltip) return button\n const { children, ...hint } = typeof tooltip === 'string' ? { children: tooltip } : tooltip\n return (\n <Hint side=\"right\" align=\"center\" hidden={state !== 'collapsed' || isMobile} {...hint} content={children}>\n {button}\n </Hint>\n )\n}\n\nfunction SidebarMenuAction({\n className,\n asChild = false,\n showOnHover = false,\n ...props\n}: React.ComponentProps<'button'> & {\n asChild?: boolean\n showOnHover?: boolean\n}) {\n const Comp = asChild ? Slot.Root : 'button'\n\n return (\n <Comp\n data-slot=\"sidebar-menu-action\"\n data-sidebar=\"menu-action\"\n className={cn(\n 'absolute top-1/2 right-1 flex aspect-square w-5 -translate-y-1/2 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',\n // Increases the hit area of the button on mobile.\n 'after:absolute after:-inset-2 md:after:hidden',\n 'group-data-[collapsible=icon]:hidden',\n showOnHover &&\n 'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground data-[state=open]:opacity-100 md:opacity-0',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarProvider,\n useSidebar,\n}\n","import * as React from 'react'\n\nconst MOBILE_BREAKPOINT = 768\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n }\n mql.addEventListener('change', onChange)\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n return !!isMobile\n}\n","'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/react/ui/utils'\nimport { XIcon } from 'lucide-react'\nimport { Dialog as SheetPrimitive } from 'radix-ui'\n\nfunction Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({ ...props }: React.ComponentProps<typeof SheetPrimitive.Trigger>) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({ ...props }: React.ComponentProps<typeof SheetPrimitive.Close>) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({ ...props }: React.ComponentProps<typeof SheetPrimitive.Portal>) {\n return <SheetPrimitive.Portal data-slot=\"sheet-portal\" {...props} />\n}\n\nfunction SheetOverlay({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Overlay>) {\n return (\n <SheetPrimitive.Overlay\n data-slot=\"sheet-overlay\"\n className={cn(\n 'fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction SheetContent({\n className,\n children,\n side = 'right',\n showCloseButton = true,\n ...props\n}: React.ComponentProps<typeof SheetPrimitive.Content> & {\n side?: 'top' | 'right' | 'bottom' | 'left'\n showCloseButton?: boolean\n}) {\n return (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Content\n data-slot=\"sheet-content\"\n className={cn(\n 'fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:animate-in data-[state=open]:duration-500',\n side === 'right' &&\n 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',\n side === 'left' &&\n 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',\n side === 'top' &&\n 'inset-x-0 top-0 h-auto border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',\n side === 'bottom' &&\n 'inset-x-0 bottom-0 h-auto border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <SheetPrimitive.Close className=\"absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none data-[state=open]:bg-secondary\">\n <XIcon className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n )}\n </SheetPrimitive.Content>\n </SheetPortal>\n )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"sheet-header\" className={cn('flex flex-col gap-1.5 p-4', className)} {...props} />\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"sheet-footer\" className={cn('mt-auto flex flex-col gap-2 p-4', className)} {...props} />\n}\n\nfunction SheetTitle({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Title>) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn('font-semibold text-foreground', className)}\n {...props}\n />\n )\n}\n\nfunction SheetDescription({ className, ...props }: React.ComponentProps<typeof SheetPrimitive.Description>) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n )\n}\n\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription }\n","import { Pin } from 'lucide-react'\nimport { Dialog } from 'radix-ui'\nimport { useEffect, useRef, useState } from 'react'\nimport type { Studio } from '../client/studio'\nimport { Logo } from './logo'\nimport { usePinnedTools } from './pinned-tools'\nimport { ToolIcon } from './tool-icon'\nimport { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from './ui/command'\nimport { Kbd, KbdGroup } from './ui/kbd'\n\nexport type StudioCommandMenuProps = {\n studio: Studio\n /** Path to the host's Studio route. Defaults to /studio. */\n studioPath?: string\n /** Optional host router navigation (for example, Next.js router.push). */\n navigate?: (href: string) => void\n}\n\n/** Mount once in the host layout, including /studio, to jump to any registered tool with ⌘/Ctrl+K. */\nexport function StudioCommandMenu({ studio, studioPath = '/studio', navigate }: StudioCommandMenuProps) {\n const { tools, pinned } = usePinnedTools(studio)\n const [open, setOpen] = useState(false)\n const opener = useRef<HTMLElement | null>(null)\n const input = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n // Studio forwards preview shortcuts to its parent window; don't open a second menu in the iframe.\n if (window.frameElement?.getAttribute('data-slot') === 'studio-preview') return\n const onKey = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.isComposing || event.altKey || !(event.metaKey || event.ctrlKey)) return\n if (event.key.toLowerCase() !== 'k') return\n event.preventDefault()\n if (event.repeat) return\n setOpen((current) => !current)\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [])\n\n const select = (id: string) => {\n setOpen(false)\n const target = new URL(studioPath, window.location.href)\n target.hash = id\n if (target.pathname === window.location.pathname) {\n // Keep the mounted Studio and its drafts alive when switching tools.\n window.location.hash = target.hash\n } else if (navigate) {\n navigate(`${target.pathname}${target.search}${target.hash}`)\n } else {\n window.location.assign(target.href)\n }\n }\n\n return (\n <Dialog.Root open={open} onOpenChange={setOpen}>\n <Dialog.Portal>\n <Dialog.Overlay data-slot=\"studio-command-overlay\" />\n <Dialog.Content\n data-slot=\"studio-command-menu\"\n onOpenAutoFocus={(event) => {\n event.preventDefault()\n opener.current = document.activeElement instanceof HTMLElement ? document.activeElement : null\n input.current?.focus()\n }}\n onCloseAutoFocus={(event) => {\n event.preventDefault()\n opener.current?.focus()\n }}\n >\n <div data-slot=\"studio-command-heading\">\n <Dialog.Title aria-label=\"Studio tools\">\n <Logo aria-hidden />\n <strong>STUDIO</strong>\n </Dialog.Title>\n <Dialog.Close aria-label=\"Close tool menu\">\n <Kbd>esc</Kbd>\n </Dialog.Close>\n </div>\n <Dialog.Description data-slot=\"studio-command-description\">Open a tool in Studio.</Dialog.Description>\n <Command label=\"Studio tools\" loop vimBindings={false}>\n <CommandInput ref={input} placeholder=\"Search tools…\" />\n <CommandList>\n <CommandEmpty>{studio.definitions.length ? 'No tools found.' : 'No tools registered yet.'}</CommandEmpty>\n {tools.map((tool) => (\n <CommandItem\n key={tool.id}\n value={tool.id}\n keywords={[tool.title ?? tool.id]}\n onSelect={() => select(tool.id)}\n >\n <ToolIcon icon={tool.icon} />\n <span data-slot=\"studio-command-label\">{tool.title ?? tool.id}</span>\n {pinned.has(tool.id) && <Pin aria-hidden />}\n </CommandItem>\n ))}\n </CommandList>\n </Command>\n <div data-slot=\"studio-command-footer\" aria-hidden>\n <span>\n <KbdGroup>\n <Kbd>↑</Kbd>\n <Kbd>↓</Kbd>\n </KbdGroup>\n navigate\n </span>\n <span>\n <Kbd>↵</Kbd> open tool\n </span>\n </div>\n </Dialog.Content>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","'use client'\n\nimport * as React from 'react'\nimport { Command as CommandPrimitive } from 'cmdk'\nimport { SearchIcon } from 'lucide-react'\nimport { cn } from '@/react/ui/utils'\n\n// shadcn/ui Command primitives; the host-safe menu theme is scoped in command-menu.css.\nfunction Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n 'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst CommandInput = React.forwardRef<\n React.ComponentRef<typeof CommandPrimitive.Input>,\n React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(function CommandInput({ className, ...props }, ref) {\n return (\n <div data-slot=\"command-input-wrapper\" className=\"flex h-9 items-center gap-2 border-b px-3\">\n <SearchIcon aria-hidden className=\"size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n ref={ref}\n data-slot=\"command-input\"\n className={cn(\n 'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n </div>\n )\n})\n\nfunction CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {\n return (\n <CommandPrimitive.List\n data-slot=\"command-list\"\n className={cn('max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto', className)}\n {...props}\n />\n )\n}\n\nfunction CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {\n return <CommandPrimitive.Empty data-slot=\"command-empty\" className=\"py-6 text-center text-sm\" {...props} />\n}\n\nfunction CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {\n return (\n <CommandPrimitive.Item\n data-slot=\"command-item\"\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n )\n}\n\nexport { Command, CommandInput, CommandList, CommandEmpty, CommandItem }\n","import { Check, ChevronDown, ChevronUp } from 'lucide-react'\nimport { Select } from 'radix-ui'\nimport { type ComponentProps } from 'react'\nimport { cn } from './ui/utils'\n\nexport type StudioSelectProps = ComponentProps<typeof Select.Root> & {\n label: string\n title?: string\n className?: string\n}\n\n/** Compact Radix select shared by canvas and activity toolbars. */\nexport function StudioSelect({ label, title, className, children, ...props }: StudioSelectProps) {\n return (\n <Select.Root {...props}>\n <Select.Trigger\n data-slot=\"select-trigger\"\n aria-label={label}\n title={title}\n className={cn(\n 'border-input text-foreground focus-visible:border-ring focus-visible:ring-ring/50 flex h-7 max-w-full shrink-0 items-center justify-between gap-2 rounded-md border bg-(--field) px-2 text-xs whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-(--field-hover) focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span:first-child]:truncate',\n className,\n )}\n >\n <Select.Value />\n <Select.Icon>\n <ChevronDown className=\"shrink-0 text-muted-foreground\" size={14} strokeWidth={1.5} aria-hidden />\n </Select.Icon>\n </Select.Trigger>\n <Select.Portal>\n <Select.Content\n className=\"relative z-50 max-h-(--radix-select-content-available-height) min-w-(--radix-select-trigger-width) overflow-hidden rounded-md border border-border bg-popover font-(family-name:--studio-font) text-xs font-normal text-popover-foreground shadow-md\"\n data-slot=\"select-content\"\n position=\"popper\"\n align=\"end\"\n sideOffset={6}\n >\n <Select.ScrollUpButton className=\"flex justify-center py-1\">\n <ChevronUp size={14} aria-hidden />\n </Select.ScrollUpButton>\n <Select.Viewport className=\"p-1\">{children}</Select.Viewport>\n <Select.ScrollDownButton className=\"flex justify-center py-1\">\n <ChevronDown size={14} aria-hidden />\n </Select.ScrollDownButton>\n </Select.Content>\n </Select.Portal>\n </Select.Root>\n )\n}\n\nexport function StudioSelectItem({ className, children, ...props }: ComponentProps<typeof Select.Item>) {\n return (\n <Select.Item\n data-slot=\"select-item\"\n className={cn(\n 'relative flex min-h-7 cursor-default items-center rounded-sm py-1.5 pr-8 pl-2 outline-none select-none data-[highlighted]:bg-(--field-hover) data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className,\n )}\n {...props}\n >\n <Select.ItemText>{children}</Select.ItemText>\n <Select.ItemIndicator className=\"absolute right-2\">\n <Check size={14} strokeWidth={1.5} aria-hidden />\n </Select.ItemIndicator>\n </Select.Item>\n )\n}\n","import { forwardRef, type ComponentPropsWithoutRef } from 'react'\nimport { cn } from './utils'\n\n/** Logical padding lets icon-bearing fields override only their leading inset. */\nexport const Input = forwardRef<HTMLInputElement, ComponentPropsWithoutRef<'input'>>(function Input(\n { className, ...props },\n ref,\n) {\n return (\n <input\n ref={ref}\n data-slot=\"input\"\n className={cn(\n 'border-input text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 h-8 w-full min-w-0 rounded-md border bg-transparent py-1 ps-3 pe-3 text-sm transition-[color,box-shadow] outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n )\n})\n"],"mappings":"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","names":["Pin","useEffect","useRef","useState","jsx","jsx","jsx","Slot","forwardRef","Slot","jsx","StudioSurface","Slot","StudioToolbar","jsx","forwardRef","Panel","Slot","PanelContent","jsx","jsxs","editable","jsx","useEffect","useState","forwardRef","useRef","useState","useState","jsx","jsxs","useState","jsx","jsxs","forwardRef","PreviewCanvas","useState","useRef","useEffect","useState","React","cva","Slot","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","open","cva","Slot","button","Fragment","jsx","jsxs","useState","useRef","useEffect","handle","compare","Pin","Pin","useEffect","useRef","useState","React","jsx","jsxs","CommandInput","jsx","jsxs","useState","useRef","useEffect","Pin","jsx","jsxs","forwardRef","jsx","forwardRef","Input"]}
1
+ {"version":3,"sources":["../src/react/studio.tsx","../package.json","../src/client/studio.ts","../src/react/hooks.ts","../src/react/inspector.tsx","../src/react/theme.ts","../src/react/tool-icon.tsx","../src/react/ui/button.tsx","../src/react/ui/utils.ts","../src/react/ui/kbd.tsx","../src/react/ui/tooltip.tsx","../src/react/shadow-root.tsx","../src/react/generated/studio.css","../src/react/shadow-css.ts","../src/react/ui/panel.tsx","../src/react/surface.tsx","../src/react/logo.tsx","../src/react/pinned-tools.ts","../src/react/preview-canvas.tsx","../src/react/canvas-toolbar.tsx","../src/react/session-flag.ts","../src/react/ui/sidebar.tsx","../src/react/ui/hooks/use-mobile.ts","../src/react/ui/sheet.tsx","../src/react/debug.tsx","../src/react/command-menu.tsx","../src/react/ui/command.tsx","../src/react/select.tsx","../src/react/select-labels.ts","../src/react/ui/input.tsx"],"sourcesContent":["import {\n ChevronLeft,\n ChevronRight,\n LoaderCircle,\n PanelLeftClose,\n PanelLeftOpen,\n Pin,\n PlugZap,\n Unplug,\n type LucideIcon,\n} from 'lucide-react'\nimport { useEffect, useRef, useState, type ComponentPropsWithRef, type ComponentType } from 'react'\nimport { version } from '../../package.json'\nimport type { Connection } from '../client/bridge'\nimport { postCompare, type Studio as StudioClient } from '../client/studio'\nimport { useStudio } from './hooks'\nimport { Inspector } from './inspector'\nimport { Logo } from './logo'\nimport { usePinnedTools } from './pinned-tools'\nimport { PreviewCanvas } from './preview-canvas'\nimport { useSessionFlag } from './session-flag'\nimport { activeElement, eventTarget, StudioShadowRoot } from './shadow-root'\nimport { ToolIcon } from './tool-icon'\nimport { Button } from './ui/button'\nimport { Kbd, KbdGroup } from './ui/kbd'\nimport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarProvider,\n useSidebar,\n} from './ui/sidebar'\nimport { Hint } from './ui/tooltip'\nimport { Panel } from './ui/panel'\nimport { cn } from './ui/utils'\n\nconst CONNECTION: Record<Connection['phase'], { icon: LucideIcon; tone: string; label: string }> = {\n connected: { icon: PlugZap, tone: 'text-success', label: 'Runtime connected' },\n connecting: { icon: LoaderCircle, tone: 'text-warning animate-spin', label: 'Connecting to runtime' },\n offline: { icon: Unplug, tone: 'text-destructive', label: 'Runtime offline' },\n local: { icon: Unplug, tone: 'text-faint', label: 'No runtime' },\n}\n\n/** Bottom of the sidebar: runtime status and the collapse toggle, both readable as icons when collapsed. */\nfunction StudioFooter({ connection }: { connection: Connection }) {\n const { state, toggleSidebar } = useSidebar()\n const { icon: Status, tone, label } = CONNECTION[connection.phase]\n const Toggle = state === 'expanded' ? PanelLeftClose : PanelLeftOpen\n return (\n <SidebarFooter>\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton tooltip={label} className=\"cursor-default hover:bg-transparent active:bg-transparent\">\n <Status className={tone} />\n <span className=\"text-clip! group-data-[collapsible=icon]:hidden\">{label}</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n <SidebarMenuItem>\n <SidebarMenuButton\n aria-label={`${state === 'expanded' ? 'Collapse' : 'Expand'} sidebar`}\n tooltip={`${state === 'expanded' ? 'Collapse' : 'Expand'} sidebar`}\n onClick={toggleSidebar}\n >\n <Toggle />\n <span className=\"text-clip! group-data-[collapsible=icon]:hidden\">Collapse</span>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n </SidebarFooter>\n )\n}\n\n/** ⌘/Ctrl shortcuts: B toggles both panels, S saves, K opens the host's tool menu. */\nconst SHORTCUTS = new Set(['b', 's', 'k'])\n/** Hold to show the saved config instead of the draft (Lightroom's before/after key). */\nconst COMPARE_KEY = '\\\\'\n\n// Duck-typed: keys pressed in the preview target the iframe window's own Element class. Read the target\n// through the shadow root, or window listeners would only see Studio's host element.\nconst editable = (event: Event) =>\n !!(eventTarget(event) as Partial<Element> | null)?.matches?.('input, textarea, select, [contenteditable]')\n\n/** ⌘/Ctrl+Z undoes; ⌘/Ctrl+Y or ⌘/Ctrl+Shift+Z redoes. Text fields keep their own native undo. */\nconst historyAction = (event: KeyboardEvent) => {\n if (!(event.metaKey || event.ctrlKey) || event.altKey || editable(event)) return null\n const key = event.key.toLowerCase()\n return key === 'z' ? (event.shiftKey ? 'redo' : 'undo') : key === 'y' ? 'redo' : null\n}\n\nconst isShortcut = (event: KeyboardEvent) =>\n ((event.metaKey || event.ctrlKey) && SHORTCUTS.has(event.key.toLowerCase())) ||\n (event.key === COMPARE_KEY && !editable(event)) ||\n !!historyAction(event)\n\n/**\n * Keys pressed inside the preview go to the iframe's window, not Studio's. Re-dispatch Studio's\n * shortcuts on the parent window so they work wherever focus is (same-origin previews only).\n */\nfunction forwardShortcuts(frame: HTMLIFrameElement) {\n const forward = (event: KeyboardEvent) => {\n if (event.defaultPrevented || !isShortcut(event)) return\n event.preventDefault()\n window.dispatchEvent(new KeyboardEvent(event.type, event))\n }\n try {\n frame.contentWindow?.addEventListener('keydown', forward)\n frame.contentWindow?.addEventListener('keyup', forward)\n } catch {\n // Cross-origin preview: its keys stay its own.\n }\n}\n\nexport interface StudioProps {\n studio: StudioClient\n /** Forward the iframe ref and native props to preserve Studio shortcuts and compare. */\n previewComponent?: ComponentType<ComponentPropsWithRef<'iframe'>> | 'iframe'\n /** Resolve config paths using the host's editor URL or source browser. */\n getConfigFileHref?: (file: string) => string\n}\n\n/** The /studio route: every registered tool, its preview, and its Tweakpane inspector. */\nexport function Studio({ studio, previewComponent, getConfigFileHref }: StudioProps) {\n useStudio(studio)\n const { tools, pinned, togglePin } = usePinnedTools(studio)\n // Connection and draft state only exist in the browser; skip SSR so hydration never disagrees.\n const [mounted, setMounted] = useState(false)\n // Layout survives a refresh in this tab: each hidden panel and the expanded canvas.\n const [sidebarHidden, setSidebarHidden] = useSessionFlag('joyco-studio:sidebar-hidden')\n const [inspectorHidden, setInspectorHidden] = useSessionFlag('joyco-studio:inspector-hidden')\n const [canvasExpanded, setCanvasExpanded] = useSessionFlag('joyco-studio:canvas-expanded')\n const [selected, setSelected] = useState<string | undefined>(studio.definitions[0]?.id)\n const preview = useRef<HTMLIFrameElement>(null)\n const definition = studio.definitions.find((tool) => tool.id === selected)\n // Preview-only tools have no handle, so nothing below compares, undoes, or inspects them.\n const handle = studio.tools.find((tool) => tool.definition.id === selected)\n const Preview = previewComponent ?? (definition?.previewLayout === 'custom' ? 'iframe' : PreviewCanvas)\n // Preview-only tools have no inspector to show, whatever its flag says.\n const hidden = { left: sidebarHidden, right: inspectorHidden || !handle }\n const show = { left: () => setSidebarHidden(false), right: () => setInspectorHidden(false) }\n const layout = useRef(hidden)\n layout.current = hidden\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.isComposing || event.altKey || !(event.metaKey || event.ctrlKey)) return\n if (event.key.toLowerCase() !== 'b') return\n event.preventDefault()\n if (event.repeat) return\n // Hidden panels stay mounted to preserve controls, but must release keyboard focus.\n const active = activeElement()\n if (\n active instanceof HTMLElement &&\n active.closest('[data-slot=\"sidebar-container\"], [data-slot=\"studio-inspector\"]')\n ) {\n active.blur()\n preview.current?.focus()\n }\n // Hide whatever is open; with both hidden, bring both back.\n const hide = !layout.current.left || !layout.current.right\n setSidebarHidden(hide)\n setInspectorHidden(hide)\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [])\n\n /** Compare here and in the preview iframe, which runs its own studio client. */\n const compare = (showSaved: boolean) => {\n if (!handle) return\n handle.compare(showSaved)\n postCompare(preview.current?.contentWindow, handle.definition.id, showSaved)\n }\n\n // Switching tools mid-compare must not leave the previous one showing its saved config.\n useEffect(() => () => handle?.compare(false), [handle])\n\n // Listeners live for the whole mount; they read the current tool through a ref so a re-render\n // (which comparing itself causes) never tears them down mid-hold.\n const current = useRef({ handle, compare })\n current.current = { handle, compare }\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== COMPARE_KEY || editable(event) || event.repeat) return\n event.preventDefault()\n const { handle, compare } = current.current\n compare(event.type === 'keydown' && !!handle?.dirty)\n }\n const release = () => current.current.compare(false)\n addEventListener('keydown', onKey)\n addEventListener('keyup', onKey)\n addEventListener('blur', release)\n return () => {\n release()\n removeEventListener('keydown', onKey)\n removeEventListener('keyup', onKey)\n removeEventListener('blur', release)\n }\n }, [])\n\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n const action = event.defaultPrevented ? null : historyAction(event)\n if (!action) return\n event.preventDefault()\n current.current.handle?.[action]()\n }\n addEventListener('keydown', onKey)\n return () => removeEventListener('keydown', onKey)\n }, [])\n\n useEffect(() => {\n const fromHash = () => {\n const id = decodeURIComponent(location.hash.slice(1))\n if (studio.definitions.some((tool) => tool.id === id)) setSelected(id)\n }\n setMounted(true)\n fromHash()\n addEventListener('hashchange', fromHash)\n return () => removeEventListener('hashchange', fromHash)\n }, [studio])\n\n if (!mounted) return null\n // shadcn's sidebar persists its state in a cookie; Studio renders client-only, so read it here.\n const sidebarOpen = !document.cookie.split('; ').includes('sidebar_state=false')\n\n return (\n <StudioShadowRoot>\n <SidebarProvider\n defaultOpen={sidebarOpen}\n data-preview-layout={previewComponent ? 'canvas' : (definition?.previewLayout ?? 'canvas')}\n data-sidebar-panel={hidden.left ? 'hidden' : 'shown'}\n className=\"studio-workspace relative h-svh min-h-0 overflow-hidden text-xs\"\n >\n {definition?.preview ? (\n <Preview\n data-slot=\"studio-preview\"\n ref={preview}\n key={definition.id}\n src={definition.preview}\n title={definition.title ?? definition.id}\n onLoad={(event) => forwardShortcuts(event.currentTarget)}\n {...(Preview === PreviewCanvas && { expanded: canvasExpanded, onExpandedChange: setCanvasExpanded })}\n />\n ) : (\n <div className=\"absolute inset-0 grid place-items-center text-faint\">\n {definition ? 'This tool has no preview' : 'No tools registered'}\n </div>\n )}\n\n {(['left', 'right'] as const)\n .filter((side) => hidden[side] && (side === 'left' || handle))\n .map((side) => {\n const Chevron = side === 'left' ? ChevronRight : ChevronLeft\n const label = side === 'left' ? 'Show tools' : 'Show inspector'\n return (\n <div\n key={side}\n data-slot=\"studio-panel-edge\"\n data-side={side}\n className={cn('group/edge absolute inset-y-0 z-20 w-8', side === 'left' ? 'left-0' : 'right-0')}\n >\n <Hint\n side={side === 'left' ? 'right' : 'left'}\n sideOffset={8}\n className=\"flex items-center gap-2\"\n content={\n <>\n {label} <span className=\"text-faint\">· both</span>\n <KbdGroup>\n <Kbd>⌘/Ctrl</Kbd>\n <Kbd>B</Kbd>\n </KbdGroup>\n </>\n }\n >\n <Panel asChild>\n <Button\n data-slot=\"studio-panel-reveal\"\n variant=\"ghost\"\n size=\"icon\"\n aria-label={label}\n onClick={show[side]}\n className={cn(\n 'absolute top-1/2 h-16 w-6 -translate-y-1/2 cursor-pointer px-0 text-sidebar-foreground opacity-0 transition-[translate,opacity] duration-200 ease-out hover:bg-sidebar/95 hover:text-foreground focus:translate-x-0 focus:opacity-100 group-hover/edge:translate-x-0 group-hover/edge:opacity-100 motion-reduce:transition-none [@media(hover:none)]:translate-x-0 [@media(hover:none)]:opacity-100',\n side === 'left'\n ? 'left-1 -translate-x-[calc(100%+0.25rem)]'\n : 'right-1 translate-x-[calc(100%+0.25rem)]',\n )}\n >\n <Chevron aria-hidden />\n </Button>\n </Panel>\n </Hint>\n </div>\n )\n })}\n\n <Sidebar\n collapsible=\"icon\"\n variant=\"floating\"\n inert={hidden.left}\n aria-hidden={hidden.left}\n className={cn(\n 'transition-[left,right,width,translate] duration-200 ease-out motion-reduce:transition-none',\n hidden.left && '-translate-x-[calc(100%+1rem)]',\n )}\n >\n {/* Expanded, the logo starts on the tool icons' left edge (16px). Collapsed, it centers on their\n 24px axis: 24px minus half the 14px-tall mark's width (352:144). Padding animates with the\n sidebar's own 200ms width transition, so the logo slides instead of jumping. */}\n <SidebarHeader className=\"h-10 flex-row items-center overflow-hidden py-0 pr-0 pl-4 transition-[padding] duration-200 ease-out group-data-[collapsible=icon]:pl-[calc(1.5rem-0.875rem*352/144/2)] motion-reduce:transition-none\">\n <span className=\"flex items-center gap-2.5 text-foreground\">\n {/* Fixed height, width follows the mark's aspect ratio. */}\n <Logo className=\"h-3.5 w-auto shrink-0\" />\n <strong className=\"tracking-[0.08em] whitespace-nowrap\">STUDIO</strong>\n <span data-slot=\"studio-version\" className=\"text-[10px] text-faint group-data-[collapsible=icon]:hidden\">\n v{version}\n </span>\n </span>\n </SidebarHeader>\n\n <SidebarContent>\n <SidebarGroup>\n <SidebarMenu>\n {tools.map((tool) => {\n const title = tool.title ?? tool.id\n const isPinned = pinned.has(tool.id)\n const { state, dirty } = studio.tools.find((handle) => handle.definition.id === tool.id) ?? {}\n const pinLabel = `${isPinned ? 'Unpin' : 'Pin'} ${title}`\n return (\n <SidebarMenuItem key={tool.id}>\n <SidebarMenuButton\n isActive={tool.id === selected}\n tooltip={title}\n onClick={() => (location.hash = tool.id)}\n >\n <span className=\"relative\">\n <ToolIcon icon={tool.icon} className=\"size-4\" />\n {dirty && (\n <span\n aria-label={state?.conflict ? 'Changed on disk' : 'Unsaved'}\n className={cn(\n 'absolute -top-0.5 -right-0.5 size-1.5 rounded-full',\n state?.conflict ? 'bg-destructive' : 'bg-warning',\n )}\n />\n )}\n </span>\n {/* Gone the moment the sidebar collapses; clipped (not ellipsized) while it expands. */}\n <span className=\"text-clip! group-data-[collapsible=icon]:hidden\">{title}</span>\n </SidebarMenuButton>\n <Hint content={pinLabel} side=\"right\">\n <SidebarMenuAction\n type=\"button\"\n aria-label={pinLabel}\n aria-pressed={isPinned}\n showOnHover={!isPinned}\n onClick={() => togglePin(tool.id)}\n className={cn(\n 'cursor-pointer [&>svg]:size-3 [@media(hover:none)]:opacity-100',\n isPinned && 'text-sidebar-primary',\n )}\n >\n <Pin aria-hidden fill={isPinned ? 'currentColor' : 'none'} />\n </SidebarMenuAction>\n </Hint>\n </SidebarMenuItem>\n )\n })}\n </SidebarMenu>\n </SidebarGroup>\n </SidebarContent>\n <StudioFooter connection={studio.connection} />\n </Sidebar>\n\n {handle && (\n <Panel asChild>\n <aside\n data-slot=\"studio-inspector\"\n inert={hidden.right}\n aria-hidden={hidden.right}\n className={cn(\n 'absolute inset-y-2 right-2 z-10 flex w-(--studio-inspector-width) flex-col gap-1 p-1 transition-transform duration-200 ease-out motion-reduce:transition-none',\n hidden.right && 'translate-x-[calc(100%+1rem)]',\n )}\n >\n <Inspector\n key={handle.definition.id}\n studio={studio}\n handle={handle}\n onCompare={compare}\n fileHref={getConfigFileHref?.(handle.definition.file)}\n />\n </aside>\n </Panel>\n )}\n </SidebarProvider>\n </StudioShadowRoot>\n )\n}\n","{\n \"name\": \"@joycostudio/studio\",\n \"version\": \"0.1.4\",\n \"description\": \"Plug project-specific tools into a /studio route, a floating debug pane, and MCP agents.\",\n \"type\": \"module\",\n \"license\": \"ISC\",\n \"author\": \"joyco.studio\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/joyco-studio/studio.git\",\n \"directory\": \"packages/studio\"\n },\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org\",\n \"access\": \"public\"\n },\n \"files\": [\n \"dist\"\n ],\n \"bin\": {\n \"studio\": \"./dist/cli.js\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"./client\": {\n \"types\": \"./dist/client.d.ts\",\n \"default\": \"./dist/client.js\"\n },\n \"./react\": {\n \"types\": \"./dist/react.d.ts\",\n \"default\": \"./dist/react.js\"\n },\n \"./runtime\": {\n \"types\": \"./dist/runtime.d.ts\",\n \"default\": \"./dist/runtime.js\"\n },\n \"./styles.css\": \"./dist/styles.css\",\n \"./command-menu.css\": \"./dist/command-menu.css\",\n \"./next\": {\n \"types\": \"./dist/next.d.ts\",\n \"default\": \"./dist/next.js\"\n },\n \"./controls\": {\n \"types\": \"./dist/controls.d.ts\",\n \"default\": \"./dist/controls.js\"\n },\n \"./next/config\": {\n \"types\": \"./dist/next-config.d.ts\",\n \"default\": \"./dist/next-config.js\"\n }\n },\n \"scripts\": {\n \"build\": \"pnpm build:shadow-css && tsup && tailwindcss -i src/react/styles.css -o dist/styles.css --minify && cp src/react/command-menu-export.css dist/command-menu.css\",\n \"dev\": \"pnpm build:shadow-css && pnpm run --parallel \\\"/^dev:/\\\"\",\n \"test\": \"vitest run\",\n \"test:browser\": \"STUDIO_TEST_BROWSER=1 vitest run test/browser-sync.test.ts\",\n \"test:capture\": \"STUDIO_TEST_CAPTURE=1 vitest run test/capture.test.ts\",\n \"typecheck\": \"tsc --noEmit\",\n \"dev:js\": \"tsup --watch\",\n \"dev:css\": \"tailwindcss -i src/react/styles.css -o dist/styles.css --watch=always\",\n \"build:shadow-css\": \"tailwindcss -i src/react/shadow.css -o src/react/generated/studio.css --minify\",\n \"dev:shadow-css\": \"tailwindcss -i src/react/shadow.css -o src/react/generated/studio.css --minify --watch=always\"\n },\n \"dependencies\": {\n \"@base-ui/react\": \"^1.9.0\",\n \"@modelcontextprotocol/node\": \"^2.1.1\",\n \"@modelcontextprotocol/server\": \"^2.3.1\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"cmdk\": \"^1.1.1\",\n \"cn\": \"^0.4.0\",\n \"jiti\": \"^2.7.0\",\n \"lucide\": \"^1.55.0\",\n \"lucide-react\": \"^1.55.0\",\n \"playwright\": \"^1.64.0\",\n \"radix-ui\": \"^1.8.0\",\n \"tailwind-merge\": \"^3.7.0\",\n \"ws\": \"^8.22.0\",\n \"zod\": \"^4.6.6\",\n \"typescript\": \"^5.9.3\"\n },\n \"peerDependencies\": {\n \"@joycostudio/xyz\": \"^1.4.0\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\",\n \"tweakpane\": \"^4.0.5\"\n },\n \"peerDependenciesMeta\": {\n \"react\": {\n \"optional\": true\n },\n \"tweakpane\": {\n \"optional\": true\n },\n \"react-dom\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@joycostudio/xyz\": \"^1.4.0\",\n \"@modelcontextprotocol/client\": \"^2.3.1\",\n \"@tailwindcss/cli\": \"^4.3.3\",\n \"@tweakpane/core\": \"^2.0.5\",\n \"@types/node\": \"^24.19.2\",\n \"@types/react\": \"^19.3.0\",\n \"@types/react-dom\": \"^19.3.0\",\n \"@types/ws\": \"^8.18.2\",\n \"react\": \"^19.3.0\",\n \"react-dom\": \"^19.3.0\",\n \"tailwindcss\": \"^4.3.3\",\n \"tsup\": \"^8.5.1\",\n \"tw-animate-css\": \"^1.4.0\",\n \"tweakpane\": \"^4.0.5\",\n \"vitest\": \"^5.0.3\"\n },\n \"sideEffects\": [\n \"*.css\"\n ]\n}\n","import {\n button,\n type DebugDefinition,\n type DebugField,\n type DebugFolder,\n type DebugSchema,\n schemaValues,\n} from '@joycostudio/xyz/debug'\nimport { changedPaths } from '../core/diff'\nimport type { ToolState } from '../core/protocol'\nimport { error, type Result } from '../core/result'\nimport { hasConfig, type StudioTool, type ToolDefinition, type ToolReference } from '../core/tool'\nimport { connectBridge, type BridgeClient, type Connection } from './bridge'\nimport { connectBrowserSync } from './browser-sync'\nimport { createHistory, writePath } from './history'\nimport { assignDeep, live } from './live'\n\nexport type ToolHandle<TConfig extends object = any> = {\n readonly definition: ToolDefinition<TConfig>\n /** The live config. Writes sync to same-origin pages and, when connected, the runtime. */\n readonly config: TConfig\n /** Runtime-owned state; null until the runtime answers (always null without one). */\n readonly state: ToolState<TConfig> | null\n /** Bumps on every config change. Handy as a React snapshot. */\n readonly version: number\n /** Called after every config change, local or remote. */\n subscribe(listener: (config: TConfig) => void): () => void\n /** The tool's Xyz schema bound to the live config. */\n controls(): DebugSchema\n /** Xyz `Debuggable`: `debugManager.register(handle)` mounts this tool in the app's floating pane. */\n debug(): DebugFolder\n /** The config on disk: the runtime's saved value or, until one answers, the bundled `initial`. */\n readonly saved: TConfig\n /** Dotted paths where the draft differs from `saved`. Tracked locally, so it works without a runtime too. */\n readonly changes: string[]\n /** The draft differs from `saved`. */\n readonly dirty: boolean\n /** True while `compare(true)` shows the saved config in place of the draft. */\n readonly comparing: boolean\n /**\n * Temporarily show `saved` (true) or go back to the draft (false). Local only: nothing\n * reaches the runtime, and edits made while comparing are dropped when it ends.\n */\n compare(showSaved: boolean): void\n /** True when `undo()` has an edit made on this page to step back through. */\n readonly canUndo: boolean\n readonly canRedo: boolean\n /**\n * Step back through edits made on this page (a slider drag counts as one), then sync the result like any\n * other edit. Only the leaves each edit changed are restored. Returns false with nothing to undo or while comparing.\n */\n undo(): boolean\n redo(): boolean\n save(options?: { force?: boolean }): Promise<Result<ToolState<TConfig>>>\n discard(): Promise<Result<ToolState<TConfig>>>\n}\n\nexport type Studio = {\n /** Every registered tool in order, including preview-only ones. */\n readonly definitions: readonly StudioTool[]\n /** A handle per tool with a config. Preview-only tools have none. */\n readonly tools: readonly ToolHandle[]\n tool<TConfig extends object>(definition: ToolReference<TConfig>): ToolHandle<TConfig>\n readonly connection: Connection\n /** Bumps on connection or any tool state change. */\n readonly version: number\n subscribe(listener: () => void): () => void\n close(): void\n}\n\nexport type StudioOptions = {\n tools: readonly StudioTool[]\n /**\n * Runtime bridge URL (e.g. `ws://127.0.0.1:5179`). Omit or pass false for browser-only syncing, as in production.\n * Only browsers connect, so a module-scope `createStudio` is safe to evaluate during SSR.\n */\n runtime?: string | false\n}\n\nconst COMPARE_MESSAGE = 'joyco-studio:compare'\ntype CompareMessage = { type: typeof COMPARE_MESSAGE; tool: string; showSaved: boolean }\n\n/** Make the studio running in `target` (e.g. a preview iframe) compare `tool` as well. */\nexport function postCompare(target: Window | null | undefined, tool: string, showSaved: boolean) {\n const message: CompareMessage = { type: COMPARE_MESSAGE, tool, showSaved }\n target?.postMessage(message, location.origin)\n}\n\n/** Mark every value control live so a pane registered with `registerFrame` reflects remote edits. */\nfunction liveSchema(schema: DebugSchema): DebugSchema {\n return Object.fromEntries(\n Object.entries(schema).map(([key, field]): [string, DebugField] => {\n if (field.kind === 'button') return [key, field]\n if (field.kind === 'folder')\n return [\n key,\n { ...field, definition: { ...field.definition, schema: () => liveSchema(field.definition.schema()) } },\n ]\n return [key, { ...field, live: true }]\n }),\n )\n}\n\n/**\n * Xyz `extend` for a folder bound to `handle.controls()` (optionally followed by more fields, as in `debug()`):\n * double-clicking a slider resets it to its saved value.\n */\nexport function resetSlidersOnDoubleClick(handle: ToolHandle): NonNullable<DebugDefinition['extend']> {\n return (folder, { fields }) => {\n const sliders = fields().filter(({ field }) => field.kind === 'slider')\n const onDoubleClick = (event: MouseEvent) => {\n // Double-clicking the number input selects its text instead.\n if (handle.comparing || (event.target as Element).closest('input')) return\n const slider = sliders.find(({ blade }) => blade.element.contains(event.target as Node))\n if (slider?.field.kind !== 'slider') return\n const saved = slider.path.reduce<unknown>(\n (values, key) => (values as Record<string, unknown> | undefined)?.[key],\n schemaValues(handle.definition.controls(structuredClone(handle.saved))),\n )\n if (typeof saved === 'number') slider.field.write(saved)\n }\n folder.element.addEventListener('dblclick', onDoubleClick)\n return () => folder.element.removeEventListener('dblclick', onDoubleClick)\n }\n}\n\n/** A `registerFrame` for Xyz's `DebugManager` / `bindDebugSchema`: refreshes live controls every animation frame. */\nexport function everyFrame(refresh: () => void) {\n let frame = requestAnimationFrame(function tick() {\n refresh()\n frame = requestAnimationFrame(tick)\n })\n return () => cancelAnimationFrame(frame)\n}\n\n/** One studio per runtime URL (or local tool set) per page; replace HMR instances without leaking transports. */\nconst instances: Map<string, Studio> = ((globalThis as { __joycoStudio?: Map<string, Studio> }).__joycoStudio ??=\n new Map())\n\nexport function createStudio(config: StudioOptions, options: Pick<StudioOptions, 'runtime'> = {}): Studio {\n const { tools } = config\n const runtime = options.runtime ?? config.runtime\n const instanceKey = runtime || JSON.stringify(tools.map(({ id, file }) => [id, file]).sort())\n let bridge: BridgeClient | null = null\n let connection: Connection = { phase: runtime ? 'connecting' : 'local' }\n let version = 0\n const studioListeners = new Set<() => void>()\n const touch = () => {\n version++\n for (const listener of studioListeners) listener()\n }\n\n const createHandle = <TConfig extends object>(definition: ToolDefinition<TConfig>) => {\n const raw = structuredClone(definition.initial)\n const listeners = new Set<(config: TConfig) => void>()\n let pushing: Promise<unknown> = Promise.resolve()\n let scheduled = false\n /** The draft to restore while comparing; null when showing the draft. */\n let stashed: TConfig | null = null\n const history = createHistory()\n /** A copy of `raw` as of the last change, so the next local edit can be diffed against it. */\n let snapshot = structuredClone(raw)\n\n const changed = () => {\n snapshot = structuredClone(raw)\n handle.version++\n for (const listener of listeners) listener(handle.config)\n touch()\n }\n const adopt = (state: ToolState) => {\n handle.state = state as ToolState<TConfig>\n touch()\n }\n const receive = (state: ToolState) => {\n if (stashed) stashed = structuredClone(state.draft.value) as TConfig\n else assignDeep(raw as Record<string, unknown>, state.draft.value as Record<string, unknown>)\n adopt(state)\n if (!stashed) changed()\n browserSync?.publish(state.draft.value as TConfig)\n }\n const resync = async () => {\n const result = await bridge?.request('tool.get', { tool: definition.id })\n if (result?.ok) receive(result.data)\n }\n const push = () => {\n if (scheduled || !bridge) return\n scheduled = true\n pushing = Promise.resolve().then(async () => {\n scheduled = false\n const result = await bridge?.request('tool.update', { tool: definition.id, value: raw })\n if (!result) return\n if (result.ok) adopt(result.data)\n else if (result.error !== 'runtime_unavailable') {\n console.warn(`[studio] ${definition.id}: ${result.message ?? result.error}`)\n await resync()\n }\n })\n }\n\n const edited = () => {\n changed()\n if (!stashed) {\n browserSync?.publish(raw)\n push()\n }\n }\n const restore = (patch: ReturnType<typeof history.undo>) => {\n if (!patch) return false\n for (const { path, value } of patch) writePath(raw as Record<string, unknown>, path, value)\n edited()\n return true\n }\n\n const handle = {\n definition,\n config: live(raw, () => {\n if (!stashed) history.record(snapshot, raw)\n edited()\n }),\n state: null as ToolState<TConfig> | null,\n version: 0,\n get saved(): TConfig {\n return handle.state?.saved.value ?? definition.initial\n },\n get changes() {\n return changedPaths(handle.saved, stashed ?? raw)\n },\n get dirty() {\n return handle.changes.length > 0\n },\n comparing: false,\n compare(showSaved: boolean) {\n if (showSaved === handle.comparing) return\n if (showSaved) stashed = structuredClone(raw)\n const next = showSaved ? handle.saved : stashed!\n assignDeep(raw as Record<string, unknown>, next as Record<string, unknown>)\n if (!showSaved) stashed = null\n handle.comparing = showSaved\n changed()\n },\n get canUndo() {\n return history.canUndo\n },\n get canRedo() {\n return history.canRedo\n },\n undo: () => !stashed && restore(history.undo()),\n redo: () => !stashed && restore(history.redo()),\n subscribe(listener: (config: TConfig) => void) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n controls: () => definition.controls(handle.config),\n debug(): DebugFolder {\n const actions: DebugSchema = runtime\n ? {\n save: button('Save', () => handle.save().then(fail), 'Saved ✓'),\n discard: button('Discard', () => handle.discard().then(fail), 'Discarded'),\n }\n : {}\n return {\n title: definition.title ?? definition.id,\n schema: () => ({ ...liveSchema(handle.controls()), ...actions }),\n extend: resetSlidersOnDoubleClick(handle),\n }\n },\n async save({ force = false } = {}) {\n if (!bridge) return error('runtime_unavailable')\n await pushing\n const revision = handle.state?.draft.revision\n if (revision === undefined) return error('runtime_unavailable')\n const result = await bridge.request('tool.save', { tool: definition.id, revision, force })\n if (result.ok) adopt(result.data)\n return result as Result<ToolState<TConfig>>\n },\n async discard() {\n if (!bridge) return error('runtime_unavailable')\n await pushing\n const before = snapshot\n const result = await bridge.request('tool.discard', { tool: definition.id })\n if (result.ok) {\n receive(result.data)\n // Discarding is undoable, as its own step.\n if (!stashed) history.record(before, raw, { merge: false })\n }\n return result as Result<ToolState<TConfig>>\n },\n receive,\n resync,\n close: () => browserSync?.close(),\n }\n const browserSync = connectBrowserSync(definition, runtime, {\n enabled: () => connection.phase !== 'connected',\n receive(value) {\n if (stashed) {\n // The shown saved config stays put, but `changes` and `dirty` read the new draft.\n stashed = value\n touch()\n } else {\n assignDeep(raw as Record<string, unknown>, value as Record<string, unknown>)\n changed()\n }\n },\n })\n return handle\n }\n\n const handles = new Map(tools.filter(hasConfig).map((definition) => [definition.id, createHandle(definition)]))\n\n // /studio asks its same-origin preview iframe to compare too (see `postCompare`).\n const onMessage = (event: MessageEvent) => {\n const message = event.data as CompareMessage | undefined\n if (event.origin !== location.origin || message?.type !== COMPARE_MESSAGE) return\n handles.get(message.tool)?.compare(message.showSaved)\n }\n if (typeof window !== 'undefined') window.addEventListener?.('message', onMessage)\n\n if (runtime && typeof window !== 'undefined') {\n bridge = connectBridge(runtime, {\n state: (state) => handles.get(state.tool)?.receive(state),\n connection(next) {\n connection = next\n touch()\n if (next.phase === 'connected') for (const handle of handles.values()) void handle.resync()\n },\n })\n }\n\n const studio: Studio = {\n definitions: tools,\n tools: [...handles.values()],\n tool<TConfig extends object>(definition: ToolDefinition<TConfig>) {\n const handle = handles.get(definition.id)\n if (!handle) throw new Error(`[studio] tool \"${definition.id}\" was not passed to createStudio`)\n return handle as unknown as ToolHandle<TConfig>\n },\n get connection() {\n return connection\n },\n get version() {\n return version\n },\n subscribe(listener) {\n studioListeners.add(listener)\n return () => void studioListeners.delete(listener)\n },\n close() {\n bridge?.close()\n for (const handle of handles.values()) handle.close()\n studioListeners.clear()\n if (typeof window !== 'undefined') window.removeEventListener?.('message', onMessage)\n if (instances.get(instanceKey) === studio) instances.delete(instanceKey)\n },\n }\n if (typeof window !== 'undefined') {\n instances.get(instanceKey)?.close()\n instances.set(instanceKey, studio)\n }\n return studio\n}\n\nfunction fail(result: Result<unknown>) {\n if (!result.ok) throw new Error(result.message ?? result.error)\n}\n","import { useSyncExternalStore } from 'react'\nimport type { Studio, ToolHandle } from '../client/studio'\n\n/** Re-render on connection and tool state changes. */\nexport function useStudio(studio: Studio) {\n useSyncExternalStore(\n studio.subscribe,\n () => studio.version,\n () => 0,\n )\n return studio\n}\n\n/** The tool's live config; re-renders on every change, local or remote. */\nexport function useToolConfig<TConfig extends object>(handle: ToolHandle<TConfig>) {\n useSyncExternalStore(\n handle.subscribe,\n () => handle.version,\n () => 0,\n )\n return handle.config\n}\n","import { bindDebugSchema } from '@joycostudio/xyz/debug'\nimport { SquareSplitHorizontal } from 'lucide-react'\nimport { useEffect, useRef, useState } from 'react'\nimport { resetSlidersOnDoubleClick, type Studio, type ToolHandle } from '../client/studio'\nimport type { Result } from '../core/result'\nimport { useStudio } from './hooks'\nimport { tweakpaneTheme } from './theme'\nimport { ToolIcon } from './tool-icon'\nimport { Button } from './ui/button'\nimport { Kbd, KbdGroup } from './ui/kbd'\nimport { Hint } from './ui/tooltip'\nimport { PanelContent, PanelFooter, PanelHeader } from './ui/panel'\n\nfunction describe(studio: Studio, handle: ToolHandle) {\n const { state } = handle\n if (handle.comparing) return { tone: 'text-sky-400', text: 'Showing saved' }\n if (studio.connection.phase !== 'connected') return { tone: 'text-faint', text: 'Not persisting' }\n if (!state) return { tone: 'text-destructive', text: 'Restart studio dev' }\n if (state.conflict) return { tone: 'text-destructive', text: 'Changed on disk' }\n if (state.dirty) return { tone: 'text-warning', text: 'Unsaved' }\n return { tone: 'text-success', text: state.saved.hash ? 'Saved' : 'Not on disk yet' }\n}\n\n/**\n * Tweakpane (and its plugins) inject their CSS into `document.head`, which doesn't reach Studio's shadow\n * root. Copy those styles next to the pane; Tweakpane skips ids it has already injected in the head.\n */\nfunction adoptTweakpaneStyles(container: HTMLElement) {\n const root = container.getRootNode()\n if (!(root instanceof ShadowRoot)) return\n for (const style of document.head.querySelectorAll<HTMLStyleElement>('style[data-tp-style]')) {\n if (!root.querySelector(`style[data-tp-style=\"${style.dataset.tpStyle}\"]`)) root.append(style.cloneNode(true))\n }\n}\n\n/** The tool's Tweakpane controls, framed by the Studio's own status and save/discard actions. */\nexport function Inspector({\n studio,\n handle,\n onCompare,\n fileHref,\n}: {\n studio: Studio\n handle: ToolHandle\n /** Show the saved config (true) or the draft (false), in the preview as well. */\n onCompare: (showSaved: boolean) => void\n fileHref?: string\n}) {\n useStudio(studio)\n const container = useRef<HTMLDivElement>(null)\n const pane = useRef<{ disabled: boolean } | null>(null)\n const [failure, setFailure] = useState<string | null>(null)\n\n const run = (action: Promise<Result<unknown>>) =>\n void action.then((result) => setFailure(result.ok ? null : (result.message ?? result.error)))\n const save = (force = false) => run(handle.save({ force }))\n\n useEffect(() => {\n let disposed = false\n let teardown = () => {}\n void import('tweakpane').then(({ Pane }) => {\n if (disposed || !container.current) return\n const instance = new Pane({ container: container.current })\n pane.current = instance\n const bound = bindDebugSchema(instance, {\n schema: () => handle.controls(),\n extend: resetSlidersOnDoubleClick(handle),\n })\n adoptTweakpaneStyles(container.current)\n const unsubscribe = handle.subscribe(() => bound.refresh())\n teardown = () => {\n unsubscribe()\n bound.dispose()\n instance.dispose()\n pane.current = null\n }\n })\n return () => {\n disposed = true\n teardown()\n }\n }, [handle])\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 's' || !(event.metaKey || event.ctrlKey)) return\n event.preventDefault()\n if (handle.state?.dirty) save()\n }\n addEventListener('keydown', onKeyDown)\n return () => removeEventListener('keydown', onKeyDown)\n })\n\n // While comparing, the controls show the saved config: read-only, so nothing edits the wrong version.\n useEffect(() => {\n if (pane.current) pane.current.disabled = handle.comparing\n })\n\n const { definition, state } = handle\n const ConfigFile = fileHref ? 'a' : 'span'\n const status = describe(studio, handle)\n const editable = studio.connection.phase === 'connected' && !!state?.dirty && !handle.comparing\n // Shown like the controls' labels: `vignette.amount` reads as \"Vignette › Amount\".\n const changes = handle.changes.map((path) =>\n path\n .split('.')\n .map((key) => key.charAt(0).toUpperCase() + key.slice(1))\n .join(' › '),\n )\n\n return (\n <>\n <PanelHeader>\n <strong className=\"flex min-w-0 items-center gap-2 text-foreground\">\n <ToolIcon icon={definition.icon} className=\"size-3.5 shrink-0\" />\n <span className=\"truncate\" title={definition.title ?? definition.id}>\n {definition.title ?? definition.id}\n </span>\n </strong>\n <div className=\"mt-1 flex items-center gap-3 pl-5.5 text-[11px]\">\n <ConfigFile\n data-slot=\"studio-config-file\"\n className=\"min-w-0 flex-1 truncate text-muted-foreground\"\n href={fileHref}\n title={fileHref ? `Open ${definition.file}` : definition.file}\n >\n {definition.file}\n </ConfigFile>\n <span\n className={`flex shrink-0 items-center gap-1.5 ${status.tone}`}\n title={state ? `Draft revision ${state.draft.revision}` : undefined}\n >\n <span aria-hidden=\"true\" className=\"size-1.5 rounded-full bg-current\" />\n {status.text}\n </span>\n </div>\n </PanelHeader>\n\n <PanelContent ref={container} data-slot=\"studio-controls\" style={tweakpaneTheme} />\n\n <PanelFooter>\n {failure && <div className=\"text-destructive\">{failure}</div>}\n {changes.length > 0 && (\n <div className=\"truncate text-muted-foreground\" title={changes.join(', ')}>\n {changes.length} changed: <span className=\"text-foreground\">{changes.join(', ')}</span>\n </div>\n )}\n <div className=\"flex gap-2\">\n <Hint\n className=\"flex items-center gap-2\"\n content={\n <>\n Hold to compare with saved <Kbd>{'\\\\'}</Kbd>\n </>\n }\n >\n <Button\n variant=\"secondary\"\n size=\"icon-sm\"\n aria-label=\"Hold to compare with saved\"\n aria-pressed={handle.comparing}\n disabled={!handle.dirty && !handle.comparing}\n className=\"shrink-0 aria-pressed:bg-primary aria-pressed:text-primary-foreground\"\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId)\n onCompare(true)\n }}\n onPointerUp={() => onCompare(false)}\n onPointerCancel={() => onCompare(false)}\n >\n <SquareSplitHorizontal />\n </Button>\n </Hint>\n <Button\n variant=\"secondary\"\n size=\"sm\"\n className=\"flex-1\"\n disabled={!editable}\n onClick={() => run(handle.discard())}\n >\n Discard\n </Button>\n {state?.conflict ? (\n <Button variant=\"destructive\" size=\"sm\" className=\"flex-1\" onClick={() => save(true)}>\n Overwrite file\n </Button>\n ) : (\n <Button size=\"sm\" className=\"flex-1\" disabled={!editable} onClick={() => save()}>\n Save\n <KbdGroup>\n <Kbd>⌘</Kbd>\n <Kbd>S</Kbd>\n </KbdGroup>\n </Button>\n )}\n </div>\n </PanelFooter>\n </>\n )\n}\n","import type { CSSProperties } from 'react'\n\n/** Tweakpane reads its theme from inherited custom properties; point them at the Studio palette in styles.css. */\nexport const tweakpaneTheme = {\n '--tp-base-background-color': 'transparent',\n '--tp-base-shadow-color': 'transparent',\n '--tp-base-border-radius': '0px',\n '--tp-base-font-family': 'var(--studio-font)',\n '--tp-blade-border-radius': 'var(--radius)',\n '--tp-blade-horizontal-padding': '4px',\n '--tp-blade-value-width': '168px',\n '--tp-container-horizontal-padding': '8px',\n '--tp-container-vertical-padding': '6px',\n '--tp-container-unit-size': '22px',\n '--tp-container-unit-spacing': '6px',\n '--tp-container-background-color': 'var(--card)',\n '--tp-container-background-color-hover': 'var(--field)',\n '--tp-container-background-color-focus': 'var(--field-hover)',\n '--tp-container-background-color-active': 'var(--field-active)',\n '--tp-container-foreground-color': 'var(--muted-foreground)',\n '--tp-input-background-color': 'var(--field)',\n '--tp-input-background-color-hover': 'var(--field-hover)',\n '--tp-input-background-color-focus': 'var(--field-active)',\n '--tp-input-background-color-active': 'var(--field-active)',\n '--tp-input-foreground-color': 'var(--foreground)',\n // Buttons and slider knobs: lighter than fields so the knob reads against the track.\n '--tp-button-background-color': 'var(--knob)',\n '--tp-button-background-color-hover': 'var(--knob-hover)',\n '--tp-button-background-color-focus': 'var(--knob-hover)',\n '--tp-button-background-color-active': 'var(--muted-foreground)',\n '--tp-button-foreground-color': 'var(--foreground)',\n '--tp-groove-foreground-color': 'var(--border)',\n '--tp-label-foreground-color': 'var(--muted-foreground)',\n '--tp-monitor-background-color': 'var(--card)',\n '--tp-monitor-foreground-color': 'var(--muted-foreground)',\n} as CSSProperties\n","import { SlidersHorizontal } from 'lucide'\nimport type { SVGProps } from 'react'\nimport type { ToolIcon as ToolIconData } from '../core/tool'\n\nconst camel = (name: string) => name.replace(/-([a-z])/g, (_, char: string) => char.toUpperCase())\n\n/** Render a tool's icon data as a Lucide-style stroke icon; tools without one get a generic sliders icon. */\nexport function ToolIcon({ icon = SlidersHorizontal, ...props }: { icon?: ToolIconData } & SVGProps<SVGSVGElement>) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n {...props}\n >\n {icon.map(([Tag, attrs], index) => {\n const Element = Tag as 'path'\n return (\n <Element\n key={index}\n {...Object.fromEntries(Object.entries(attrs).map(([name, value]) => [camel(name), value]))}\n />\n )\n })}\n </svg>\n )\n}\n","import * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/react/ui/utils'\nimport { Slot } from 'radix-ui'\n\nconst buttonVariants = cva(\n \"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 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 hover:bg-primary/90',\n destructive:\n 'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40',\n outline:\n 'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',\n secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',\n ghost: 'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',\n link: 'text-primary underline-offset-4 hover:underline',\n },\n size: {\n default: 'h-9 px-4 py-2 has-[>svg]:px-3',\n xs: \"h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3\",\n sm: 'h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5',\n lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',\n icon: 'size-9',\n 'icon-xs': \"size-6 rounded-md [&_svg:not([class*='size-'])]:size-3\",\n 'icon-sm': 'size-8',\n 'icon-lg': 'size-10',\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 asChild = false,\n ...props\n}: React.ComponentProps<'button'> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot.Root : 'button'\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\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","import type * as React from 'react'\nimport { cn } from '@/react/ui/utils'\n\nfunction Kbd({ className, ...props }: React.ComponentProps<'kbd'>) {\n return (\n <kbd\n data-slot=\"kbd\"\n className={cn(\n 'bg-muted text-muted-foreground border-border pointer-events-none inline-flex h-5 w-fit min-w-5 items-center justify-center gap-1 rounded-sm border border-b-2 px-1 font-mono text-xs font-normal select-none',\n \"[&_svg:not([class*='size-'])]:size-3\",\n '[[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction KbdGroup({ className, ...props }: React.ComponentProps<'span'>) {\n return <span data-slot=\"kbd-group\" className={cn('inline-flex items-center gap-1', className)} {...props} />\n}\n\nexport { Kbd, KbdGroup }\n","import * as React from 'react'\nimport { Tooltip as TooltipPrimitive } from '@base-ui/react/tooltip'\nimport { cn } from '@/react/ui/utils'\nimport { usePortalContainer } from '@/react/shadow-root'\n\nfunction TooltipProvider({ delay = 0, ...props }: TooltipPrimitive.Provider.Props) {\n return <TooltipPrimitive.Provider data-slot=\"tooltip-provider\" delay={delay} {...props} />\n}\n\nfunction Tooltip({ ...props }: TooltipPrimitive.Root.Props) {\n return <TooltipPrimitive.Root data-slot=\"tooltip\" {...props} />\n}\n\nfunction TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {\n return <TooltipPrimitive.Trigger data-slot=\"tooltip-trigger\" {...props} />\n}\n\ntype TooltipContentProps = TooltipPrimitive.Popup.Props &\n Pick<TooltipPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>\n\nfunction TooltipContent({\n className,\n side = 'top',\n sideOffset = 0,\n align = 'center',\n alignOffset = 0,\n children,\n ...props\n}: TooltipContentProps) {\n return (\n <TooltipPrimitive.Portal container={usePortalContainer()}>\n <TooltipPrimitive.Positioner\n align={align}\n alignOffset={alignOffset}\n side={side}\n sideOffset={sideOffset}\n className=\"isolate z-50\"\n >\n <TooltipPrimitive.Popup\n data-slot=\"tooltip-content\"\n className={cn(\n 'z-50 w-fit origin-(--transform-origin) rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background 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-[instant]:animate-none 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 {children}\n <TooltipPrimitive.Arrow className=\"z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground data-[side=bottom]:top-1 data-[side=left]:top-1/2! data-[side=left]:-right-1 data-[side=left]:-translate-y-1/2 data-[side=right]:top-1/2! data-[side=right]:-left-1 data-[side=right]:-translate-y-1/2 data-[side=top]:-bottom-2.5\" />\n </TooltipPrimitive.Popup>\n </TooltipPrimitive.Positioner>\n </TooltipPrimitive.Portal>\n )\n}\n\n/** Compose a hint around an existing control without adding a DOM wrapper. */\nfunction Hint({\n children,\n content,\n disabled,\n ...props\n}: Omit<TooltipContentProps, 'children' | 'content'> & {\n children: React.ReactElement\n content: React.ReactNode\n /** Keep the control but never show its hint (for example, while its label is already visible). */\n disabled?: boolean\n}) {\n return (\n <Tooltip disabled={disabled}>\n <TooltipTrigger render={children} />\n <TooltipContent {...props}>{content}</TooltipContent>\n </Tooltip>\n )\n}\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, Hint }\n","import { createContext, useCallback, useContext, useState, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport css from './generated/studio.css'\nimport { toShadowCss } from './shadow-css'\n\nlet sheet: CSSStyleSheet | undefined\n/** One parsed sheet, adopted by every Studio shadow root on the page. */\nfunction studioStyleSheet() {\n if (!sheet) {\n sheet = new CSSStyleSheet()\n sheet.replaceSync(toShadowCss(css))\n }\n return sheet\n}\n\nconst PortalContainer = createContext<HTMLElement | null>(null)\n\n/** Where popups (tooltips, selects, dialogs) mount: inside the current shadow root, or the body outside one. */\nexport const usePortalContainer = () => useContext(PortalContainer) ?? undefined\n\n/**\n * Render Studio UI in its own shadow root so host page styles can't reach it, and Studio's styles can't\n * reach the host. Only inherited properties cross the boundary, and `[data-studio-root]` resets those.\n */\nexport function StudioShadowRoot({ children }: { children: ReactNode }) {\n const [root, setRoot] = useState<HTMLElement | null>(null)\n const attach = useCallback((host: HTMLDivElement | null) => {\n if (!host) return\n let shadow = host.shadowRoot\n if (!shadow) {\n shadow = host.attachShadow({ mode: 'open' })\n shadow.adoptedStyleSheets = [studioStyleSheet()]\n const container = document.createElement('div')\n container.setAttribute('data-studio-root', '')\n shadow.append(container)\n }\n setRoot(shadow.querySelector<HTMLElement>('[data-studio-root]'))\n }, [])\n\n return (\n // `display: contents` keeps the host out of layout; inline so host stylesheets can't override it.\n <div ref={attach} data-studio-host=\"\" style={{ display: 'contents' }}>\n {root && createPortal(<PortalContainer.Provider value={root}>{children}</PortalContainer.Provider>, root)}\n </div>\n )\n}\n\n/** The focused element, looking inside shadow roots (`document.activeElement` stops at their host). */\nexport function activeElement() {\n let element = document.activeElement\n while (element?.shadowRoot?.activeElement) element = element.shadowRoot.activeElement\n return element\n}\n\n/** The element an event started on; window listeners otherwise see a shadow root's host. */\nexport const eventTarget = (event: Event) => event.composedPath()[0] ?? event.target\n","/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:\"\";--tw-animation-delay:0s;--tw-animation-direction:normal;--tw-animation-duration:initial;--tw-animation-fill-mode:none;--tw-animation-iteration-count:1;--tw-enter-blur:0;--tw-enter-opacity:1;--tw-enter-rotate:0;--tw-enter-scale:1;--tw-enter-translate-x:0;--tw-enter-translate-y:0;--tw-exit-blur:0;--tw-exit-opacity:1;--tw-exit-rotate:0;--tw-exit-scale:1;--tw-exit-translate-x:0;--tw-exit-translate-y:0}}}@layer theme{:root,:host{--color-sky-400:oklch(74.6% .16 232.661);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--radius-xs:.125rem;--radius-lg:calc(var(--radius) + 2px);--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-spin:spin 1s linear infinite;--blur-xl:24px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--studio-font);--default-mono-font-family:var(--studio-font);--color-border:var(--border);--color-sidebar:var(--sidebar)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", \"Noto Sans\", Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{border-color:var(--border);outline-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){*{outline-color:color-mix(in oklab, var(--ring) 50%, transparent)}}body{background-color:var(--background);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--foreground)}}@layer components{.studio-surface{border-radius:calc(var(--radius) - 2px);background:var(--card);padding:6px}.studio-toolbar{pointer-events:auto;flex-wrap:wrap;align-items:center;gap:4px;display:flex}.studio-toolbar>button:not([data-slot=select-trigger]),.studio-toolbar [data-slot=toolbar-action]{border-radius:calc(var(--radius) - 2px);min-height:28px;color:var(--muted-foreground);font:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:1px solid #0000;align-items:center;gap:6px;padding:4px 8px;font-size:11px;display:inline-flex}:is(.studio-toolbar>button:not([data-slot=select-trigger]),.studio-toolbar [data-slot=toolbar-action]):hover{color:var(--foreground);background:var(--field-hover)}:is(.studio-toolbar>button:not([data-slot=select-trigger]),.studio-toolbar [data-slot=toolbar-action]):is(:active,[aria-pressed=true]){color:var(--foreground);background:var(--field-active)}:is(.studio-toolbar>button:not([data-slot=select-trigger]),.studio-toolbar [data-slot=toolbar-action]):focus-visible{outline:2px solid var(--ring);outline-offset:2px}.studio-canvas-toolbar{z-index:20;min-width:0;color:var(--muted-foreground);pointer-events:none;flex-shrink:0;position:relative}.studio-canvas-actions{opacity:1;transition:opacity .2s ease-out,translate .2s ease-out;translate:0}.studio-canvas-toolbar[data-ghost]{position:absolute;inset:4px 4px auto}.studio-canvas-toolbar[data-ghost]:before{content:\"\";pointer-events:auto;height:24px;position:absolute;inset:-4px 0 auto}.studio-canvas-toolbar[data-ghost] .studio-canvas-actions{-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);opacity:0;transition-delay:3s;translate:0 calc(-100% - 8px)}.studio-canvas-toolbar[data-ghost]:is(:hover,:has(:focus-visible,[aria-expanded=true],[data-state=open])) .studio-canvas-actions{opacity:1;transition-delay:0s;translate:0}@media (hover:none){.studio-canvas-toolbar[data-ghost] .studio-canvas-actions{opacity:1;translate:0}}.studio-canvas-toolbar[data-expanded]{height:80px;position:absolute;inset:0 0 auto}.studio-canvas-toolbar[data-expanded] .studio-canvas-actions{pointer-events:none;background:0 0;height:100%;padding:0}.studio-canvas-toolbar[data-expanded] .studio-canvas-actions>:not(.studio-canvas-toggle){display:none}.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle{width:min(280px,100%);height:100%;padding-top:max(12px, env(safe-area-inset-top));pointer-events:auto;justify-content:center;align-items:flex-start;margin-inline:auto;display:flex}.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle>button{border-color:var(--sidebar-border);border-radius:var(--radius);min-height:30px;color:var(--foreground);background:var(--sidebar)}@supports (color:color-mix(in lab, red, red)){.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle>button{background:color-mix(in srgb, var(--sidebar) 85%, transparent)}}.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle>button{-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);font-size:inherit;opacity:0;transition:opacity .2s ease-out 3s,translate .2s ease-out 3s;translate:0 -8px;box-shadow:0 4px 12px #0006}.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle>button:hover{background:var(--field-hover)}.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle:hover>button,.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle>button:focus-visible{opacity:1;transition-delay:0s;translate:0}@media (hover:none){.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle>button{opacity:1;translate:0}}@media (prefers-reduced-motion:reduce){.studio-canvas-actions,.studio-canvas-toolbar[data-expanded] .studio-canvas-toggle>button{transition-duration:0s}}.studio-preview-canvas{border:1px solid var(--sidebar-border);border-radius:calc(var(--radius) + 2px);background:var(--sidebar);flex-direction:column;gap:4px;min-width:0;min-height:0;padding:4px;display:flex;position:relative;overflow:hidden}@supports (color:color-mix(in lab, red, red)){.studio-preview-canvas{background:color-mix(in srgb, var(--sidebar) 85%, transparent)}}.studio-preview-canvas{font:12px/1.5 var(--studio-font);box-shadow:0 12px 24px #0006}.studio-preview-source{align-items:center;min-width:0;margin-right:auto;display:flex}.studio-preview-title{padding-inline:8px}.studio-preview-canvas>iframe{border-radius:calc(var(--radius) - 2px);background:var(--background);border:0;flex:1;width:100%;min-height:0}.studio-preview-canvas[data-expanded]{z-index:30;background:var(--background);border:0;border-radius:0;padding:0;position:fixed;inset:0}.studio-preview-canvas[data-expanded]>iframe{border-radius:0}}@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.inset-y-0{inset-block:0}.inset-y-2{inset-block:calc(var(--spacing) * 2)}.-top-0\\.5{top:calc(var(--spacing) * -.5)}.top-0{top:0}.top-1\\/2{top:50%}.top-4{top:calc(var(--spacing) * 4)}.-right-0\\.5{right:calc(var(--spacing) * -.5)}.right-0{right:0}.right-1{right:var(--spacing)}.right-2{right:calc(var(--spacing) * 2)}.right-4{right:calc(var(--spacing) * 4)}.bottom-0{bottom:0}.left-0{left:0}.left-1{left:var(--spacing)}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mt-1{margin-top:var(--spacing)}.mt-auto{margin-top:auto}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.aspect-square{aspect-ratio:1}.size-1\\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-2\\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3\\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-10{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.h-3\\.5{height:calc(var(--spacing) * 3.5)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-16{height:calc(var(--spacing) * 16)}.h-auto{height:auto}.h-full{height:100%}.h-svh{height:100svh}.max-h-\\(--available-height\\){max-height:var(--available-height)}.max-h-\\[300px\\]{max-height:300px}.min-h-0{min-height:0}.min-h-7{min-height:calc(var(--spacing) * 7)}.min-h-svh{min-height:100svh}.w-\\(--sidebar-width\\){width:var(--sidebar-width)}.w-\\(--studio-inspector-width\\){width:var(--studio-inspector-width)}.w-3\\/4{width:75%}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-full{max-width:100%}.min-w-\\(--anchor-width\\){min-width:var(--anchor-width)}.min-w-0{min-width:0}.min-w-5{min-width:calc(var(--spacing) * 5)}.flex-1{flex:1}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.origin-\\(--transform-origin\\){transform-origin:var(--transform-origin)}.-translate-x-\\[calc\\(100\\%\\+0\\.25rem\\)\\]{--tw-translate-x:calc(calc(100% + .25rem) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-\\[calc\\(100\\%\\+1rem\\)\\]{--tw-translate-x:calc(calc(100% + 1rem) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-\\[calc\\(100\\%\\+0\\.25rem\\)\\]{--tw-translate-x:calc(100% + .25rem);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-\\[calc\\(100\\%\\+1rem\\)\\]{--tw-translate-x:calc(100% + 1rem);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-y-\\[calc\\(-50\\%-2px\\)\\]{--tw-translate-y:calc(-50% - 2px);translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-45{rotate:45deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.scroll-py-1{scroll-padding-block:var(--spacing)}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.place-items-center{place-items:center}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-1\\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-\\[2px\\]{border-radius:2px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:calc(var(--radius) + 2px)}.rounded-md{border-radius:var(--radius)}.rounded-sm{border-radius:calc(var(--radius) - 2px)}.rounded-xs{border-radius:var(--radius-xs)}.border{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-border{border-color:var(--border)}.border-input{border-color:var(--input)}.border-sidebar-border{border-color:var(--sidebar-border)}.bg-\\(--field\\){background-color:var(--field)}.bg-background{background-color:var(--background)}.bg-black\\/50{background-color:#00000080}@supports (color:color-mix(in lab, red, red)){.bg-black\\/50{background-color:color-mix(in oklab, var(--color-black) 50%, transparent)}}.bg-current{background-color:currentColor}.bg-destructive{background-color:var(--destructive)}.bg-foreground{background-color:var(--foreground)}.bg-muted{background-color:var(--muted)}.bg-popover{background-color:var(--popover)}.bg-primary{background-color:var(--primary)}.bg-secondary{background-color:var(--secondary)}.bg-sidebar,.bg-sidebar\\/85{background-color:var(--sidebar)}@supports (color:color-mix(in lab, red, red)){.bg-sidebar\\/85{background-color:color-mix(in oklab, var(--sidebar) 85%, transparent)}}.bg-transparent{background-color:#0000}.bg-warning{background-color:var(--warning)}.fill-foreground{fill:var(--foreground)}.p-0{padding:0}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.px-0{padding-inline:0}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0{padding-block:0}.py-1{padding-block:var(--spacing)}.py-1\\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-6{padding-block:calc(var(--spacing) * 6)}.ps-3{padding-inline-start:calc(var(--spacing) * 3)}.pe-3{padding-inline-end:calc(var(--spacing) * 3)}.pt-2\\.5{padding-top:calc(var(--spacing) * 2.5)}.pr-0{padding-right:0}.pr-8{padding-right:calc(var(--spacing) * 8)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5\\.5{padding-left:calc(var(--spacing) * 5.5)}.text-center{text-align:center}.text-left{text-align:left}.font-\\(family-name\\:--studio-font\\),.font-mono{font-family:var(--studio-font)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\\[10px\\]{font-size:10px}.text-\\[11px\\]{font-size:11px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\\[0\\.08em\\]{--tw-tracking:.08em;letter-spacing:.08em}.text-balance{text-wrap:balance}.text-clip\\!{text-overflow:clip!important}.whitespace-nowrap{white-space:nowrap}.text-background{color:var(--background)}.text-destructive{color:var(--destructive)}.text-faint{color:var(--faint)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-popover-foreground{color:var(--popover-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-secondary-foreground{color:var(--secondary-foreground)}.text-sidebar-foreground{color:var(--sidebar-foreground)}.text-sidebar-primary{color:var(--sidebar-primary)}.text-sky-400{color:var(--color-sky-400)}.text-success{color:var(--success)}.text-warning{color:var(--warning)}.text-white{color:var(--color-white)}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\\[0_0_0_1px_var\\(--sidebar-border\\)\\]{--tw-shadow:0 0 0 1px var(--tw-shadow-color,var(--sidebar-border));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xs{--tw-shadow:0 1px 2px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-black\\/40{--tw-shadow-color:#0006}@supports (color:color-mix(in lab, red, red)){.shadow-black\\/40{--tw-shadow-color:color-mix(in oklab, color-mix(in oklab, var(--color-black) 40%, transparent) var(--tw-shadow-alpha), transparent)}}.ring-sidebar-ring{--tw-ring-color:var(--sidebar-ring)}.ring-offset-background{--tw-ring-offset-color:var(--background)}.outline-hidden{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.outline-hidden{outline-offset:2px;outline:2px solid #0000}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-xl{--tw-backdrop-blur:blur(var(--blur-xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[color\\,box-shadow\\]{transition-property:color,box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[left\\,right\\,width\\,translate\\]{transition-property:left,right,width,translate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[left\\,right\\,width\\]{transition-property:left,right,width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[padding\\]{transition-property:padding;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[translate\\,opacity\\]{transition-property:translate,opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[width\\,height\\,padding\\]{transition-property:width,height,padding;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\\[width\\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-linear{--tw-ease:linear;transition-timing-function:linear}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.paused{animation-play-state:paused}.running{animation-play-state:running}.group-focus-within\\/menu-item\\:opacity-100:is(:where(.group\\/menu-item):focus-within *){opacity:1}@media (hover:hover){.group-hover\\/edge\\:translate-x-0:is(:where(.group\\/edge):hover *){--tw-translate-x:0px;translate:var(--tw-translate-x) var(--tw-translate-y)}.group-hover\\/edge\\:opacity-100:is(:where(.group\\/edge):hover *),.group-hover\\/menu-item\\:opacity-100:is(:where(.group\\/menu-item):hover *){opacity:1}}.group-has-data-\\[sidebar\\=menu-action\\]\\/menu-item\\:pr-8:is(:where(.group\\/menu-item):has([data-sidebar=menu-action]) *){padding-right:calc(var(--spacing) * 8)}.group-data-\\[collapsible\\=icon\\]\\:hidden:is(:where(.group)[data-collapsible=icon] *){display:none}.group-data-\\[collapsible\\=icon\\]\\:size-8\\!:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--spacing) * 8)!important;height:calc(var(--spacing) * 8)!important}.group-data-\\[collapsible\\=icon\\]\\:w-\\(--sidebar-width-icon\\):is(:where(.group)[data-collapsible=icon] *){width:var(--sidebar-width-icon)}.group-data-\\[collapsible\\=icon\\]\\:w-\\[calc\\(var\\(--sidebar-width-icon\\)\\+\\(--spacing\\(4\\)\\)\\)\\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing) * 4)))}.group-data-\\[collapsible\\=icon\\]\\:w-\\[calc\\(var\\(--sidebar-width-icon\\)\\+\\(--spacing\\(4\\)\\)\\+2px\\)\\]:is(:where(.group)[data-collapsible=icon] *){width:calc(var(--sidebar-width-icon) + (calc(var(--spacing) * 4)) + 2px)}.group-data-\\[collapsible\\=icon\\]\\:overflow-hidden:is(:where(.group)[data-collapsible=icon] *){overflow:hidden}.group-data-\\[collapsible\\=icon\\]\\:p-0\\!:is(:where(.group)[data-collapsible=icon] *){padding:0!important}.group-data-\\[collapsible\\=icon\\]\\:p-2\\!:is(:where(.group)[data-collapsible=icon] *){padding:calc(var(--spacing) * 2)!important}.group-data-\\[collapsible\\=icon\\]\\:pl-\\[calc\\(1\\.5rem-0\\.875rem\\*352\\/144\\/2\\)\\]:is(:where(.group)[data-collapsible=icon] *){padding-left:.430556rem}.group-data-\\[collapsible\\=offcanvas\\]\\:right-\\[calc\\(var\\(--sidebar-width\\)\\*-1\\)\\]:is(:where(.group)[data-collapsible=offcanvas] *){right:calc(var(--sidebar-width) * -1)}.group-data-\\[collapsible\\=offcanvas\\]\\:left-\\[calc\\(var\\(--sidebar-width\\)\\*-1\\)\\]:is(:where(.group)[data-collapsible=offcanvas] *){left:calc(var(--sidebar-width) * -1)}.group-data-\\[collapsible\\=offcanvas\\]\\:w-0:is(:where(.group)[data-collapsible=offcanvas] *){width:0}.group-data-\\[side\\=left\\]\\:border-r:is(:where(.group)[data-side=left] *){border-right-style:var(--tw-border-style);border-right-width:1px}.group-data-\\[side\\=right\\]\\:rotate-180:is(:where(.group)[data-side=right] *){rotate:180deg}.group-data-\\[side\\=right\\]\\:border-l:is(:where(.group)[data-side=right] *){border-left-style:var(--tw-border-style);border-left-width:1px}@media (hover:hover){.peer-hover\\/menu-button\\:text-sidebar-accent-foreground:is(:where(.peer\\/menu-button):hover~*){color:var(--sidebar-accent-foreground)}}.peer-data-\\[active\\=true\\]\\/menu-button\\:text-sidebar-accent-foreground:is(:where(.peer\\/menu-button)[data-active=true]~*){color:var(--sidebar-accent-foreground)}.placeholder\\:text-muted-foreground::placeholder{color:var(--muted-foreground)}.after\\:absolute:after{content:var(--tw-content);position:absolute}.after\\:-inset-2:after{content:var(--tw-content);inset:calc(var(--spacing) * -2)}@media (hover:hover){.hover\\:bg-\\(--field-hover\\):hover{background-color:var(--field-hover)}.hover\\:bg-accent:hover{background-color:var(--accent)}.hover\\:bg-destructive\\/90:hover{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-destructive\\/90:hover{background-color:color-mix(in oklab, var(--destructive) 90%, transparent)}}.hover\\:bg-primary\\/90:hover{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-primary\\/90:hover{background-color:color-mix(in oklab, var(--primary) 90%, transparent)}}.hover\\:bg-secondary\\/80:hover{background-color:var(--secondary)}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-secondary\\/80:hover{background-color:color-mix(in oklab, var(--secondary) 80%, transparent)}}.hover\\:bg-sidebar-accent:hover{background-color:var(--sidebar-accent)}.hover\\:bg-sidebar\\/95:hover{background-color:var(--sidebar)}@supports (color:color-mix(in lab, red, red)){.hover\\:bg-sidebar\\/95:hover{background-color:color-mix(in oklab, var(--sidebar) 95%, transparent)}}.hover\\:bg-transparent:hover{background-color:#0000}.hover\\:text-accent-foreground:hover{color:var(--accent-foreground)}.hover\\:text-foreground:hover{color:var(--foreground)}.hover\\:text-sidebar-accent-foreground:hover{color:var(--sidebar-accent-foreground)}.hover\\:underline:hover{text-decoration-line:underline}.hover\\:opacity-100:hover{opacity:1}.hover\\:shadow-\\[0_0_0_1px_var\\(--sidebar-accent\\)\\]:hover{--tw-shadow:0 0 0 1px var(--tw-shadow-color,var(--sidebar-accent));box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.focus\\:translate-x-0:focus{--tw-translate-x:0px;translate:var(--tw-translate-x) var(--tw-translate-y)}.focus\\:opacity-100:focus{opacity:1}.focus\\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\\:ring-ring:focus{--tw-ring-color:var(--ring)}.focus\\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.focus\\:outline-hidden:focus{--tw-outline-style:none;outline-style:none}@media (forced-colors:active){.focus\\:outline-hidden:focus{outline-offset:2px;outline:2px solid #0000}}.focus-visible\\:border-ring:focus-visible{border-color:var(--ring)}.focus-visible\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\\:ring-\\[3px\\]:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-visible\\:ring-destructive\\/20:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.focus-visible\\:ring-destructive\\/20:focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.focus-visible\\:ring-ring\\/50:focus-visible{--tw-ring-color:var(--ring)}@supports (color:color-mix(in lab, red, red)){.focus-visible\\:ring-ring\\/50:focus-visible{--tw-ring-color:color-mix(in oklab, var(--ring) 50%, transparent)}}.active\\:bg-sidebar-accent:active{background-color:var(--sidebar-accent)}.active\\:bg-transparent:active{background-color:#0000}.active\\:text-sidebar-accent-foreground:active{color:var(--sidebar-accent-foreground)}.disabled\\:pointer-events-none:disabled{pointer-events:none}.disabled\\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\\:opacity-50:disabled{opacity:.5}.has-data-\\[variant\\=inset\\]\\:bg-sidebar:has([data-variant=inset]){background-color:var(--sidebar)}.has-\\[\\>svg\\]\\:px-1\\.5:has(>svg){padding-inline:calc(var(--spacing) * 1.5)}.has-\\[\\>svg\\]\\:px-2\\.5:has(>svg){padding-inline:calc(var(--spacing) * 2.5)}.has-\\[\\>svg\\]\\:px-3:has(>svg){padding-inline:calc(var(--spacing) * 3)}.has-\\[\\>svg\\]\\:px-4:has(>svg){padding-inline:calc(var(--spacing) * 4)}.aria-disabled\\:pointer-events-none[aria-disabled=true]{pointer-events:none}.aria-disabled\\:opacity-50[aria-disabled=true]{opacity:.5}.aria-invalid\\:border-destructive[aria-invalid=true]{border-color:var(--destructive)}.aria-invalid\\:ring-destructive\\/20[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.aria-invalid\\:ring-destructive\\/20[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 20%, transparent)}}.aria-pressed\\:bg-primary[aria-pressed=true]{background-color:var(--primary)}.aria-pressed\\:text-primary-foreground[aria-pressed=true]{color:var(--primary-foreground)}.data-closed\\:animate-out[data-closed]{animation:exit var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-closed\\:duration-300[data-closed]{--tw-duration:.3s;transition-duration:.3s}.data-closed\\:fade-out-0[data-closed]{--tw-exit-opacity:0}.data-closed\\:zoom-out-95[data-closed]{--tw-exit-scale:.95}.data-closed\\:slide-out-to-bottom[data-closed]{--tw-exit-translate-y:100%}.data-closed\\:slide-out-to-left[data-closed]{--tw-exit-translate-x:-100%}.data-closed\\:slide-out-to-right[data-closed]{--tw-exit-translate-x:100%}.data-closed\\:slide-out-to-top[data-closed]{--tw-exit-translate-y:-100%}.data-open\\:animate-in[data-open]{animation:enter var(--tw-animation-duration,var(--tw-duration,.15s))var(--tw-ease,ease)var(--tw-animation-delay,0s)var(--tw-animation-iteration-count,1)var(--tw-animation-direction,normal)var(--tw-animation-fill-mode,none)}.data-open\\:duration-500[data-open]{--tw-duration:.5s;transition-duration:.5s}.data-open\\:fade-in-0[data-open]{--tw-enter-opacity:0}.data-open\\:zoom-in-95[data-open]{--tw-enter-scale:.95}.data-open\\:slide-in-from-bottom[data-open]{--tw-enter-translate-y:100%}.data-open\\:slide-in-from-left[data-open]{--tw-enter-translate-x:-100%}.data-open\\:slide-in-from-right[data-open]{--tw-enter-translate-x:100%}.data-open\\:slide-in-from-top[data-open]{--tw-enter-translate-y:-100%}.data-\\[active\\=true\\]\\:bg-sidebar-accent[data-active=true]{background-color:var(--sidebar-accent)}.data-\\[active\\=true\\]\\:font-medium[data-active=true]{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.data-\\[active\\=true\\]\\:text-sidebar-accent-foreground[data-active=true]{color:var(--sidebar-accent-foreground)}.data-\\[disabled\\]\\:pointer-events-none[data-disabled]{pointer-events:none}.data-\\[disabled\\]\\:opacity-50[data-disabled]{opacity:.5}.data-\\[disabled\\=true\\]\\:pointer-events-none[data-disabled=true]{pointer-events:none}.data-\\[disabled\\=true\\]\\:opacity-50[data-disabled=true]{opacity:.5}.data-\\[highlighted\\]\\:bg-\\(--field-hover\\)[data-highlighted]{background-color:var(--field-hover)}.data-\\[highlighted\\]\\:text-accent-foreground[data-highlighted]{color:var(--accent-foreground)}.data-\\[instant\\]\\:animate-none[data-instant]{animation:none}.data-\\[selected\\=true\\]\\:bg-accent[data-selected=true]{background-color:var(--accent)}.data-\\[selected\\=true\\]\\:text-accent-foreground[data-selected=true]{color:var(--accent-foreground)}.data-\\[side\\=bottom\\]\\:top-1[data-side=bottom]{top:var(--spacing)}.data-\\[side\\=bottom\\]\\:slide-in-from-top-2[data-side=bottom]{--tw-enter-translate-y:calc(2*var(--spacing)*-1)}.data-\\[side\\=left\\]\\:top-1\\/2\\![data-side=left]{top:50%!important}.data-\\[side\\=left\\]\\:-right-1[data-side=left]{right:calc(var(--spacing) * -1)}.data-\\[side\\=left\\]\\:-translate-y-1\\/2[data-side=left]{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\\[side\\=left\\]\\:slide-in-from-right-2[data-side=left]{--tw-enter-translate-x:calc(2*var(--spacing))}.data-\\[side\\=right\\]\\:top-1\\/2\\![data-side=right]{top:50%!important}.data-\\[side\\=right\\]\\:-left-1[data-side=right]{left:calc(var(--spacing) * -1)}.data-\\[side\\=right\\]\\:-translate-y-1\\/2[data-side=right]{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.data-\\[side\\=right\\]\\:slide-in-from-left-2[data-side=right]{--tw-enter-translate-x:calc(2*var(--spacing)*-1)}.data-\\[side\\=top\\]\\:-bottom-2\\.5[data-side=top]{bottom:calc(var(--spacing) * -2.5)}.data-\\[side\\=top\\]\\:slide-in-from-bottom-2[data-side=top]{--tw-enter-translate-y:calc(2*var(--spacing))}.data-\\[state\\=open\\]\\:opacity-100[data-state=open]{opacity:1}@media (hover:hover){.data-\\[state\\=open\\]\\:hover\\:bg-sidebar-accent[data-state=open]:hover{background-color:var(--sidebar-accent)}.data-\\[state\\=open\\]\\:hover\\:text-sidebar-accent-foreground[data-state=open]:hover{color:var(--sidebar-accent-foreground)}}@media (prefers-reduced-motion:reduce){.motion-reduce\\:transition-none{transition-property:none}}@media (min-width:40rem){.sm\\:max-w-sm{max-width:var(--container-sm)}}@media (min-width:48rem){.md\\:block{display:block}.md\\:flex{display:flex}.md\\:opacity-0{opacity:0}.md\\:after\\:hidden:after{content:var(--tw-content);display:none}}@media (prefers-color-scheme:dark){.dark\\:border-input{border-color:var(--input)}.dark\\:bg-destructive\\/60{background-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\\:bg-destructive\\/60{background-color:color-mix(in oklab, var(--destructive) 60%, transparent)}}.dark\\:bg-input\\/30{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\\:bg-input\\/30{background-color:color-mix(in oklab, var(--input) 30%, transparent)}}@media (hover:hover){.dark\\:hover\\:bg-accent\\/50:hover{background-color:var(--accent)}@supports (color:color-mix(in lab, red, red)){.dark\\:hover\\:bg-accent\\/50:hover{background-color:color-mix(in oklab, var(--accent) 50%, transparent)}}.dark\\:hover\\:bg-input\\/50:hover{background-color:var(--input)}@supports (color:color-mix(in lab, red, red)){.dark\\:hover\\:bg-input\\/50:hover{background-color:color-mix(in oklab, var(--input) 50%, transparent)}}}.dark\\:focus-visible\\:ring-destructive\\/40:focus-visible{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\\:focus-visible\\:ring-destructive\\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}.dark\\:aria-invalid\\:ring-destructive\\/40[aria-invalid=true]{--tw-ring-color:var(--destructive)}@supports (color:color-mix(in lab, red, red)){.dark\\:aria-invalid\\:ring-destructive\\/40[aria-invalid=true]{--tw-ring-color:color-mix(in oklab, var(--destructive) 40%, transparent)}}}.\\[\\&_svg\\]\\:pointer-events-none svg{pointer-events:none}.\\[\\&_svg\\]\\:shrink-0 svg{flex-shrink:0}.\\[\\&_svg\\:not\\(\\[class\\*\\=\\'size-\\'\\]\\)\\]\\:size-3 svg:not([class*=size-]){width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\\[\\&_svg\\:not\\(\\[class\\*\\=\\'size-\\'\\]\\)\\]\\:size-4 svg:not([class*=size-]){width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\\[\\&_svg\\:not\\(\\[class\\*\\=\\'text-\\'\\]\\)\\]\\:text-muted-foreground svg:not([class*=text-]){color:var(--muted-foreground)}.\\[\\&\\>button\\]\\:hidden>button{display:none}.\\[\\&\\>span\\:first-child\\]\\:truncate>span:first-child,.\\[\\&\\>span\\:last-child\\]\\:truncate>span:last-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\\[\\&\\>svg\\]\\:size-3>svg{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.\\[\\&\\>svg\\]\\:size-4>svg{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.\\[\\&\\>svg\\]\\:shrink-0>svg{flex-shrink:0}@media (hover:none){.\\[\\@media\\(hover\\:none\\)\\]\\:translate-x-0{--tw-translate-x:0px;translate:var(--tw-translate-x) var(--tw-translate-y)}.\\[\\@media\\(hover\\:none\\)\\]\\:opacity-100{opacity:1}}[data-slot=tooltip-content] .\\[\\[data-slot\\=tooltip-content\\]_\\&\\]\\:bg-background\\/20{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){[data-slot=tooltip-content] .\\[\\[data-slot\\=tooltip-content\\]_\\&\\]\\:bg-background\\/20{background-color:color-mix(in oklab, var(--background) 20%, transparent)}}[data-slot=tooltip-content] .\\[\\[data-slot\\=tooltip-content\\]_\\&\\]\\:text-background{color:var(--background)}@media (prefers-color-scheme:dark){[data-slot=tooltip-content] .dark\\:\\[\\[data-slot\\=tooltip-content\\]_\\&\\]\\:bg-background\\/10{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){[data-slot=tooltip-content] .dark\\:\\[\\[data-slot\\=tooltip-content\\]_\\&\\]\\:bg-background\\/10{background-color:color-mix(in oklab, var(--background) 10%, transparent)}}}}@property --tw-animation-delay{syntax:\"*\";inherits:false;initial-value:0s}@property --tw-animation-direction{syntax:\"*\";inherits:false;initial-value:normal}@property --tw-animation-duration{syntax:\"*\";inherits:false}@property --tw-animation-fill-mode{syntax:\"*\";inherits:false;initial-value:none}@property --tw-animation-iteration-count{syntax:\"*\";inherits:false;initial-value:1}@property --tw-enter-blur{syntax:\"*\";inherits:false;initial-value:0}@property --tw-enter-opacity{syntax:\"*\";inherits:false;initial-value:1}@property --tw-enter-rotate{syntax:\"*\";inherits:false;initial-value:0}@property --tw-enter-scale{syntax:\"*\";inherits:false;initial-value:1}@property --tw-enter-translate-x{syntax:\"*\";inherits:false;initial-value:0}@property --tw-enter-translate-y{syntax:\"*\";inherits:false;initial-value:0}@property --tw-exit-blur{syntax:\"*\";inherits:false;initial-value:0}@property --tw-exit-opacity{syntax:\"*\";inherits:false;initial-value:1}@property --tw-exit-rotate{syntax:\"*\";inherits:false;initial-value:0}@property --tw-exit-scale{syntax:\"*\";inherits:false;initial-value:1}@property --tw-exit-translate-x{syntax:\"*\";inherits:false;initial-value:0}@property --tw-exit-translate-y{syntax:\"*\";inherits:false;initial-value:0}.studio-workspace{color:var(--foreground);background:var(--background);font:12px/1.5 var(--studio-font);cursor:default}.studio-workspace [data-slot=studio-config-file][href]{cursor:pointer;text-underline-offset:3px;text-decoration:none}.studio-workspace [data-slot=studio-config-file][href]:is(:hover,:focus-visible){text-decoration-line:underline}.studio-workspace [data-slot=studio-config-file][href]:focus-visible{outline:2px solid var(--ring);outline-offset:2px}.studio-workspace :is([data-slot=sidebar-header],[data-slot=sidebar-footer]){isolation:isolate;flex-shrink:0;position:relative}.studio-workspace :is([data-slot=sidebar-header],[data-slot=sidebar-footer]):before{content:\"\";z-index:-1;border-radius:calc(var(--radius-lg) - .25rem);background:var(--card);pointer-events:none;position:absolute;inset:4px}.studio-workspace [data-slot=sidebar-content] [data-slot=sidebar-menu-button]{min-height:36px;color:var(--muted-foreground);gap:10px;font-size:13px;line-height:20px}.studio-workspace [data-slot=sidebar-content] [data-slot=sidebar-menu-button]>span:first-child{flex-shrink:0;display:flex}.studio-workspace [data-slot=sidebar-content] [data-slot=sidebar-menu-button]:is(:hover,:focus-visible,[data-active=true]){color:var(--sidebar-accent-foreground)}.studio-workspace{--studio-inspector-width:20rem;--preview-left:8px;--preview-right:8px;--preview-bottom:8px;position:relative}@media (min-width:768px){.studio-workspace[data-sidebar-panel=shown]{--preview-left:var(--sidebar-width)}.studio-workspace[data-sidebar-panel=shown]:has([data-slot=sidebar][data-state=collapsed]){--preview-left:calc(var(--sidebar-width-icon) + 1rem + 2px)}}@media (min-width:1024px){.studio-workspace:has([data-slot=studio-inspector][aria-hidden=false]){--preview-right:calc(var(--studio-inspector-width) + 1rem)}}@media (max-width:1023px){.studio-workspace:is(:has(>[data-slot=preview-canvas]:not([data-expanded])),[data-preview-layout=custom]):has([data-slot=studio-inspector][aria-hidden=false]){--preview-bottom:40%}.studio-workspace:is(:has(>[data-slot=preview-canvas]:not([data-expanded])),[data-preview-layout=custom]) [data-slot=studio-inspector]{inset:calc(60% + 8px) 8px 8px var(--preview-left);width:auto}}.studio-workspace>[data-slot=preview-canvas]{z-index:0}.studio-workspace>[data-slot=preview-canvas]:not([data-expanded]){inset:8px var(--preview-right) var(--preview-bottom) var(--preview-left);position:absolute}.studio-workspace>iframe[data-slot=studio-preview]{background:var(--background);border:0;width:100%;height:100%;position:absolute;inset:0}.studio-workspace[data-preview-layout=custom]>iframe[data-slot=studio-preview]{inset:0 calc(var(--preview-right) - 8px) calc(var(--preview-bottom) - 8px) calc(var(--preview-left) - 8px);width:calc(100% - var(--preview-left) - var(--preview-right) + 16px);height:calc(100% - var(--preview-bottom) + 8px)}:root{--background:#000;--foreground:#d6d7dc;--card:#ffffff0a;--card-foreground:#d6d7dc;--popover:#18191c;--popover-foreground:#d6d7dc;--primary:#e6e7ea;--primary-foreground:#000;--secondary:#ffffff14;--secondary-foreground:#d6d7dc;--muted:#18191c;--muted-foreground:#8b8c94;--faint:#5d5e66;--accent:#18191c;--accent-foreground:#d6d7dc;--destructive:#f87171;--success:#4ade80;--warning:#facc15;--border:#26272b;--input:#26272b;--ring:#5d5e66;--radius:.5rem;--field:#ffffff0f;--field-hover:#ffffff17;--field-active:#ffffff1f;--knob:#4a4b52;--knob-hover:#5a5b63;--sidebar:#000;--sidebar-foreground:#8b8c94;--sidebar-primary:#e6e7ea;--sidebar-primary-foreground:#000;--sidebar-accent:#ffffff14;--sidebar-accent-foreground:#d6d7dc;--sidebar-border:#26272b;--sidebar-ring:#5d5e66;--studio-font:ui-monospace, SFMono-Regular, Menlo, monospace;color-scheme:dark}[data-slot=studio-controls] :is(.tp-lblv_l,.tp-fldv_t):first-letter{text-transform:uppercase}[data-slot=studio-command-overlay]{z-index:1000;background:#0000004d;position:fixed;inset:0}[data-slot=studio-command-menu]{z-index:1001;border:1px solid var(--sidebar-border);border-radius:calc(var(--radius) + 2px);background:var(--sidebar);width:min(480px,100vw - 32px);max-height:calc(100dvh - min(20vh,160px) - 16px);position:fixed;top:min(20vh,160px);left:50%;overflow:auto;transform:translate(-50%)}@supports (color:color-mix(in lab, red, red)){[data-slot=studio-command-menu]{background:color-mix(in srgb, var(--sidebar) 85%, transparent)}}[data-slot=studio-command-menu]{color:var(--foreground);color-scheme:dark;font:12px/1.5 var(--studio-font);-webkit-backdrop-filter:blur(24px);backdrop-filter:blur(24px);box-shadow:0 20px 25px -5px #0006,0 8px 10px -6px #0006}[data-slot=studio-command-menu],[data-slot=studio-command-menu] *{box-sizing:border-box}[data-slot=studio-command-menu] svg{width:16px;height:16px;color:inherit;flex-shrink:0}[data-slot=studio-command-menu] [data-slot=kbd]{pointer-events:none;border:1px solid var(--border);border-radius:calc(var(--radius) - 2px);background:var(--muted);width:fit-content;min-width:20px;height:20px;font:inherit;color:var(--muted-foreground);-webkit-user-select:none;user-select:none;border-bottom-width:2px;justify-content:center;align-items:center;gap:4px;padding:0 4px;font-size:12px;font-weight:400;display:inline-flex}[data-slot=studio-command-menu] [data-slot=kbd-group]{align-items:center;gap:4px;display:inline-flex}[data-slot=studio-command-menu] button{font:inherit;color:inherit;cursor:pointer;background:0 0;border:0;border-radius:4px}[data-slot=studio-command-menu] button:focus-visible{outline:2px solid var(--sidebar-ring);outline-offset:2px}[data-slot=studio-command-menu] [data-slot=studio-command-heading]{align-items:center;gap:8px;height:40px;padding:0 12px 0 16px;display:flex}[data-slot=studio-command-menu] [data-slot=studio-command-heading] h2{font:inherit;flex:1;align-items:center;gap:10px;margin:0;display:flex}[data-slot=studio-command-menu] [data-slot=studio-command-heading] svg{width:auto;height:14px}[data-slot=studio-command-menu] [data-slot=studio-command-heading] strong{letter-spacing:.08em;white-space:nowrap;font-weight:700}[data-slot=studio-command-menu] [data-slot=studio-command-heading] button{padding:0}[data-slot=studio-command-menu] [data-slot=studio-command-heading] button:hover{background:var(--sidebar-accent)}[data-slot=studio-command-menu] [data-slot=studio-command-description]{display:none}[data-slot=studio-command-menu] [data-slot=command]{height:auto;color:inherit;background:0 0;flex-direction:column;display:flex;overflow:hidden}[data-slot=studio-command-menu] [data-slot=command-input-wrapper]{border-radius:var(--radius);background:var(--field);height:36px;color:var(--muted-foreground);border:1px solid #0000;align-items:center;gap:8px;margin:8px;padding:0 8px;display:flex}[data-slot=studio-command-menu] [data-slot=command-input-wrapper]:focus-within{border-color:var(--sidebar-ring)}[data-slot=studio-command-menu] [data-slot=command-input-wrapper] svg{opacity:1}[data-slot=studio-command-menu] [data-slot=command-input]{width:100%;min-width:0;height:100%;color:var(--sidebar-primary);font:inherit;background:0 0;border:0;outline:none;padding:0}[data-slot=studio-command-menu] [data-slot=command-input]::placeholder{color:var(--muted-foreground)}[data-slot=studio-command-menu] [data-slot=command-list]{overscroll-behavior:contain;max-height:300px;padding:0 8px 8px;scroll-padding:4px;overflow-y:auto}[data-slot=studio-command-menu] [data-slot=command-item]{border-radius:calc(var(--radius) - 2px);min-height:36px;font:inherit;color:var(--sidebar-foreground);cursor:pointer;align-items:center;gap:8px;padding:8px;display:flex}[data-slot=studio-command-menu] [data-slot=command-item][data-selected=true]{background:var(--sidebar-accent);color:var(--sidebar-accent-foreground)}[data-slot=studio-command-menu] [data-slot=studio-command-label]{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}[data-slot=studio-command-menu] [data-slot=command-empty]{text-align:center;font:inherit;color:var(--muted-foreground);padding:24px 8px}[data-slot=studio-command-menu] [data-slot=studio-command-footer]{border-top:1px solid var(--sidebar-border);color:var(--muted-foreground);align-items:center;gap:16px;padding:8px 12px;font-size:10px;display:flex}[data-slot=studio-command-menu] [data-slot=studio-command-footer]>span{align-items:center;gap:6px;display:inline-flex}[data-studio-root]{all:initial;color:var(--foreground);font:12px/1.5 var(--studio-font);color-scheme:dark;display:contents}@property --tw-translate-x{syntax:\"*\";inherits:false;initial-value:0}@property --tw-translate-y{syntax:\"*\";inherits:false;initial-value:0}@property --tw-translate-z{syntax:\"*\";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:\"*\";inherits:false}@property --tw-rotate-y{syntax:\"*\";inherits:false}@property --tw-rotate-z{syntax:\"*\";inherits:false}@property --tw-skew-x{syntax:\"*\";inherits:false}@property --tw-skew-y{syntax:\"*\";inherits:false}@property --tw-border-style{syntax:\"*\";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:\"*\";inherits:false}@property --tw-tracking{syntax:\"*\";inherits:false}@property --tw-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:\"*\";inherits:false}@property --tw-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:\"*\";inherits:false}@property --tw-inset-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:\"*\";inherits:false}@property --tw-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:\"*\";inherits:false}@property --tw-inset-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:\"*\";inherits:false}@property --tw-ring-offset-width{syntax:\"<length>\";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:\"*\";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:\"*\";inherits:false;initial-value:solid}@property --tw-blur{syntax:\"*\";inherits:false}@property --tw-brightness{syntax:\"*\";inherits:false}@property --tw-contrast{syntax:\"*\";inherits:false}@property --tw-grayscale{syntax:\"*\";inherits:false}@property --tw-hue-rotate{syntax:\"*\";inherits:false}@property --tw-invert{syntax:\"*\";inherits:false}@property --tw-opacity{syntax:\"*\";inherits:false}@property --tw-saturate{syntax:\"*\";inherits:false}@property --tw-sepia{syntax:\"*\";inherits:false}@property --tw-drop-shadow{syntax:\"*\";inherits:false}@property --tw-drop-shadow-color{syntax:\"*\";inherits:false}@property --tw-drop-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:\"*\";inherits:false}@property --tw-backdrop-blur{syntax:\"*\";inherits:false}@property --tw-backdrop-brightness{syntax:\"*\";inherits:false}@property --tw-backdrop-contrast{syntax:\"*\";inherits:false}@property --tw-backdrop-grayscale{syntax:\"*\";inherits:false}@property --tw-backdrop-hue-rotate{syntax:\"*\";inherits:false}@property --tw-backdrop-invert{syntax:\"*\";inherits:false}@property --tw-backdrop-opacity{syntax:\"*\";inherits:false}@property --tw-backdrop-saturate{syntax:\"*\";inherits:false}@property --tw-backdrop-sepia{syntax:\"*\";inherits:false}@property --tw-duration{syntax:\"*\";inherits:false}@property --tw-ease{syntax:\"*\";inherits:false}@property --tw-content{syntax:\"*\";inherits:false;initial-value:\"\"}@keyframes spin{to{transform:rotate(360deg)}}@keyframes enter{0%{opacity:var(--tw-enter-opacity,1);transform:translate3d(var(--tw-enter-translate-x,0),var(--tw-enter-translate-y,0),0)scale3d(var(--tw-enter-scale,1),var(--tw-enter-scale,1),var(--tw-enter-scale,1))rotate(var(--tw-enter-rotate,0));filter:blur(var(--tw-enter-blur,0))}}@keyframes exit{to{opacity:var(--tw-exit-opacity,1);transform:translate3d(var(--tw-exit-translate-x,0),var(--tw-exit-translate-y,0),0)scale3d(var(--tw-exit-scale,1),var(--tw-exit-scale,1),var(--tw-exit-scale,1))rotate(var(--tw-exit-rotate,0));filter:blur(var(--tw-exit-blur,0))}}","/** Studio's px values assume the browser default root size; hosts often change `<html>`'s font size. */\nconst ROOT_FONT_SIZE = 16\n\n/**\n * Adapt Studio's compiled Tailwind CSS to run inside a shadow root:\n *\n * - `@property` rules are ignored in shadow trees, so the `--tw-*` variables that shadows, rings, and\n * transforms compose would have no initial value. Set those initial values on every element instead,\n * as Tailwind's own fallback for browsers without `@property` does.\n * - `rem` resolves against the host page's `<html>`, not the shadow root, so a host that sets\n * `html { font-size: 62.5% }` would shrink Studio. Pin every declared `rem` to px.\n * - Theme variables declared on `:root`/`:host` would land on the shadow host, a light-DOM element the\n * host page can also style (`div { --foreground: red }` beats `:host`), and inherit into Studio. Declare\n * them on `[data-studio-root]` inside the shadow tree instead, out of the host page's reach.\n */\nexport function toShadowCss(css: string) {\n const defaults = [...css.matchAll(/@property\\s*(--[\\w-]+)\\s*\\{([^}]*)\\}/g)].flatMap(([, name, body]) => {\n const value = /initial-value:\\s*([^;}]+)/.exec(body!)?.[1]?.trim()\n return value ? [`${name}:${value}`] : []\n })\n const scoped = css.replace(/(^|[{};])\\s*:root(?:\\s*,\\s*:host)?\\s*\\{/g, '$1[data-studio-root]{')\n // Only declarations (text before `;` or `}`), never selectors, which may contain escaped rem values.\n const pinned = scoped.replace(/[^{};]+(?=[;}])/g, (declaration) =>\n declaration.replace(/(?<![\\w.\\\\])(-?\\d*\\.?\\d+)rem\\b/g, (_, value: string) => `${+value * ROOT_FONT_SIZE}px`),\n )\n if (!defaults.length) return pinned\n return `${pinned}\\n@layer properties{*,::before,::after,::backdrop{${defaults.join(';')}}}`\n}\n","import { Slot } from 'radix-ui'\nimport { forwardRef, type ComponentProps, type ComponentPropsWithoutRef } from 'react'\nimport { cn } from './utils'\nimport { StudioSurface } from '../surface'\n\n/** Shared floating surface. Layout and visibility belong to the caller. */\nexport const Panel = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'> & { asChild?: boolean }>(function Panel(\n { className, asChild = false, ...props },\n ref,\n) {\n const Comp = asChild ? Slot.Root : 'div'\n return (\n <Comp\n ref={ref}\n data-slot=\"panel\"\n className={cn(\n 'rounded-lg border border-sidebar-border bg-sidebar/85 shadow-xl shadow-black/40 backdrop-blur-xl',\n className,\n )}\n {...props}\n />\n )\n})\n\n/** Raised sections sit inside the panel's 4px padding with concentric corners. */\nexport function PanelHeader({ className, ...props }: ComponentProps<'header'>) {\n return (\n <StudioSurface asChild className={cn('px-3 pt-2.5 pb-2', className)}>\n <header data-slot=\"panel-header\" {...props} />\n </StudioSurface>\n )\n}\n\nexport const PanelContent = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'>>(function PanelContent(\n { className, ...props },\n ref,\n) {\n return (\n <div\n ref={ref}\n data-slot=\"panel-content\"\n className={cn('min-h-0 flex-1 overflow-auto px-1 py-1.5', className)}\n {...props}\n />\n )\n})\n\nexport function PanelFooter({ className, ...props }: ComponentProps<'footer'>) {\n return (\n <StudioSurface asChild className={cn('grid gap-2 p-2', className)}>\n <footer data-slot=\"panel-footer\" {...props} />\n </StudioSurface>\n )\n}\n","import { Slot } from 'radix-ui'\nimport { forwardRef, type ComponentPropsWithoutRef } from 'react'\nimport { cn } from './ui/utils'\n\n/** The inset card surface shared by canvas headers, toolbars, and detail panels. */\nexport const StudioSurface = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'> & { asChild?: boolean }>(\n function StudioSurface({ asChild = false, className, ...props }, ref) {\n const Comp = asChild ? Slot.Root : 'div'\n return <Comp ref={ref} data-slot=\"studio-surface\" className={cn('studio-surface', className)} {...props} />\n },\n)\n\nexport const StudioToolbar = forwardRef<HTMLDivElement, ComponentPropsWithoutRef<'div'>>(function StudioToolbar(\n { className, ...props },\n ref,\n) {\n return <StudioSurface ref={ref} role=\"group\" className={cn('studio-toolbar', className)} {...props} />\n})\n","import type { SVGProps } from 'react'\n\n/** The JOYCO stretched iso mark (r2.joyco.studio/brand/iso-stretched.svg), without the © glyph that vanishes at UI sizes. */\nexport function Logo(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 352 144\" fill=\"currentColor\" aria-label=\"JOYCO\" role=\"img\" {...props}>\n <path d=\"M328 96L280 144H0V40H176V112H192V24H0V0H352V24H328V96Z\" />\n </svg>\n )\n}\n","import { useEffect, useState } from 'react'\nimport type { Studio } from '../client/studio'\n\nconst STORAGE_KEY = 'joyco-studio:pinned-tools'\nconst CHANGE_EVENT = 'joyco-studio:pins-changed'\n\nfunction readPins(): string[] {\n try {\n const value: unknown = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]')\n return Array.isArray(value) ? value.filter((id): id is string => typeof id === 'string') : []\n } catch {\n return []\n }\n}\n\n/** Browser-local preferences shared by the sidebar, command menu, and other tabs. */\nexport function usePinnedTools(studio: Studio) {\n const [pins, setPins] = useState<string[]>([])\n\n useEffect(() => {\n setPins(readPins())\n const onChange = (event: Event) => setPins((event as CustomEvent<string[]>).detail)\n const onStorage = (event: StorageEvent) => {\n if (event.key === STORAGE_KEY || event.key === null) setPins(readPins())\n }\n window.addEventListener(CHANGE_EVENT, onChange)\n window.addEventListener('storage', onStorage)\n return () => {\n window.removeEventListener(CHANGE_EVENT, onChange)\n window.removeEventListener('storage', onStorage)\n }\n }, [])\n\n const pinned = new Set(pins)\n // Keep registration order within each group, and never reorder the client's tool registry.\n const tools = [...studio.definitions].sort((a, b) => Number(pinned.has(b.id)) - Number(pinned.has(a.id)))\n\n const togglePin = (id: string) => {\n const next = pinned.has(id) ? pins.filter((pin) => pin !== id) : [...pins, id]\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(next))\n } catch {\n // Pinning still works for mounted views when browser storage is unavailable.\n }\n window.dispatchEvent(new CustomEvent(CHANGE_EVENT, { detail: next }))\n }\n\n return { tools, pinned, togglePin }\n}\n","import { RotateCw } from 'lucide-react'\nimport { forwardRef, useImperativeHandle, useRef, useState, type ComponentPropsWithoutRef, type ReactNode } from 'react'\nimport { CanvasToolbar } from './canvas-toolbar'\n\nexport interface PreviewCanvasProps extends ComponentPropsWithoutRef<'iframe'> {\n expanded?: boolean\n onExpandedChange?: (expanded: boolean) => void\n onReload?: () => void\n toolbar?: ReactNode\n}\n\n/** Expands the same iframe in place. Native iframe props and the ref reach the iframe. */\nexport const PreviewCanvas = forwardRef<HTMLIFrameElement, PreviewCanvasProps>(function PreviewCanvas(\n { title = 'Preview', expanded: controlled, onExpandedChange, onReload, toolbar, ...props },\n ref,\n) {\n const [localExpanded, setExpanded] = useState(false)\n const expanded = controlled ?? localExpanded\n const frame = useRef<HTMLIFrameElement>(null)\n useImperativeHandle(ref, () => frame.current!, [])\n\n return (\n <section\n className=\"studio-preview-canvas\"\n data-slot=\"preview-canvas\"\n data-expanded={expanded || undefined}\n aria-label={`${title} canvas`}\n >\n <CanvasToolbar\n label=\"Preview canvas\"\n expanded={expanded}\n onToggle={() => {\n setExpanded(!expanded)\n onExpandedChange?.(!expanded)\n }}\n >\n <button\n type=\"button\"\n aria-label=\"Reload preview\"\n title=\"Reload preview\"\n onClick={() => {\n onReload?.()\n if (frame.current) frame.current.src = frame.current.src\n }}\n >\n <RotateCw size={14} strokeWidth={1.5} aria-hidden />\n </button>\n <div className=\"studio-preview-source\">{toolbar ?? <span className=\"studio-preview-title\">{title}</span>}</div>\n </CanvasToolbar>\n <iframe {...props} ref={frame} title={title} />\n </section>\n )\n})\n","import { Maximize, Minimize, Pin, PinOff } from 'lucide-react'\nimport { useState, type ReactNode } from 'react'\nimport { StudioToolbar } from './surface'\n\nexport interface CanvasToolbarProps {\n label: string\n expanded?: boolean\n onToggle?: () => void\n children?: ReactNode\n}\n\n/** Pinned by default; auto-hide preserves pointer, keyboard, open-menu, and touch access. */\nexport function CanvasToolbar({ label, expanded = false, onToggle, children }: CanvasToolbarProps) {\n const [ghost, setGhost] = useState(false)\n const ExpandIcon = expanded ? Minimize : Maximize\n const PinIcon = ghost ? PinOff : Pin\n\n return (\n <div\n className=\"studio-canvas-toolbar\"\n data-slot=\"canvas-toolbar\"\n data-expanded={expanded || undefined}\n data-ghost={(!expanded && ghost) || undefined}\n role=\"group\"\n aria-label={label}\n >\n <StudioToolbar className=\"studio-canvas-actions\">\n {children}\n {onToggle && (\n <div className=\"studio-canvas-toggle\">\n <button data-slot=\"toolbar-action\" type=\"button\" aria-pressed={expanded} onClick={onToggle}>\n <ExpandIcon size={14} strokeWidth={1.5} aria-hidden />\n {expanded ? 'Contain canvas' : 'Expand'}\n </button>\n </div>\n )}\n {!expanded && (\n <button\n type=\"button\"\n aria-label={`Auto-hide ${label.toLowerCase()} header`}\n aria-pressed={ghost}\n title={ghost ? 'Pin header' : 'Auto-hide header'}\n onClick={() => setGhost(!ghost)}\n >\n <PinIcon size={14} strokeWidth={1.5} aria-hidden />\n </button>\n )}\n </StudioToolbar>\n </div>\n )\n}\n","import { useEffect, useState } from 'react'\n\n/** A boolean that survives reloads in this tab. Reads storage on first render, so render it client-only. */\nexport function useSessionFlag(key: string) {\n const [value, setValue] = useState(() => {\n try {\n return sessionStorage.getItem(key) === 'true'\n } catch {\n return false\n }\n })\n\n useEffect(() => {\n try {\n sessionStorage.setItem(key, String(value))\n } catch {\n // The flag still works for this mount when browser storage is unavailable.\n }\n }, [key, value])\n\n return [value, setValue] as const\n}\n","'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/react/ui/utils'\nimport { Slot } from 'radix-ui'\n\nimport { useIsMobile } from '@/react/ui/hooks/use-mobile'\nimport { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@/react/ui/sheet'\nimport { Hint, TooltipContent, TooltipProvider } from '@/react/ui/tooltip'\nimport { Panel } from './panel'\n\nconst SIDEBAR_COOKIE_NAME = 'sidebar_state'\nconst SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7\n// px, not rem: inline styles skip the shadow stylesheet's rem pinning, and rem follows the host's <html>.\nconst SIDEBAR_WIDTH = '256px'\nconst SIDEBAR_WIDTH_MOBILE = '288px'\nconst SIDEBAR_WIDTH_ICON = '48px'\n\ntype SidebarContextProps = {\n state: 'expanded' | 'collapsed'\n open: boolean\n setOpen: (open: boolean) => void\n openMobile: boolean\n setOpenMobile: (open: boolean) => void\n isMobile: boolean\n toggleSidebar: () => void\n}\n\nconst SidebarContext = React.createContext<SidebarContextProps | null>(null)\n\nfunction useSidebar() {\n const context = React.useContext(SidebarContext)\n if (!context) {\n throw new Error('useSidebar must be used within a SidebarProvider.')\n }\n\n return context\n}\n\nfunction SidebarProvider({\n defaultOpen = true,\n open: openProp,\n onOpenChange: setOpenProp,\n className,\n style,\n children,\n ...props\n}: React.ComponentProps<'div'> & {\n defaultOpen?: boolean\n open?: boolean\n onOpenChange?: (open: boolean) => void\n}) {\n const isMobile = useIsMobile()\n const [openMobile, setOpenMobile] = React.useState(false)\n\n // This is the internal state of the sidebar.\n // We use openProp and setOpenProp for control from outside the component.\n const [_open, _setOpen] = React.useState(defaultOpen)\n const open = openProp ?? _open\n const setOpen = React.useCallback(\n (value: boolean | ((value: boolean) => boolean)) => {\n const openState = typeof value === 'function' ? value(open) : value\n if (setOpenProp) {\n setOpenProp(openState)\n } else {\n _setOpen(openState)\n }\n\n // This sets the cookie to keep the sidebar state.\n document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`\n },\n [setOpenProp, open],\n )\n\n // Helper to toggle the sidebar.\n const toggleSidebar = React.useCallback(() => {\n return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)\n }, [isMobile, setOpen, setOpenMobile])\n\n // We add a state so that we can do data-state=\"expanded\" or \"collapsed\".\n // This makes it easier to style the sidebar with Tailwind classes.\n const state = open ? 'expanded' : 'collapsed'\n\n const contextValue = React.useMemo<SidebarContextProps>(\n () => ({\n state,\n open,\n setOpen,\n isMobile,\n openMobile,\n setOpenMobile,\n toggleSidebar,\n }),\n [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],\n )\n\n return (\n <SidebarContext.Provider value={contextValue}>\n <TooltipProvider delay={0}>\n <div\n data-slot=\"sidebar-wrapper\"\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH,\n '--sidebar-width-icon': SIDEBAR_WIDTH_ICON,\n ...style,\n } as React.CSSProperties\n }\n className={cn('group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-sidebar', className)}\n {...props}\n >\n {children}\n </div>\n </TooltipProvider>\n </SidebarContext.Provider>\n )\n}\n\nfunction Sidebar({\n side = 'left',\n variant = 'sidebar',\n collapsible = 'offcanvas',\n className,\n children,\n ...props\n}: React.ComponentProps<'div'> & {\n side?: 'left' | 'right'\n variant?: 'sidebar' | 'floating' | 'inset'\n collapsible?: 'offcanvas' | 'icon' | 'none'\n}) {\n const { isMobile, state, openMobile, setOpenMobile } = useSidebar()\n const Surface = variant === 'floating' ? Panel : 'div'\n\n if (collapsible === 'none') {\n return (\n <div\n data-slot=\"sidebar\"\n className={cn('flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground', className)}\n {...props}\n >\n {children}\n </div>\n )\n }\n\n if (isMobile) {\n return (\n <Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>\n <SheetContent\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar\"\n data-mobile=\"true\"\n className=\"w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden\"\n style={\n {\n '--sidebar-width': SIDEBAR_WIDTH_MOBILE,\n } as React.CSSProperties\n }\n side={side}\n >\n <SheetHeader className=\"sr-only\">\n <SheetTitle>Sidebar</SheetTitle>\n <SheetDescription>Displays the mobile sidebar.</SheetDescription>\n </SheetHeader>\n <div className=\"flex h-full w-full flex-col\">{children}</div>\n </SheetContent>\n </Sheet>\n )\n }\n\n return (\n <div\n className=\"group peer hidden text-sidebar-foreground md:block\"\n data-state={state}\n data-collapsible={state === 'collapsed' ? collapsible : ''}\n data-variant={variant}\n data-side={side}\n data-slot=\"sidebar\"\n >\n {/* This is what handles the sidebar gap on desktop */}\n <div\n data-slot=\"sidebar-gap\"\n className={cn(\n 'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear',\n 'group-data-[collapsible=offcanvas]:w-0',\n 'group-data-[side=right]:rotate-180',\n variant === 'floating' || variant === 'inset'\n ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]'\n : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',\n )}\n />\n <div\n data-slot=\"sidebar-container\"\n className={cn(\n 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex',\n side === 'left'\n ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'\n : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',\n // Adjust the padding for floating and inset variants.\n variant === 'floating' || variant === 'inset'\n ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'\n : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l',\n className,\n )}\n {...props}\n >\n <Surface\n data-sidebar=\"sidebar\"\n data-slot=\"sidebar-inner\"\n className={cn('flex h-full w-full flex-col', variant !== 'floating' && 'bg-sidebar')}\n >\n {children}\n </Surface>\n </div>\n </div>\n )\n}\n\nfunction SidebarHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-header\"\n data-sidebar=\"header\"\n className={cn('flex flex-col gap-2 p-2', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-footer\"\n data-sidebar=\"footer\"\n className={cn('flex flex-col gap-2 p-2', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarContent({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-content\"\n data-sidebar=\"content\"\n className={cn(\n 'flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction SidebarGroup({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"sidebar-group\"\n data-sidebar=\"group\"\n className={cn('relative flex w-full min-w-0 flex-col p-2', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarMenu({ className, ...props }: React.ComponentProps<'ul'>) {\n return (\n <ul\n data-slot=\"sidebar-menu\"\n data-sidebar=\"menu\"\n className={cn('flex w-full min-w-0 flex-col gap-1', className)}\n {...props}\n />\n )\n}\n\nfunction SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>) {\n return (\n <li\n data-slot=\"sidebar-menu-item\"\n data-sidebar=\"menu-item\"\n className={cn('group/menu-item relative', className)}\n {...props}\n />\n )\n}\n\nconst sidebarMenuButtonVariants = cva(\n 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',\n {\n variants: {\n variant: {\n default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',\n outline:\n 'bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]',\n },\n size: {\n default: 'h-8 text-sm',\n sm: 'h-7 text-xs',\n lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!',\n },\n },\n defaultVariants: {\n variant: 'default',\n size: 'default',\n },\n },\n)\n\nfunction SidebarMenuButton({\n asChild = false,\n isActive = false,\n variant = 'default',\n size = 'default',\n tooltip,\n className,\n ...props\n}: React.ComponentProps<'button'> & {\n asChild?: boolean\n isActive?: boolean\n tooltip?: string | React.ComponentProps<typeof TooltipContent>\n} & VariantProps<typeof sidebarMenuButtonVariants>) {\n const Comp = asChild ? Slot.Root : 'button'\n const { isMobile, state } = useSidebar()\n\n const button = (\n <Comp\n data-slot=\"sidebar-menu-button\"\n data-sidebar=\"menu-button\"\n data-size={size}\n data-active={isActive}\n className={cn(sidebarMenuButtonVariants({ variant, size }), className)}\n {...props}\n />\n )\n\n if (!tooltip) return button\n const { children, ...hint } = typeof tooltip === 'string' ? { children: tooltip } : tooltip\n return (\n <Hint side=\"right\" align=\"center\" disabled={state !== 'collapsed' || isMobile} {...hint} content={children}>\n {button}\n </Hint>\n )\n}\n\nfunction SidebarMenuAction({\n className,\n asChild = false,\n showOnHover = false,\n ...props\n}: React.ComponentProps<'button'> & {\n asChild?: boolean\n showOnHover?: boolean\n}) {\n const Comp = asChild ? Slot.Root : 'button'\n\n return (\n <Comp\n data-slot=\"sidebar-menu-action\"\n data-sidebar=\"menu-action\"\n className={cn(\n 'absolute top-1/2 right-1 flex aspect-square w-5 -translate-y-1/2 items-center justify-center rounded-md p-0 text-sidebar-foreground ring-sidebar-ring outline-hidden transition-transform peer-hover/menu-button:text-sidebar-accent-foreground hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',\n // Increases the hit area of the button on mobile.\n 'after:absolute after:-inset-2 md:after:hidden',\n 'group-data-[collapsible=icon]:hidden',\n showOnHover &&\n 'group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground data-[state=open]:opacity-100 md:opacity-0',\n className,\n )}\n {...props}\n />\n )\n}\n\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarHeader,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarProvider,\n useSidebar,\n}\n","import * as React from 'react'\n\nconst MOBILE_BREAKPOINT = 768\n\nexport function useIsMobile() {\n const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)\n\n React.useEffect(() => {\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)\n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n }\n mql.addEventListener('change', onChange)\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)\n return () => mql.removeEventListener('change', onChange)\n }, [])\n\n return !!isMobile\n}\n","'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/react/ui/utils'\nimport { XIcon } from 'lucide-react'\nimport { Dialog as SheetPrimitive } from '@base-ui/react/dialog'\nimport { usePortalContainer } from '@/react/shadow-root'\n\nfunction Sheet({ ...props }: SheetPrimitive.Root.Props) {\n return <SheetPrimitive.Root data-slot=\"sheet\" {...props} />\n}\n\nfunction SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {\n return <SheetPrimitive.Trigger data-slot=\"sheet-trigger\" {...props} />\n}\n\nfunction SheetClose({ ...props }: SheetPrimitive.Close.Props) {\n return <SheetPrimitive.Close data-slot=\"sheet-close\" {...props} />\n}\n\nfunction SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {\n return <SheetPrimitive.Portal data-slot=\"sheet-portal\" container={usePortalContainer()} {...props} />\n}\n\nfunction SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {\n return (\n <SheetPrimitive.Backdrop\n data-slot=\"sheet-overlay\"\n className={cn(\n 'fixed inset-0 z-50 bg-black/50 data-closed:animate-out data-closed:fade-out-0 data-open:animate-in data-open:fade-in-0',\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction SheetContent({\n className,\n children,\n side = 'right',\n showCloseButton = true,\n ...props\n}: SheetPrimitive.Popup.Props & {\n side?: 'top' | 'right' | 'bottom' | 'left'\n showCloseButton?: boolean\n}) {\n return (\n <SheetPortal>\n <SheetOverlay />\n <SheetPrimitive.Popup\n data-slot=\"sheet-content\"\n className={cn(\n 'fixed z-50 flex flex-col gap-4 bg-background shadow-lg transition ease-in-out data-closed:animate-out data-closed:duration-300 data-open:animate-in data-open:duration-500',\n side === 'right' &&\n 'inset-y-0 right-0 h-full w-3/4 border-l data-closed:slide-out-to-right data-open:slide-in-from-right sm:max-w-sm',\n side === 'left' &&\n 'inset-y-0 left-0 h-full w-3/4 border-r data-closed:slide-out-to-left data-open:slide-in-from-left sm:max-w-sm',\n side === 'top' && 'inset-x-0 top-0 h-auto border-b data-closed:slide-out-to-top data-open:slide-in-from-top',\n side === 'bottom' &&\n 'inset-x-0 bottom-0 h-auto border-t data-closed:slide-out-to-bottom data-open:slide-in-from-bottom',\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton && (\n <SheetPrimitive.Close className=\"absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none\">\n <XIcon className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </SheetPrimitive.Close>\n )}\n </SheetPrimitive.Popup>\n </SheetPortal>\n )\n}\n\nfunction SheetHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"sheet-header\" className={cn('flex flex-col gap-1.5 p-4', className)} {...props} />\n}\n\nfunction SheetFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"sheet-footer\" className={cn('mt-auto flex flex-col gap-2 p-4', className)} {...props} />\n}\n\nfunction SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {\n return (\n <SheetPrimitive.Title\n data-slot=\"sheet-title\"\n className={cn('font-semibold text-foreground', className)}\n {...props}\n />\n )\n}\n\nfunction SheetDescription({ className, ...props }: SheetPrimitive.Description.Props) {\n return (\n <SheetPrimitive.Description\n data-slot=\"sheet-description\"\n className={cn('text-sm text-muted-foreground', className)}\n {...props}\n />\n )\n}\n\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription }\n","import { DebugManager } from '@joycostudio/xyz/debug'\nimport { useEffect } from 'react'\nimport { everyFrame, type Studio } from '../client/studio'\n\n/** Mount once in the host app for ?debug / Option+D controls. */\nexport function StudioDebug({ studio }: { studio: Studio }) {\n useEffect(() => {\n const debug = new DebugManager({\n createPane: async () => new (await import('tweakpane')).Pane({ title: 'debug' }),\n binding: { registerFrame: everyFrame },\n })\n for (const tool of studio.tools) debug.register(tool)\n return () => debug.dispose()\n }, [studio])\n return null\n}\n","import { Dialog } from '@base-ui/react/dialog'\nimport { Pin } from 'lucide-react'\nimport { useEffect, useRef, useState } from 'react'\nimport type { Studio } from '../client/studio'\nimport { Logo } from './logo'\nimport { usePinnedTools } from './pinned-tools'\nimport { StudioShadowRoot, usePortalContainer } from './shadow-root'\nimport { ToolIcon } from './tool-icon'\nimport { Command, CommandEmpty, CommandInput, CommandItem, CommandList } from './ui/command'\nimport { Kbd, KbdGroup } from './ui/kbd'\n\nexport type StudioCommandMenuProps = {\n studio: Studio\n /** Path to the host's Studio route. Defaults to /studio. */\n studioPath?: string\n /** Optional host router navigation (for example, Next.js router.push). */\n navigate?: (href: string) => void\n}\n\n/** Mount once in the host layout, including /studio, to jump to any registered tool with ⌘/Ctrl+K. */\nexport function StudioCommandMenu(props: StudioCommandMenuProps) {\n return (\n <StudioShadowRoot>\n <CommandMenu {...props} />\n </StudioShadowRoot>\n )\n}\n\nfunction CommandMenu({ studio, studioPath = '/studio', navigate }: StudioCommandMenuProps) {\n const { tools, pinned } = usePinnedTools(studio)\n const [open, setOpen] = useState(false)\n // Each opening starts a fresh search. Base UI keeps a closing popup mounted for a few frames, so a quick\n // reopen would otherwise keep the previous query and highlight; remount the list instead.\n const [session, setSession] = useState(0)\n const isOpen = useRef(open)\n isOpen.current = open\n const show = (next: boolean) => {\n if (next && !isOpen.current) setSession((count) => count + 1)\n setOpen(next)\n }\n const input = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n // Studio forwards preview shortcuts to its parent window; don't open a second menu in the iframe.\n if (window.frameElement?.getAttribute('data-slot') === 'studio-preview') return\n const onKey = (event: KeyboardEvent) => {\n if (event.defaultPrevented || event.isComposing || event.altKey || !(event.metaKey || event.ctrlKey)) return\n if (event.key.toLowerCase() !== 'k') return\n event.preventDefault()\n if (event.repeat) return\n show(!isOpen.current)\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [])\n\n const select = (id: string) => {\n show(false)\n const target = new URL(studioPath, window.location.href)\n target.hash = id\n if (target.pathname === window.location.pathname) {\n // Keep the mounted Studio and its drafts alive when switching tools.\n window.location.hash = target.hash\n } else if (navigate) {\n navigate(`${target.pathname}${target.search}${target.hash}`)\n } else {\n window.location.assign(target.href)\n }\n }\n\n return (\n <Dialog.Root open={open} onOpenChange={show}>\n <Dialog.Portal container={usePortalContainer()}>\n <Dialog.Backdrop data-slot=\"studio-command-overlay\" />\n {/* Closing returns focus to whatever had it, including elements inside Studio's own shadow root. */}\n <Dialog.Popup data-slot=\"studio-command-menu\" initialFocus={input}>\n <div data-slot=\"studio-command-heading\">\n <Dialog.Title aria-label=\"Studio tools\">\n <Logo aria-hidden />\n <strong>STUDIO</strong>\n </Dialog.Title>\n <Dialog.Close aria-label=\"Close tool menu\">\n <Kbd>esc</Kbd>\n </Dialog.Close>\n </div>\n <Dialog.Description data-slot=\"studio-command-description\">Open a tool in Studio.</Dialog.Description>\n <Command key={session} label=\"Studio tools\" loop vimBindings={false}>\n <CommandInput ref={input} placeholder=\"Search tools…\" />\n <CommandList>\n <CommandEmpty>{studio.definitions.length ? 'No tools found.' : 'No tools registered yet.'}</CommandEmpty>\n {tools.map((tool) => (\n <CommandItem\n key={tool.id}\n value={tool.id}\n keywords={[tool.title ?? tool.id]}\n onSelect={() => select(tool.id)}\n >\n <ToolIcon icon={tool.icon} />\n <span data-slot=\"studio-command-label\">{tool.title ?? tool.id}</span>\n {pinned.has(tool.id) && <Pin aria-hidden />}\n </CommandItem>\n ))}\n </CommandList>\n </Command>\n <div data-slot=\"studio-command-footer\" aria-hidden>\n <span>\n <KbdGroup>\n <Kbd>↑</Kbd>\n <Kbd>↓</Kbd>\n </KbdGroup>\n navigate\n </span>\n <span>\n <Kbd>↵</Kbd> open tool\n </span>\n </div>\n </Dialog.Popup>\n </Dialog.Portal>\n </Dialog.Root>\n )\n}\n","'use client'\n\nimport * as React from 'react'\nimport { Command as CommandPrimitive } from 'cmdk'\nimport { SearchIcon } from 'lucide-react'\nimport { cn } from '@/react/ui/utils'\n\n// shadcn/ui Command primitives; the host-safe menu theme is scoped in command-menu.css.\nfunction Command({ className, ...props }: React.ComponentProps<typeof CommandPrimitive>) {\n return (\n <CommandPrimitive\n data-slot=\"command\"\n className={cn(\n 'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',\n className,\n )}\n {...props}\n />\n )\n}\n\nconst CommandInput = React.forwardRef<\n React.ComponentRef<typeof CommandPrimitive.Input>,\n React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>\n>(function CommandInput({ className, ...props }, ref) {\n return (\n <div data-slot=\"command-input-wrapper\" className=\"flex h-9 items-center gap-2 border-b px-3\">\n <SearchIcon aria-hidden className=\"size-4 shrink-0 opacity-50\" />\n <CommandPrimitive.Input\n ref={ref}\n data-slot=\"command-input\"\n className={cn(\n 'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n </div>\n )\n})\n\nfunction CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {\n return (\n <CommandPrimitive.List\n data-slot=\"command-list\"\n className={cn('max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto', className)}\n {...props}\n />\n )\n}\n\nfunction CommandEmpty({ ...props }: React.ComponentProps<typeof CommandPrimitive.Empty>) {\n return <CommandPrimitive.Empty data-slot=\"command-empty\" className=\"py-6 text-center text-sm\" {...props} />\n}\n\nfunction CommandItem({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.Item>) {\n return (\n <CommandPrimitive.Item\n data-slot=\"command-item\"\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n />\n )\n}\n\nexport { Command, CommandInput, CommandList, CommandEmpty, CommandItem }\n","import { Select } from '@base-ui/react/select'\nimport { Check, ChevronDown, ChevronUp } from 'lucide-react'\nimport { type ReactNode } from 'react'\nimport { itemLabels } from './select-labels'\nimport { usePortalContainer } from './shadow-root'\nimport { cn } from './ui/utils'\n\nexport type StudioSelectProps = Omit<Select.Root.Props<string>, 'children'> & {\n label: string\n title?: string\n className?: string\n children?: ReactNode\n}\n\n/** Compact select shared by canvas and activity toolbars. */\nexport function StudioSelect({ label, title, className, children, ...props }: StudioSelectProps) {\n return (\n <Select.Root items={itemLabels(children)} {...props}>\n <Select.Trigger\n data-slot=\"select-trigger\"\n aria-label={label}\n title={title}\n className={cn(\n 'border-input text-foreground focus-visible:border-ring focus-visible:ring-ring/50 flex h-7 max-w-full shrink-0 items-center justify-between gap-2 rounded-md border bg-(--field) px-2 text-xs whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-(--field-hover) focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span:first-child]:truncate',\n className,\n )}\n >\n <Select.Value />\n <Select.Icon>\n <ChevronDown className=\"shrink-0 text-muted-foreground\" size={14} strokeWidth={1.5} aria-hidden />\n </Select.Icon>\n </Select.Trigger>\n <Select.Portal container={usePortalContainer()}>\n <Select.Positioner align=\"end\" sideOffset={6} alignItemWithTrigger={false} className=\"isolate z-50\">\n <Select.Popup\n className=\"relative max-h-(--available-height) min-w-(--anchor-width) overflow-y-auto rounded-md border border-border bg-popover p-1 font-(family-name:--studio-font) text-xs font-normal text-popover-foreground shadow-md outline-none\"\n data-slot=\"select-content\"\n >\n <Select.ScrollUpArrow className=\"sticky top-0 z-10 flex w-full justify-center bg-popover py-1\">\n <ChevronUp size={14} aria-hidden />\n </Select.ScrollUpArrow>\n <Select.List>{children}</Select.List>\n <Select.ScrollDownArrow className=\"sticky bottom-0 z-10 flex w-full justify-center bg-popover py-1\">\n <ChevronDown size={14} aria-hidden />\n </Select.ScrollDownArrow>\n </Select.Popup>\n </Select.Positioner>\n </Select.Portal>\n </Select.Root>\n )\n}\n\nexport function StudioSelectItem({ className, children, ...props }: Select.Item.Props) {\n return (\n <Select.Item\n data-slot=\"select-item\"\n className={cn(\n 'relative flex min-h-7 cursor-default items-center rounded-sm py-1.5 pr-8 pl-2 outline-none select-none data-[highlighted]:bg-(--field-hover) data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className,\n )}\n {...props}\n >\n <Select.ItemText>{children}</Select.ItemText>\n <Select.ItemIndicator className=\"absolute right-2\">\n <Check size={14} strokeWidth={1.5} aria-hidden />\n </Select.ItemIndicator>\n </Select.Item>\n )\n}\n","// Kept apart from select.tsx so it can be tested without the UI (and its build-generated stylesheet).\nimport { Children, isValidElement, type ReactNode } from 'react'\n\n/**\n * The selected item's label, from the `StudioSelectItem`s among the children (also inside fragments or\n * wrappers); Base UI shows the raw value otherwise.\n */\nexport function itemLabels(children: ReactNode, labels: Record<string, ReactNode> = {}) {\n Children.forEach(children, (child) => {\n if (!isValidElement<{ value?: unknown; children?: ReactNode }>(child)) return\n if (typeof child.props.value === 'string') labels[child.props.value] = child.props.children\n else itemLabels(child.props.children, labels)\n })\n return labels\n}\n","import { forwardRef, type ComponentPropsWithoutRef } from 'react'\nimport { cn } from './utils'\n\n/** Logical padding lets icon-bearing fields override only their leading inset. */\nexport const Input = forwardRef<HTMLInputElement, ComponentPropsWithoutRef<'input'>>(function Input(\n { className, ...props },\n ref,\n) {\n return (\n <input\n ref={ref}\n data-slot=\"input\"\n className={cn(\n 'border-input text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 h-8 w-full min-w-0 rounded-md border bg-transparent py-1 ps-3 pe-3 text-sm transition-[color,box-shadow] outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-50',\n className,\n )}\n {...props}\n />\n )\n})\n"],"mappings":"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","names":["Pin","useEffect","useRef","useState","useState","jsx","jsx","jsx","jsx","Slot","forwardRef","Slot","jsx","StudioSurface","Slot","StudioToolbar","jsx","forwardRef","Panel","Slot","PanelContent","jsx","jsxs","useState","editable","jsx","useEffect","useState","forwardRef","useRef","useState","useState","jsx","jsxs","useState","jsx","jsxs","forwardRef","PreviewCanvas","useState","useRef","useEffect","useState","React","cva","Slot","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","open","cva","Slot","button","Fragment","jsx","jsxs","useState","useRef","useEffect","handle","compare","Pin","useEffect","useEffect","Pin","useEffect","useRef","useState","React","jsx","jsxs","CommandInput","jsx","jsxs","useState","useRef","useEffect","Pin","jsx","jsxs","forwardRef","jsx","forwardRef","Input"]}