@joycostudio/studio 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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/core/diff.ts","../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/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 { 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\nconst editable = (target: EventTarget | null) =>\n target instanceof Element && target.matches('input, textarea, select, [contenteditable]')\n\nconst isShortcut = (event: KeyboardEvent) =>\n ((event.metaKey || event.ctrlKey) && SHORTCUTS.has(event.key.toLowerCase())) ||\n (event.key === COMPARE_KEY && !editable(event.target))\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 const [panelsHidden, setPanelsHidden] = useState(false)\n const [selected, setSelected] = useState<string | undefined>(studio.tools[0]?.definition.id)\n const preview = useRef<HTMLIFrameElement>(null)\n const handle = studio.tools.find((tool) => tool.definition.id === selected)\n const Preview = previewComponent ?? (handle?.definition.previewLayout === 'custom' ? 'iframe' : PreviewCanvas)\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 setPanelsHidden((hidden) => !hidden)\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?.state?.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 fromHash = () => {\n const id = decodeURIComponent(location.hash.slice(1))\n if (studio.tools.some((handle) => handle.definition.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' : (handle?.definition.previewLayout ?? 'canvas')}\n className=\"studio-workspace relative h-svh min-h-0 overflow-hidden text-xs\"\n >\n {handle?.definition.preview ? (\n <Preview\n data-slot=\"studio-preview\"\n ref={preview}\n key={handle.definition.id}\n src={handle.definition.preview}\n title={handle.definition.title ?? handle.definition.id}\n onLoad={(event) => forwardShortcuts(event.currentTarget)}\n />\n ) : (\n <div className=\"absolute inset-0 grid place-items-center text-faint\">\n {handle ? 'This tool has no preview' : 'No tools registered'}\n </div>\n )}\n\n {panelsHidden &&\n (['left', 'right'] as const).map((side) => {\n const Chevron = side === 'left' ? ChevronRight : ChevronLeft\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 Show Studio panels{' '}\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=\"Show Studio panels\"\n onClick={() => setPanelsHidden(false)}\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={panelsHidden}\n aria-hidden={panelsHidden}\n className={cn(\n 'transition-[left,right,width,translate] duration-200 ease-out motion-reduce:transition-none',\n panelsHidden && '-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(({ definition, state }) => {\n const title = definition.title ?? definition.id\n const isPinned = pinned.has(definition.id)\n const pinLabel = `${isPinned ? 'Unpin' : 'Pin'} ${title}`\n return (\n <SidebarMenuItem key={definition.id}>\n <SidebarMenuButton\n isActive={definition.id === selected}\n tooltip={title}\n onClick={() => (location.hash = definition.id)}\n >\n <span className=\"relative\">\n <ToolIcon icon={definition.icon} className=\"size-4\" />\n {state?.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(definition.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={panelsHidden}\n aria-hidden={panelsHidden}\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 panelsHidden && '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.0\",\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: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.3.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.3.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 { button, type DebugField, type DebugFolder, type DebugSchema } from '@joycostudio/xyz/debug'\nimport type { ToolState } from '../core/protocol'\nimport { error, type Result } from '../core/result'\nimport type { AnyTool, ToolDefinition } from '../core/tool'\nimport { connectBridge, type BridgeClient, type Connection } from './bridge'\nimport { assignDeep, live } from './live'\n\nexport type ToolHandle<TConfig extends object = any> = {\n readonly definition: ToolDefinition<TConfig>\n /** The live config. Read it to apply; writes (from any pane, or your code) sync to 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 /** True while `compare(true)` shows the saved config in place of the draft. */\n readonly comparing: boolean\n /**\n * Temporarily show the saved config (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 save(options?: { force?: boolean }): Promise<Result<ToolState<TConfig>>>\n discard(): Promise<Result<ToolState<TConfig>>>\n}\n\nexport type Studio = {\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 AnyTool[]\n /**\n * Runtime bridge URL (e.g. `ws://127.0.0.1:5179`). Omit or pass false to stay local, 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/** 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 per page: HMR re-evaluating `createStudio` replaces the previous instance instead of leaking its socket. */\nconst instances: Map<string, Studio> = ((globalThis as { __joycoStudio?: Map<string, Studio> }).__joycoStudio ??=\n new Map())\n\nexport function createStudio({ tools, runtime }: StudioOptions): Studio {\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\n const changed = () => {\n handle.version++\n for (const listener of listeners) listener(handle.config)\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 }\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 handle = {\n definition,\n config: live(raw, () => {\n changed()\n if (!stashed) push()\n }),\n state: null as ToolState<TConfig> | null,\n version: 0,\n comparing: false,\n compare(showSaved: boolean) {\n if (showSaved === handle.comparing || (showSaved && !handle.state)) return\n if (showSaved) stashed = structuredClone(raw)\n const next = showSaved ? handle.state!.saved.value : 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 touch()\n },\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 }\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 result = await bridge.request('tool.discard', { tool: definition.id })\n if (result.ok) receive(result.data)\n return result as Result<ToolState<TConfig>>\n },\n receive,\n resync,\n }\n return handle\n }\n\n const handles = new Map(tools.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 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 studioListeners.clear()\n if (typeof window !== 'undefined') window.removeEventListener?.('message', onMessage)\n if (runtime && instances.get(runtime) === studio) instances.delete(runtime)\n },\n }\n if (bridge && runtime) {\n instances.get(runtime)?.close()\n instances.set(runtime, 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 type { Studio, ToolHandle } from '../client/studio'\nimport { changedPaths } from '../core/diff'\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 (studio.connection.phase !== 'connected') return { tone: 'text-faint', text: 'Not persisting' }\n if (!state) return { tone: 'text-destructive', text: 'Restart studio dev' }\n if (handle.comparing) return { tone: 'text-sky-400', text: 'Showing saved' }\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, { schema: () => handle.controls() })\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 = (state?.dirty ? changedPaths(state.saved.value, state.draft.value) : []).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={!state?.dirty}\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","/** Dotted paths of every leaf that differs between two configs of the same shape. */\nexport function changedPaths(before: unknown, after: unknown, path = ''): string[] {\n const nested = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n if (nested(before) && nested(after)) {\n const keys = new Set([...Object.keys(before), ...Object.keys(after)])\n return [...keys].flatMap((key) => changedPaths(before[key], after[key], path ? `${path}.${key}` : key))\n }\n return JSON.stringify(before) === JSON.stringify(after) ? [] : [path]\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.tools].sort(\n (a, b) => Number(pinned.has(b.definition.id)) - Number(pinned.has(a.definition.id)),\n )\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","'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.tools.length ? 'No tools found.' : 'No tools registered yet.'}</CommandEmpty>\n {tools.map(({ definition: 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","Element","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","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/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/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 { 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 const [panelsHidden, setPanelsHidden] = useState(false)\n const [selected, setSelected] = useState<string | undefined>(studio.tools[0]?.definition.id)\n const preview = useRef<HTMLIFrameElement>(null)\n const handle = studio.tools.find((tool) => tool.definition.id === selected)\n const Preview = previewComponent ?? (handle?.definition.previewLayout === 'custom' ? 'iframe' : PreviewCanvas)\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 setPanelsHidden((hidden) => !hidden)\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.tools.some((handle) => handle.definition.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' : (handle?.definition.previewLayout ?? 'canvas')}\n className=\"studio-workspace relative h-svh min-h-0 overflow-hidden text-xs\"\n >\n {handle?.definition.preview ? (\n <Preview\n data-slot=\"studio-preview\"\n ref={preview}\n key={handle.definition.id}\n src={handle.definition.preview}\n title={handle.definition.title ?? handle.definition.id}\n onLoad={(event) => forwardShortcuts(event.currentTarget)}\n />\n ) : (\n <div className=\"absolute inset-0 grid place-items-center text-faint\">\n {handle ? 'This tool has no preview' : 'No tools registered'}\n </div>\n )}\n\n {panelsHidden &&\n (['left', 'right'] as const).map((side) => {\n const Chevron = side === 'left' ? ChevronRight : ChevronLeft\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 Show Studio panels{' '}\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=\"Show Studio panels\"\n onClick={() => setPanelsHidden(false)}\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={panelsHidden}\n aria-hidden={panelsHidden}\n className={cn(\n 'transition-[left,right,width,translate] duration-200 ease-out motion-reduce:transition-none',\n panelsHidden && '-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(({ definition, state, dirty }) => {\n const title = definition.title ?? definition.id\n const isPinned = pinned.has(definition.id)\n const pinLabel = `${isPinned ? 'Unpin' : 'Pin'} ${title}`\n return (\n <SidebarMenuItem key={definition.id}>\n <SidebarMenuButton\n isActive={definition.id === selected}\n tooltip={title}\n onClick={() => (location.hash = definition.id)}\n >\n <span className=\"relative\">\n <ToolIcon icon={definition.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(definition.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={panelsHidden}\n aria-hidden={panelsHidden}\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 panelsHidden && '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.2\",\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 type { AnyTool, 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 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 AnyTool[]\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.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 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.tools].sort(\n (a, b) => Number(pinned.has(b.definition.id)) - Number(pinned.has(a.definition.id)),\n )\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","'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.tools.length ? 'No tools found.' : 'No tools registered yet.'}</CommandEmpty>\n {tools.map(({ definition: 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","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"]}