@jbpark/live-editor 3.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"file":"dnd-BnXoytb5.js","names":["Children","t","CoreEditor","Children","Panel","PropertyPanel","LiveError","Renderer","Dnd","Renderer","DndImpl"],"sources":["../src/components/dnd/droppable.tsx","../src/components/dnd/draggable.tsx","../src/components/dnd/layout-context.ts","../src/components/dnd/panel/bulk-actions-bar.tsx","../src/components/dnd/panel/node.tsx","../src/components/dnd/panel/use-children-editor.ts","../src/components/dnd/panel/children.tsx","../src/components/dnd/panel/icon-map.tsx","../src/components/dnd/panel/use-items-editor.ts","../src/components/dnd/panel/items.tsx","../src/components/dnd/panel/field.tsx","../src/components/dnd/panel/field-group.tsx","../src/components/dnd/panel/panel.tsx","../src/components/dnd/layout.tsx","../src/components/dnd/renderer.tsx","../src/components/dnd/sortable.tsx","../src/components/dnd/overlay.tsx","../src/components/dnd/use-section-document.ts","../src/components/dnd/dnd.tsx","../src/components/dnd/index.ts"],"sourcesContent":["import { useDroppable } from '@dnd-kit/core';\nimport { Typography } from '@jbpark/ui-kit';\n\nimport { cn } from '~/utils';\n\nconst Droppable = ({\n children,\n className,\n}: React.ComponentPropsWithRef<'div'>) => {\n const { setNodeRef, isOver, active } = useDroppable({\n id: 'sortable-area',\n });\n\n const { setNodeRef: setBottomRef, isOver: isBottomOver } = useDroppable({\n id: 'sortable-area-bottom',\n });\n\n const isNewItemDragging = active?.data.current?.type === 'new-item';\n const shouldHighlight = isOver && isNewItemDragging;\n const shouldHighlightBottom = isBottomOver && isNewItemDragging;\n\n return (\n <div\n ref={setNodeRef}\n className={cn(\n 'min-h-full',\n 'border-2 border-dashed p-1',\n shouldHighlight ? 'border-blue-300 bg-blue-50' : 'border-gray-200',\n className,\n )}\n >\n {children}\n {isNewItemDragging && (\n <div\n ref={setBottomRef}\n className={cn(\n 'mt-2 min-h-24',\n 'rounded-lg border-2 border-dashed',\n 'transition-all duration-200',\n 'flex items-center justify-center',\n shouldHighlightBottom\n ? 'border-blue-400 bg-blue-100'\n : 'border-gray-300 bg-gray-50',\n )}\n >\n <Typography.Text className=\"text-sm text-gray-500\">\n {shouldHighlightBottom ? 'Drop here' : 'Drag here to add at bottom'}\n </Typography.Text>\n </div>\n )}\n </div>\n );\n};\n\nexport default Droppable;\n","import { useDraggable } from '@dnd-kit/core';\nimport { Card } from '@jbpark/ui-kit';\n\nimport type { Section } from '~/types';\nimport { cn } from '~/utils';\n\nexport interface DraggableItemDragState {\n ref: (node: HTMLElement | null) => void;\n dragProps: React.HTMLAttributes<HTMLElement>;\n isDragging: boolean;\n}\n\nexport interface DraggableItemProps {\n item: Section;\n children: (drag: DraggableItemDragState) => React.ReactNode;\n}\n\n// Owns the dnd-kit wiring (useDraggable + the `type: 'new-item'` data shape\n// Dnd's onDragEnd expects) so a custom palette only has to decide how\n// an item *looks*, not how dragging itself works. Exported as\n// Dnd.DraggableItem for that purpose; also used internally for the default\n// palette rendering, so both paths share the exact same drag wiring.\nconst DraggableItem = ({ item, children }: DraggableItemProps) => {\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({\n id: item.id,\n data: { type: 'new-item', item },\n });\n\n return children({\n ref: setNodeRef,\n dragProps: { ...listeners, ...attributes },\n isDragging,\n });\n};\n\n// The built-in card look, shared by the default (non-custom) palette\n// rendering and the drag overlay's floating preview — both rendered a plain\n// `<Draggable>` before this became a children-render-prop component.\nexport interface DefaultDraggableItemProps {\n item: Section;\n onAdd?: (item: Section) => void;\n // Double-click is the desktop convenience shortcut alongside drag — a\n // single click there would fire on every aborted/failed drag attempt.\n // On mobile there's nowhere to drag *to* (the palette lives in a Drawer\n // stacked over the canvas), so a tap can't be a failed drag, and\n // double-tap-to-dblclick synthesis from touch is unreliable anyway\n // (iOS Safari inconsistently fires it, and it can compete with the\n // browser's native double-tap-to-zoom gesture). Tapping just adds there.\n tapToAdd?: boolean;\n}\n\nexport const DefaultDraggableItem = ({\n item,\n onAdd,\n tapToAdd = false,\n}: DefaultDraggableItemProps) => (\n <DraggableItem item={item}>\n {({ ref, dragProps, isDragging }) => (\n <Card\n ref={ref}\n style={{ opacity: isDragging ? 0.5 : 1 }}\n {...dragProps}\n className={cn(\n 'cursor-grab',\n 'outline-none',\n 'hover:border-blue-300 hover:shadow-md',\n isDragging && 'opacity-50',\n )}\n onClick={tapToAdd && onAdd ? () => onAdd(item) : undefined}\n onDoubleClick={onAdd ? () => onAdd(item) : undefined}\n >\n {item.name}\n </Card>\n )}\n </DraggableItem>\n);\n\nexport default DraggableItem;\n","import { createContext, useContext } from 'react';\n\nimport type { DndPalette, DndPanel } from './dnd';\n\n// The layout state a custom arrangement needs. Separate from the palette and\n// panel data because a layout decides *where* things go, not what they\n// contain — the built-in layout reads only this slice.\nexport interface DndLayout {\n // From `useResponsiveSize` — the same value that picks the stacked mobile\n // arrangement, so a custom layout can branch on it without repeating the\n // breakpoint check. Also what the built-in palette reads to decide\n // tap-to-add: at a mobile breakpoint a tap can't be a failed drag attempt\n // (there's nothing visible to drag onto behind the Drawer) and dblclick\n // synthesis from double-tap is unreliable, so a single tap adds.\n isMobile: boolean;\n // `null` when nothing is selected. The built-in layout uses it to open the\n // properties Drawer on mobile, where the panel has nowhere else to go.\n selectedId: string | null;\n clearSelection: () => void;\n // The palette Drawer's open state. Dnd owns it because adding an item\n // closes the Drawer; a layout only opens it.\n paletteOpen: boolean;\n setPaletteOpen: (open: boolean) => void;\n}\n\n// Everything `Live.Dnd` publishes to its children, read back through the\n// three hooks below rather than as one object — a custom panel has no\n// business seeing the palette's items, and narrow hooks say which part of\n// Dnd a component actually depends on.\n//\n// `canvas` is the one node here rather than data: the droppable, the\n// sortable list and each section's compiled iframe are Dnd's own machinery,\n// so `Live.Dnd.Canvas` places it but nobody reproduces it.\ninterface DndRegions extends DndLayout {\n palette: DndPalette;\n panel: DndPanel;\n canvas: React.ReactNode;\n}\n\nexport const DndRegionContext = createContext<DndRegions | null>(null);\n\n// Internal, and takes a `subject` the public hooks don't: the caller as it\n// appears in source — a hook call, or the region element that wraps one — so\n// rendering `<Live.Dnd.Palette />` outside `Live.Dnd` reports the element the\n// reader actually wrote rather than the hook behind it.\nexport const useDndRegions = (subject: string): DndRegions => {\n const regions = useContext(DndRegionContext);\n\n if (!regions) {\n throw new Error(`${subject} must be used inside <Live.Dnd>.`);\n }\n\n return regions;\n};\n\n// The palette's items and the callback that adds one to the canvas. Pair it\n// with `Live.Dnd.DraggableItem` for the drag wiring and you have the whole\n// built-in palette's input.\nexport const useDndPalette = (): DndPalette =>\n useDndRegions('useDndPalette()').palette;\n\n// The selected section, its editable bindings, and the callbacks that commit\n// through Dnd's AST-update pipeline — everything the built-in property panel\n// runs on.\nexport const useDndPanel = (): DndPanel => useDndRegions('useDndPanel()').panel;\n\n// Returns the context object itself, narrowed: identity is stable across\n// renders, so this is safe in a dependency array.\nexport const useDndLayout = (): DndLayout => useDndRegions('useDndLayout()');\n","import { Button } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Copy, X } from 'lucide-react';\n\ninterface BulkActionsBarProps {\n count: number;\n onDuplicate: () => void;\n onMoveUp: () => void;\n onMoveDown: () => void;\n onDelete: () => void;\n onClear: () => void;\n}\n\nconst BulkActionsBar = ({\n count,\n onDuplicate,\n onMoveUp,\n onMoveDown,\n onDelete,\n onClear,\n}: BulkActionsBarProps) => {\n if (count === 0) {\n return null;\n }\n\n return (\n <div\n className=\"flex items-center justify-between rounded border\n border-blue-200 bg-blue-50 p-2\"\n >\n <div className=\"text-xs font-medium text-blue-700\">{count} selected</div>\n <div className=\"flex items-center space-x-1\">\n <Button\n size=\"small\"\n icon={<Copy />}\n title=\"Duplicate selected\"\n onClick={onDuplicate}\n />\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n title=\"Move selected up\"\n onClick={onMoveUp}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n title=\"Move selected down\"\n onClick={onMoveDown}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n title=\"Delete selected\"\n onClick={onDelete}\n />\n <Button size=\"small\" onClick={onClear}>\n Clear\n </Button>\n </div>\n </div>\n );\n};\n\nexport default BulkActionsBar;\n","import {\n type DataAttrNode,\n getCurrentValue,\n getStructuredValue,\n parseBinding,\n} from '~/utils/ast';\n\nimport Field from './field';\n\nexport interface FieldEditorProps {\n data: DataAttrNode;\n onChange?: (params: {\n id: string;\n label: string;\n property: string;\n value: unknown;\n }) => void;\n}\n\nconst Node = ({ data, onChange }: FieldEditorProps) => {\n const idAttr = data.dataAttributes.find(a => a.name === 'data-id');\n const bindingAttr = data.dataAttributes.find(a => a.name === 'data-binding');\n\n if (!idAttr?.value || !bindingAttr?.value) {\n return null;\n }\n\n const dataId = idAttr.value;\n const bindings = data.bindings || parseBinding(bindingAttr.value);\n\n if (!bindings.length) {\n return null;\n }\n\n return (\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {bindings.map(binding => {\n const currentValue = getCurrentValue(data, binding.property);\n const structuredValue = getStructuredValue(\n data,\n binding.property,\n binding.type,\n );\n\n return (\n <div key={binding.label} className=\"space-y-1\">\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">({binding.property})</span>\n </label>\n <Field\n binding={{\n id: dataId,\n label: binding.label,\n property: binding.property,\n type: binding.type,\n widget: binding.widget,\n options: binding.options,\n render: binding.render,\n min: binding.min,\n max: binding.max,\n pattern: binding.pattern,\n required: binding.required,\n meta: binding.meta,\n value: structuredValue,\n rawValue: currentValue,\n onChange: next =>\n onChange?.({\n id: dataId,\n label: binding.label,\n property: binding.property,\n value: next,\n }),\n }}\n onNodeChange={onChange}\n />\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default Node;\n","import { useEffect, useMemo } from 'react';\n\nimport { useMultiSelect } from '@jbpark/use-hooks';\n\nimport {\n type ChildrenAction,\n type ChildrenEdit,\n type DataAttrNode,\n getChildrenSignatures,\n} from '~/utils/ast';\n\nexport interface ChildrenEditorOptions {\n onChange?: (value: string) => void;\n}\n\n// Domain adapter: serializes a structural command for the existing binding\n// onChange/update path. The AST layer owns source validation and mutation.\nexport const useChildrenEditor = (\n items: DataAttrNode[],\n { onChange }: ChildrenEditorOptions = {},\n) => {\n const selection = useMultiSelect(items.length);\n const expected = useMemo(() => getChildrenSignatures(items), [items]);\n const revision = JSON.stringify(expected);\n const clear = selection.clear;\n\n // Reconcile only once new source arrives: rejected edits leave selection\n // intact, and external edits/undo cannot leave stale positional targets.\n useEffect(() => {\n clear();\n }, [revision, clear]);\n\n const commit = (action: ChildrenAction) => {\n const edit: ChildrenEdit = { kind: 'children-edit', expected, action };\n\n onChange?.(JSON.stringify(edit));\n };\n\n return {\n items,\n selection,\n actions: {\n move: (from: number, to: number) => commit({ type: 'move', from, to }),\n remove: (index: number) => commit({ type: 'remove', indices: [index] }),\n add: () => commit({ type: 'append' }),\n duplicateSelected: () =>\n commit({ type: 'duplicate', indices: [...selection.selected] }),\n moveSelected: (direction: 'up' | 'down') =>\n commit({\n type: 'move-selected',\n indices: [...selection.selected],\n direction,\n }),\n removeSelected: () =>\n commit({ type: 'remove', indices: [...selection.selected] }),\n },\n };\n};\n\nexport type ChildrenEditor = ReturnType<typeof useChildrenEditor>;\n","import { useMemo } from 'react';\n\nimport { Button, Checkbox } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\n\nimport { type DataAttrNode, findEditableChildren } from '~/utils/ast';\n\nimport type { PanelNodeChange } from '../dnd';\nimport BulkActionsBar from './bulk-actions-bar';\nimport Node from './node';\nimport { useChildrenEditor } from './use-children-editor';\n\ninterface Props {\n value: DataAttrNode[];\n onChange?: (value: string) => void;\n onNodeChange?: PanelNodeChange;\n}\n\nconst Children = ({ value, onChange, onNodeChange }: Props) => {\n const items = useMemo(() => (Array.isArray(value) ? value : []), [value]);\n\n const { selection, actions } = useChildrenEditor(items, { onChange });\n\n const editableChildrenMap = useMemo(() => {\n const map = new Map<number, DataAttrNode[]>();\n items.forEach((item, index) => {\n const editableNodes = findEditableChildren(item);\n if (editableNodes.length > 0) {\n map.set(index, editableNodes);\n }\n });\n return map;\n }, [items]);\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold text-green-700\">\n Children Items ({items.length})\n </div>\n <Button\n size=\"small\"\n color=\"green\"\n icon={<Plus />}\n onClick={actions.add}\n >\n Add Child\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={actions.duplicateSelected}\n onMoveUp={() => actions.moveSelected('up')}\n onMoveDown={() => actions.moveSelected('down')}\n onDelete={actions.removeSelected}\n onClear={selection.clear}\n />\n\n {items.map((item, itemIndex) => (\n <div\n key={item.id || itemIndex}\n className=\"space-y-2 rounded border border-green-200 bg-green-50 p-3\"\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-2\">\n <div\n onClick={e => selection.toggle(itemIndex, e.shiftKey)}\n className=\"inline-flex\"\n >\n <Checkbox\n checked={selection.isSelected(itemIndex)}\n onChange={() => {}}\n />\n </div>\n <div className=\"text-xs font-medium text-green-800\">\n Child {itemIndex + 1} ({item.tagName || 'fragment'})\n </div>\n </div>\n\n <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={itemIndex === 0}\n onClick={() => actions.move(itemIndex, itemIndex - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={itemIndex === items.length - 1}\n onClick={() => actions.move(itemIndex, itemIndex + 1)}\n />\n <Button\n title=\"Delete item\"\n danger\n size=\"small\"\n icon={<X />}\n onClick={() => actions.remove(itemIndex)}\n />\n </div>\n </div>\n\n {editableChildrenMap.has(itemIndex) && (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-green-700\">\n Editable Bindings:\n </div>\n {editableChildrenMap.get(itemIndex)!.map((editableNode, idx) => {\n const nodeId = editableNode.dataAttributes.find(\n a => a.name === 'data-id',\n )?.value;\n\n return (\n <div\n key={`editable-${nodeId || idx}`}\n className=\"rounded border border-green-100 bg-white p-2\"\n >\n <div className=\"mb-1 text-xs text-green-600\">\n {editableNode.tagName}\n </div>\n <Node data={editableNode} onChange={onNodeChange} />\n </div>\n );\n })}\n </div>\n )}\n\n {!!item.children && !editableChildrenMap.has(itemIndex) && (\n <div className=\"space-y-1\">\n <div className=\"text-xs font-medium text-green-700\">\n Child Nodes:\n </div>\n {item.children.map((node, nodeIndex) => (\n <div\n key={`node-${itemIndex}-${nodeIndex}`}\n className=\"ml-2 rounded border border-green-100 bg-white p-2\"\n >\n <Node data={node} onChange={onNodeChange} />\n </div>\n ))}\n </div>\n )}\n </div>\n ))}\n </div>\n );\n};\n\nexport default Children;\n","import type { LucideIcon } from 'lucide-react';\nimport {\n AlertCircle,\n ArrowDown,\n ArrowLeft,\n ArrowRight,\n ArrowUp,\n Bell,\n Bookmark,\n Calendar,\n Camera,\n Check,\n ChevronDown,\n ChevronRight,\n Clock,\n Download,\n Edit,\n Eye,\n Filter,\n Heart,\n Home,\n Image,\n Info,\n Link,\n Mail,\n Map,\n Menu,\n MessageCircle,\n Phone,\n Plus,\n Search,\n Settings,\n Share,\n ShoppingCart,\n Star,\n Trash,\n Upload,\n User,\n X,\n} from 'lucide-react';\n\nexport const ICON_MAP: Record<string, LucideIcon> = {\n AlertCircle,\n ArrowDown,\n ArrowLeft,\n ArrowRight,\n ArrowUp,\n Bell,\n Bookmark,\n Calendar,\n Camera,\n Check,\n ChevronDown,\n ChevronRight,\n Clock,\n Download,\n Edit,\n Eye,\n Filter,\n Heart,\n Home,\n Image,\n Info,\n Link,\n Mail,\n Map,\n Menu,\n MessageCircle,\n Phone,\n Plus,\n Search,\n Settings,\n Share,\n ShoppingCart,\n Star,\n Trash,\n Upload,\n User,\n X,\n};\n\n// The label/value pairs Field's icon-picker feeds to Select, derived once\n// from ICON_MAP — exported (see index.ts) so a custom panel can\n// reach icon-picker parity without rebuilding this itself, per #236/#237.\nexport const ICON_OPTIONS = Object.entries(ICON_MAP).map(([name, Icon]) => ({\n label: (\n <span className=\"flex items-center gap-2\">\n <Icon size={14} />\n {name}\n </span>\n ),\n value: name,\n}));\n","import { useEffect, useMemo } from 'react';\n\nimport * as t from '@babel/types';\nimport { Toast } from '@jbpark/ui-kit';\nimport { useMultiSelect } from '@jbpark/use-hooks';\nimport { nanoid } from 'nanoid';\n\nimport {\n type BindingRenderLeaf,\n type BindingRenderMap,\n type DataAttrNode,\n appendArrayItem,\n duplicateArrayItems,\n extract,\n extractNodeValue,\n extractObjectProperties,\n findEditableChildren,\n getCurrentValue,\n getStructuredValue,\n moveArrayItem,\n moveArrayItems,\n parseArrayExpression,\n parseBinding,\n parseValue,\n removeArrayItems,\n updateArrayItemProperty,\n updateArrayItemValue,\n} from '~/utils/ast';\n\nimport type { PanelBinding, PanelNodeChange } from '../dnd';\n\n// One data-bound element discovered inside a JSX-valued item property.\n// These are the elements the top-level `bindings` array can't reach —\n// `extract()` doesn't walk into an attribute expression, so they're found\n// by re-extracting the property's own JSX here (#308).\nexport interface ItemsEditorNestedElement {\n // The element's `data-id`, which is what commits address it by.\n id: string;\n tagName: string;\n bindings: PanelBinding[];\n}\n\nexport interface ItemsEditorNestedGroup {\n // The item property holding this JSX (e.g. `children`, `label`).\n property: string;\n elements: ItemsEditorNestedElement[];\n // Set instead of `elements` when the JSX parsed but declared no binding\n // at all. Editing the property's raw source is the only thing left to\n // offer, so this is a `jsx`-typed binding over that source (#298).\n fallback?: PanelBinding;\n}\n\nexport interface ItemsEditorItem {\n // Stable only for this parse of `value` — regenerated whenever the source\n // string changes. Fine as a React key, not as an identity across edits;\n // use `elementIndex` for that.\n id: string;\n // Position among the visible items of this kind, which is what selection\n // indices refer to.\n index: number;\n // Position in the array's elements, which is what every `~/utils/ast`\n // item function addresses. Differs from `index` when the array mixes\n // objects and primitives.\n elementIndex: number;\n // An object item's plain (non-JSX) properties, already resolved through\n // the binding `render` map.\n properties: PanelBinding[];\n // An object item's JSX-valued properties.\n nested: ItemsEditorNestedGroup[];\n // A primitive item's own value. Absent on object items.\n value?: PanelBinding;\n}\n\nexport interface ItemsEditorActions {\n add: () => void;\n move: (elementIndex: number, toIndex: number) => void;\n remove: (elementIndex: number) => void;\n duplicateSelected: () => void;\n moveSelected: (direction: 'up' | 'down') => void;\n removeSelected: () => void;\n}\n\nexport interface ItemsEditor {\n // Which kind the array is being edited as. The panel shows one kind at a\n // time; an array holding both is treated as objects, and the primitives\n // stay untouched rather than being dropped.\n kind: 'object' | 'primitive';\n items: ItemsEditorItem[];\n // `@jbpark/use-hooks`' multi-select state, re-exposed as-is: `selected`,\n // `toggle`, `isSelected`, `clear`, `replace`. Its indices are item\n // `index` values, not `elementIndex` — the actions below translate.\n selection: ReturnType<typeof useMultiSelect>;\n actions: ItemsEditorActions;\n // The source didn't parse as an array expression. `items` is empty; the\n // built-in panel also raises a toast.\n parseError: boolean;\n}\n\nexport interface ItemsEditorOptions {\n render?: BindingRenderMap;\n // Commits a whole new array source. Every mutation here goes through\n // `~/utils/ast`'s item functions, which re-parse the source and hand back\n // a string, so no AST node is held or edited across renders.\n onChange?: (value: string) => void;\n // Commits an edit to one nested element, addressed by its own `data-id`.\n // A single binding's `onChange` can't express this — see #308.\n onNodeChange?: PanelNodeChange;\n}\n\nconst resolveLeaf = (\n render: BindingRenderMap | undefined,\n key: string,\n): BindingRenderLeaf | null => {\n const leaf = render?.[key];\n\n return leaf && 'type' in leaf ? (leaf as BindingRenderLeaf) : null;\n};\n\nconst resolveMap = (\n render: BindingRenderMap | undefined,\n key: string,\n): BindingRenderMap | undefined => {\n const leaf = render?.[key];\n\n return leaf && !('type' in leaf) ? (leaf as BindingRenderMap) : undefined;\n};\n\ninterface RawObjectItem {\n id: string;\n index: number;\n elementIndex: number;\n editableProperties: ReturnType<typeof extractObjectProperties>;\n jsxBindings: Record<string, DataAttrNode[]>;\n jsxFallbacks: Record<string, string>;\n}\n\ninterface RawPrimitiveItem {\n id: string;\n index: number;\n elementIndex: number;\n value: string | number | boolean | null;\n type: ReturnType<typeof extractNodeValue>['type'];\n}\n\n// Pulls the data-bound elements out of one JSX-valued property. A container\n// declaring `children` wins outright: it owns the elements below it, so\n// listing them separately would offer the same edit twice.\nconst bindingsInJSX = (source: string): DataAttrNode[] => {\n const nodes = extract(source);\n const container = nodes.find(n =>\n n.bindings?.some(b => b.property === 'children'),\n );\n\n if (container) {\n return [container];\n }\n\n const bindings: DataAttrNode[] = [];\n\n nodes.forEach(n => {\n if (\n n.bindings &&\n n.bindings.length > 0 &&\n n.dataAttributes.some(a => a.name === 'data-id')\n ) {\n bindings.push(n);\n }\n\n bindings.push(...findEditableChildren(n));\n });\n\n return bindings;\n};\n\n// The parse. Split from the binding construction below so the Babel work is\n// memoized on the source string alone, while the callbacks the bindings\n// close over stay current on every render.\nconst parseSource = (value: string) => {\n const ast = parseArrayExpression(value);\n\n if (!ast) {\n return { objectItems: [], primitiveItems: [], parseError: true };\n }\n\n const objectItems: RawObjectItem[] = [];\n const primitiveItems: RawPrimitiveItem[] = [];\n ast.elements.forEach((element, elementIndex) => {\n if (!t.isExpression(element)) {\n return;\n }\n\n if (!t.isObjectExpression(element)) {\n const extracted = extractNodeValue(element);\n\n primitiveItems.push({\n id: nanoid(6),\n index: primitiveItems.length,\n elementIndex,\n value: extracted.value,\n type: extracted.type,\n });\n return;\n }\n\n const jsxBindings: Record<string, DataAttrNode[]> = {};\n const jsxFallbacks: Record<string, string> = {};\n\n element.properties.forEach(prop => {\n if (\n !t.isObjectProperty(prop) ||\n !t.isIdentifier(prop.key) ||\n !(t.isJSXElement(prop.value) || t.isJSXFragment(prop.value))\n ) {\n return;\n }\n\n const propertyName = prop.key.name;\n\n try {\n const found = bindingsInJSX(\n value.slice(prop.value.start!, prop.value.end!),\n );\n\n if (found.length > 0) {\n jsxBindings[propertyName] = found;\n } else {\n jsxFallbacks[propertyName] = value.slice(\n prop.value.start!,\n prop.value.end!,\n );\n }\n } catch (error) {\n console.error(\n `Failed to parse JSX in property '${propertyName}':`,\n error,\n );\n }\n });\n\n const editableProperties = extractObjectProperties(element);\n\n for (const property of Object.values(editableProperties)) {\n if (property.type === 'array' || property.type === 'object') {\n property.value = value.slice(\n property.astNode.start!,\n property.astNode.end!,\n );\n }\n }\n\n objectItems.push({\n id: nanoid(6),\n index: objectItems.length,\n elementIndex,\n editableProperties,\n jsxBindings,\n jsxFallbacks,\n });\n });\n\n return { objectItems, primitiveItems, parseError: false };\n};\n\n// The array-editing engine behind the built-in Items panel, exposed so a\n// consumer can render their own markup over it (#237/#308 follow-up).\n//\n// What it saves reimplementing: re-parsing each item's JSX to find nested\n// data-bound elements, resolving the binding `render` map, translating\n// visible item positions to array element positions before every edit, and\n// reconciling the selection after a move or delete (#285). Everything comes\n// back as `PanelBinding`s, the same currency `useDndPanel()` and\n// `Live.Dnd.Field` already speak, so nothing here requires touching Babel.\nexport const useItemsEditor = (\n value: string,\n { render, onChange, onNodeChange }: ItemsEditorOptions = {},\n): ItemsEditor => {\n const { objectItems, primitiveItems, parseError } = useMemo(\n () => parseSource(value),\n [value],\n );\n\n useEffect(() => {\n if (parseError) {\n Toast.error('Failed to parse items', {\n description: 'Check the console for details.',\n });\n }\n }, [parseError]);\n\n const kind =\n primitiveItems.length > 0 && objectItems.length === 0\n ? 'primitive'\n : 'object';\n const isPrimitive = kind === 'primitive';\n\n const selection = useMultiSelect(\n isPrimitive ? primitiveItems.length : objectItems.length,\n );\n\n // `null` means the edit could not be applied.\n const commit = (next: string | null) => {\n if (next === null) {\n Toast.error('Failed to update this item', {\n description:\n 'The source was preserved. Structural edits require a dense array without spreads; use the code editor for unsupported syntax.',\n });\n\n return false;\n }\n\n onChange?.(next);\n\n return true;\n };\n\n // Selection indices are positions among the visible items; every AST\n // function addresses element positions. Keeping the two apart is what\n // stops an edit from dropping the items that aren't on screen.\n const elementIndicesOf = (indices: Set<number>) => {\n const items = isPrimitive ? primitiveItems : objectItems;\n\n return new Set(\n items\n .filter(item => indices.has(item.index))\n .map(item => item.elementIndex),\n );\n };\n\n const updateProperty = (\n elementIndex: number,\n propertyKey: string,\n next: unknown,\n ) => {\n commit(\n updateArrayItemProperty(value, elementIndex, propertyKey, next, render),\n );\n };\n\n const actions: ItemsEditorActions = {\n add: () => commit(appendArrayItem(value, kind)),\n\n move: (elementIndex, toIndex) => {\n const items = isPrimitive ? primitiveItems : objectItems;\n const target = items.find(item => item.index === toIndex);\n\n if (!target) {\n return;\n }\n\n const accepted = commit(\n moveArrayItem(value, elementIndex, target.elementIndex),\n );\n // Positions shift after a move, but the count doesn't, so\n // `useMultiSelect` never reconciles the set on its own — clear it so a\n // later bulk action can't target the wrong elements. See #285.\n if (accepted) {\n selection.clear();\n }\n },\n\n remove: elementIndex => {\n const accepted = commit(\n removeArrayItems(value, new Set([elementIndex]), kind),\n );\n // Removing an item shifts every position after it; same reasoning.\n if (accepted) {\n selection.clear();\n }\n },\n\n duplicateSelected: () =>\n commit(duplicateArrayItems(value, elementIndicesOf(selection.selected))),\n\n moveSelected: direction => {\n const result = moveArrayItems(\n value,\n elementIndicesOf(selection.selected),\n direction,\n );\n\n if (!result) {\n commit(null);\n return;\n }\n\n // Translate the moved source positions back into the visible kind.\n const parsed = parseArrayExpression(result.code);\n const visible =\n parsed?.elements.flatMap((node, index) =>\n t.isExpression(node) && t.isObjectExpression(node) === !isPrimitive\n ? [index]\n : [],\n ) ?? [];\n selection.replace(\n new Set(\n visible.flatMap((position, index) =>\n result.indices.has(position) ? [index] : [],\n ),\n ),\n );\n commit(result.code);\n },\n\n removeSelected: () => {\n const accepted = commit(\n removeArrayItems(value, elementIndicesOf(selection.selected), kind),\n );\n if (accepted) {\n selection.clear();\n }\n },\n };\n\n // Built fresh each render rather than inside the memo above: these close\n // over `onChange`/`onNodeChange`, and the work is a plain walk of the\n // already-parsed result — no Babel.\n const items: ItemsEditorItem[] = isPrimitive\n ? primitiveItems.map(item => ({\n id: item.id,\n index: item.index,\n elementIndex: item.elementIndex,\n properties: [],\n nested: [],\n value: {\n id: `primitive-${item.id}`,\n label: `item-${item.index}`,\n property: item.type,\n value: item.value ?? '',\n rawValue: String(item.value ?? ''),\n onChange: next =>\n commit(updateArrayItemValue(value, item.elementIndex, next)),\n },\n }))\n : objectItems.map(item => {\n const properties: PanelBinding[] = Object.entries(\n item.editableProperties,\n ).map(([key, prop]) => {\n const leaf = resolveLeaf(render, key);\n\n return {\n id: `item-${item.id}-${key}`,\n label: key,\n property: leaf ? (leaf.property ?? (leaf.type as string)) : key,\n type: leaf?.type,\n render: leaf ? leaf.render : resolveMap(render, key),\n value: parseValue(String(prop.value)),\n rawValue: String(prop.value),\n // Carried through so a consumer can label the control with the\n // property's actual kind, as the built-in panel does.\n meta: { valueType: prop.type },\n onChange: next => updateProperty(item.elementIndex, key, next),\n };\n });\n\n const nested: ItemsEditorNestedGroup[] = [\n ...Object.entries(item.jsxBindings).map(([property, nodes]) => ({\n property,\n elements: nodes.flatMap(node => {\n const id = node.dataAttributes.find(\n a => a.name === 'data-id',\n )?.value;\n const attr = node.dataAttributes.find(\n a => a.name === 'data-binding',\n )?.value;\n\n if (!id || !attr) {\n return [];\n }\n\n const parsed = node.bindings ?? parseBinding(attr);\n\n if (!parsed.length) {\n return [];\n }\n\n return [\n {\n id,\n tagName: node.tagName || 'element',\n bindings: parsed.map(binding => ({\n id,\n label: binding.label,\n property: binding.property,\n type: binding.type,\n widget: binding.widget,\n options: binding.options,\n render: binding.render,\n min: binding.min,\n max: binding.max,\n pattern: binding.pattern,\n required: binding.required,\n meta: binding.meta,\n value: getStructuredValue(\n node,\n binding.property,\n binding.type,\n ),\n rawValue: getCurrentValue(node, binding.property),\n onChange: (next: unknown) =>\n onNodeChange?.({\n id,\n label: binding.label,\n property: binding.property,\n value: next,\n }),\n })),\n },\n ];\n }),\n })),\n ...Object.entries(item.jsxFallbacks).map(([property, code]) => ({\n property,\n elements: [],\n fallback: {\n id: `item-${item.id}-${property}-jsx`,\n label: property,\n property,\n type: 'jsx' as const,\n value: code,\n rawValue: code,\n onChange: (next: unknown) =>\n updateProperty(item.elementIndex, property, next),\n },\n })),\n ];\n\n return {\n id: item.id,\n index: item.index,\n elementIndex: item.elementIndex,\n properties,\n nested,\n };\n });\n\n return { kind, items, selection, actions, parseError };\n};\n","import { Button, Checkbox } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\n\nimport type { BindingRenderMap } from '~/utils/ast';\n\nimport type { PanelNodeChange } from '../dnd';\nimport BulkActionsBar from './bulk-actions-bar';\nimport Field from './field';\nimport {\n type ItemsEditorNestedGroup,\n useItemsEditor,\n} from './use-items-editor';\n\ninterface Props {\n value: string;\n render?: BindingRenderMap;\n onChange?: (value: string) => void;\n onChildChange?: PanelNodeChange;\n}\n\n// The data-bound elements found inside one JSX-valued property, or the\n// raw-source fallback when that property declared no binding at all (#298).\nconst NestedGroup = ({\n group,\n onNodeChange,\n}: {\n group: ItemsEditorNestedGroup;\n onNodeChange?: PanelNodeChange;\n}) => {\n if (group.fallback) {\n return (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {group.property}\n </div>\n <Field binding={group.fallback} onNodeChange={onNodeChange} />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {group.property} Bindings ({group.elements.length}):\n </div>\n {group.elements.map(element => (\n <div\n key={`${group.property}-${element.id}`}\n className=\"rounded border border-blue-100 bg-blue-50 p-2\"\n >\n <div className=\"mb-1 text-xs text-blue-600\">\n &lt;{element.tagName}&gt;\n </div>\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {element.bindings.map(binding => (\n <div key={binding.label} className=\"space-y-1\">\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">\n ({binding.property})\n </span>\n </label>\n <Field binding={binding} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n </div>\n </div>\n ))}\n </div>\n );\n};\n\n// Presentation for `useItemsEditor`. Everything that reads or writes the\n// array source lives in that hook, which is exported so a consumer can put\n// their own markup over the same engine — see its doc comment (#237/#308).\nconst Items = ({ value, render, onChange, onChildChange }: Props) => {\n const { kind, items, selection, actions } = useItemsEditor(value, {\n render,\n onChange,\n onNodeChange: onChildChange,\n });\n\n const bulkBar = (\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={actions.duplicateSelected}\n onMoveUp={() => actions.moveSelected('up')}\n onMoveDown={() => actions.moveSelected('down')}\n onDelete={actions.removeSelected}\n onClear={selection.clear}\n />\n );\n\n const itemControls = (item: { index: number; elementIndex: number }) => (\n <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={item.index === 0}\n onClick={() => actions.move(item.elementIndex, item.index - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={item.index === items.length - 1}\n onClick={() => actions.move(item.elementIndex, item.index + 1)}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n disabled={items.length <= 1}\n onClick={() => actions.remove(item.elementIndex)}\n />\n </div>\n );\n\n if (kind === 'primitive') {\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold\">Items ({items.length})</div>\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n onClick={actions.add}\n >\n Add Item\n </Button>\n </div>\n\n {bulkBar}\n\n {items.map(item => (\n <div\n key={item.id}\n className=\"space-y-2 rounded border border-gray-100 bg-gray-50 p-2\"\n >\n <div className=\"flex items-center justify-between space-x-1\">\n <div\n onClick={e => selection.toggle(item.index, e.shiftKey)}\n className=\"inline-flex\"\n >\n <Checkbox\n checked={selection.isSelected(item.index)}\n onChange={() => {}}\n />\n </div>\n {itemControls(item)}\n </div>\n <Field binding={item.value!} onNodeChange={onChildChange} />\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold\">Items ({items.length})</div>\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n disabled={items.length === 0}\n onClick={actions.add}\n >\n Add Item\n </Button>\n </div>\n\n {bulkBar}\n\n {items.map(item => (\n <div key={item.id} className=\"space-y-3 rounded border bg-gray-50 p-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-2\">\n <div\n onClick={e => selection.toggle(item.index, e.shiftKey)}\n className=\"inline-flex\"\n >\n <Checkbox\n checked={selection.isSelected(item.index)}\n onChange={() => {}}\n />\n </div>\n <div className=\"text-xs font-medium\">Item {item.index + 1}</div>\n </div>\n {itemControls(item)}\n </div>\n <div className=\"space-y-2\">\n {item.properties.map(binding => (\n <div key={`${item.id}-${binding.label}`}>\n <div className=\"flex flex-col space-y-2\">\n <label className=\"w-20 shrink-0 text-xs font-medium\">\n {binding.label}\n </label>\n <Field binding={binding} onNodeChange={onChildChange} />\n </div>\n <span className=\"text-right text-xs text-gray-500\">\n ({String(binding.meta?.valueType)})\n </span>\n </div>\n ))}\n </div>\n <div className=\"space-y-3 border-t pt-2\">\n {item.nested.length ? (\n item.nested.map(group => (\n <NestedGroup\n key={group.property}\n group={group}\n onNodeChange={onChildChange}\n />\n ))\n ) : (\n <div className=\"text-xs text-gray-500\">\n ✓ No JSX bindings found\n </div>\n )}\n </div>\n </div>\n ))}\n </div>\n );\n};\n\nexport default Items;\n","import { type ComponentProps, useEffect, useRef, useState } from 'react';\n\nimport {\n Checkbox,\n ColorPicker,\n DatePicker,\n Input,\n RichTextEditor,\n Select,\n Upload,\n type UploadFile,\n} from '@jbpark/ui-kit';\nimport { useDebounce } from '@jbpark/use-hooks';\n\nimport CoreEditor from '~/components/editor/core';\nimport { BINDING_PROP } from '~/constants';\nimport { parseValue, validateBindingValue } from '~/utils/ast';\n\nimport type { PanelBinding, PanelNodeChange } from '../dnd';\nimport Children from './children';\nimport { ICON_MAP, ICON_OPTIONS } from './icon-map';\nimport Items from './items';\n\n// Exported as `Live.Dnd.Field` (see index.ts) so a custom panel can\n// hand any single binding back to the built-in control instead of\n// reimplementing it — most usefully for `items`/`children` bindings, whose\n// editors discover nested data-bound elements by re-extracting the value's\n// own JSX (~100 lines of Babel walking a consumer would otherwise have to\n// reproduce). Renders the *control* only; the built-in panel's label comes\n// from `FieldGroup`, so a consumer supplies their own heading and layout.\nexport interface FieldProps {\n binding: PanelBinding;\n // `Items`/`Children` edit a *different* element than `binding` itself —\n // an array item or a sibling child, each with its own id/label/property —\n // which `binding.onChange`'s single-value shape can't express. This is\n // the node-level escape hatch those two need (see #237's documented\n // items/children boundary). Not part of `PanelBinding`, which is\n // per-binding; it reaches a custom panel through `useDndPanel()`\n // instead (#308). Omit it and nested array/children edits won't commit.\n onNodeChange?: PanelNodeChange;\n}\n\nconst isColorProperty = (propertyName: string): boolean => {\n const name = propertyName.toLowerCase();\n return name.includes('color');\n};\n\nconst normalizeToHex = (value: string): string => {\n const trimmed = value.trim();\n\n if (/^#([0-9A-Fa-f]{3}){1,2}$/.test(trimmed)) {\n return trimmed;\n }\n return '#000000';\n};\n\nconst parseDateValue = (value: string): Date | undefined => {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n\n if (!match) {\n return undefined;\n }\n\n const [, year, month, day] = match;\n const date = new Date(Number(year), Number(month) - 1, Number(day));\n\n return Number.isNaN(date.getTime()) ? undefined : date;\n};\n\nconst formatDateValue = (date: Date): string => {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return `${year}-${month}-${day}`;\n};\n\n// ColorPicker's onChange fires on every drag frame — committing straight\n// to `onChange` (which drives the AST parse/mutate/re-serialize +\n// generateSections + compile pipeline, see #130) makes a single drag cost\n// upward of 15-25ms per frame. Debouncing the *commit* keeps that pipeline\n// to roughly one run per pause instead of one per frame, while a local\n// `liveValue` state keeps the swatch/hex text updating every frame for\n// responsiveness — ColorPicker is fully controlled (`useControllableState`\n// with `value` always set here), so without this it would visually snap\n// back to the last committed color between debounced commits.\nconst COLOR_COMMIT_DELAY = 75;\n\n// A curated subset rather than `toolbar` (every preset): the panel is a\n// small sidebar field, not a full document editor, so this keeps to the\n// formatting controls most binding content actually needs.\nconst RICHTEXT_TOOLBAR: ComponentProps<typeof RichTextEditor>['toolbar'] = [\n 'bold',\n 'italic',\n 'underline',\n 'bulletList',\n 'orderedList',\n 'link',\n];\n\ninterface ColorPickerFieldProps {\n value: string;\n onChange: (value: string) => void;\n}\n\nconst ColorPickerField = ({ value, onChange }: ColorPickerFieldProps) => {\n const [liveValue, setLiveValue] = useState(value);\n // Tracks `value` purely to detect an external change during render (see\n // below) — refs can't be read/written during render, so this has to be\n // state even though nothing here reads `prevValue` itself afterward.\n const [prevValue, setPrevValue] = useState(value);\n const lastCommittedRef = useRef(value);\n\n // The committed `value` can also change from outside (undo/redo, another\n // field touching the same binding) — stay in sync with it rather than\n // only ever tracking our own commits. Adjusted during render (React's\n // recommended \"reset state when a prop changes\" pattern) rather than in\n // an effect, so the mismatched frame never actually paints.\n if (value !== prevValue) {\n setPrevValue(value);\n setLiveValue(value);\n }\n\n // `lastCommittedRef` only needs to be current by the time `commit` next\n // runs (always from an event handler / debounce timer, never render), so\n // syncing it in an effect — instead of alongside the state adjustment\n // above — keeps the ref access out of the render phase entirely.\n useEffect(() => {\n lastCommittedRef.current = value;\n }, [value]);\n\n const commit = (next: string) => {\n if (next === lastCommittedRef.current) {\n return;\n }\n lastCommittedRef.current = next;\n onChange(next);\n };\n\n const debouncedCommit = useDebounce(() => commit(liveValue), {\n delay: COLOR_COMMIT_DELAY,\n autoInvoke: false,\n });\n\n return (\n <ColorPicker\n showText\n value={liveValue}\n onChange={next => {\n setLiveValue(next);\n debouncedCommit();\n }}\n onOpenChange={open => {\n // Flush immediately on close (picker dismissed / selection\n // finished) instead of waiting out the debounce window, so the\n // last color is never at risk of being dropped by an unmount\n // racing the pending timeout.\n if (!open) {\n commit(liveValue);\n }\n }}\n />\n );\n};\n\nconst Field = ({ binding, onNodeChange }: FieldProps) => {\n // `value` is already structured (its real JS type); `rawValue` is the exact\n // source text used for the raw editors (Items/code/textarea) and as the\n // <input> defaultValue. See #238.\n const { id, value, rawValue, onChange } = binding;\n\n const [validationError, setValidationError] = useState<string | null>(null);\n\n // The text-like inputs below (url/asset/number/textarea) commit on blur, so\n // they need local live state to hold what the user is typing. Left\n // uncontrolled (`defaultValue`), they ignored later changes to the canonical\n // value — an undo/redo or another field touching the same binding — because\n // `Field` reconciles rather than remounts (stable `key={binding.label}`).\n // The stale text then got re-committed on blur, clobbering the undo. Track\n // the canonical `rawValue` with a render-phase reset, the same pattern\n // `ColorPickerField` uses above. See #284. (The date picker commits on\n // change, not blur, so it can bind the prop directly with no local state.)\n const [text, setText] = useState(rawValue);\n const [prevRawValue, setPrevRawValue] = useState(rawValue);\n\n if (rawValue !== prevRawValue) {\n setPrevRawValue(rawValue);\n setText(rawValue);\n }\n\n if (\n binding.property === 'items' ||\n binding.property === 'data' ||\n binding.type === 'array'\n ) {\n return (\n <Items\n value={rawValue}\n render={binding.render}\n onChange={onChange}\n onChildChange={onNodeChange}\n />\n );\n }\n\n if (binding.type === 'richtext') {\n return (\n <RichTextEditor\n value={rawValue}\n toolbar={RICHTEXT_TOOLBAR}\n onChange={next => {\n if (next !== rawValue) {\n onChange(next);\n }\n }}\n />\n );\n }\n\n if (binding.property === BINDING_PROP.INNER_HTML || binding.type === 'jsx') {\n const isHTML = binding.property === BINDING_PROP.INNER_HTML;\n\n return (\n <CoreEditor\n value={rawValue}\n height=\"150px\"\n fragment={!isHTML}\n raw={isHTML}\n onSave={next => {\n if (next !== rawValue) {\n onChange(next);\n }\n }}\n />\n );\n }\n\n if (binding.property === 'children' && Array.isArray(value)) {\n return (\n <Children value={value} onChange={onChange} onNodeChange={onNodeChange} />\n );\n }\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n const objectValue = value as Record<string, unknown>;\n\n return (\n <div className=\"space-y-2 rounded border border-gray-200 bg-gray-50 p-2\">\n {Object.entries(objectValue).map(([key, val]) => (\n <div key={key} className=\"space-y-1\">\n <label className=\"block text-xs font-medium text-gray-600\">\n {key}\n </label>\n <Field\n binding={{\n id,\n label: key,\n property:\n binding.render?.[key] && 'type' in binding.render[key]\n ? (binding.render[key].type as string)\n : key,\n type:\n binding.render?.[key] && 'type' in binding.render[key]\n ? (binding.render[key] as { type: PanelBinding['type'] })\n .type\n : undefined,\n render:\n binding.render?.[key] && !('type' in binding.render[key])\n ? (binding.render[key] as PanelBinding['render'])\n : undefined,\n value: val,\n rawValue:\n typeof val === 'object' && val !== null\n ? JSON.stringify(val)\n : String(val),\n onChange: next => {\n onChange({ ...objectValue, [key]: next });\n },\n }}\n onNodeChange={onNodeChange}\n />\n </div>\n ))}\n </div>\n );\n }\n\n if (binding.type === 'boolean' || typeof value === 'boolean') {\n return (\n <Checkbox\n checked={value === true || value === 'true'}\n onChange={checked => {\n onChange(checked);\n }}\n />\n );\n }\n\n const stringValue = rawValue;\n\n if (binding.options && Array.isArray(binding.options)) {\n return (\n <Select\n value={stringValue}\n options={binding.options}\n onChange={next => {\n if (next !== value) {\n onChange(next);\n }\n }}\n />\n );\n }\n\n if (binding.type === 'color' || isColorProperty(binding.property)) {\n return (\n <ColorPickerField\n value={normalizeToHex(stringValue)}\n onChange={onChange}\n />\n );\n }\n\n if (binding.type === 'date') {\n return (\n <div>\n <DatePicker\n value={parseDateValue(stringValue)}\n onChange={date => {\n const next = date ? formatDateValue(date) : '';\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n if (next !== value) {\n onChange(next);\n }\n }}\n />\n {validationError && (\n <p className=\"mt-1 text-xs text-red-500\">{validationError}</p>\n )}\n </div>\n );\n }\n\n if (binding.type === 'url') {\n return (\n <div>\n <Input\n type=\"url\"\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"https://example.com\"\n onBlur={e => {\n const next = e.target.value.trim();\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n if (next !== value) {\n onChange(next);\n }\n }}\n />\n {validationError && (\n <p className=\"mt-1 text-xs text-red-500\">{validationError}</p>\n )}\n </div>\n );\n }\n\n // Checks `type` too, not just `widget`: a `type: 'icon-picker'` binding\n // parsed by `parseBinding` is already normalized to `widget: 'icon-picker'`\n // (see #236), but a hand-constructed BindingItem — e.g. the nested\n // render-leaf case just above, which doesn't carry `widget` — can still\n // arrive with the alias directly in `type`.\n if (binding.widget === 'icon-picker' || binding.type === 'icon-picker') {\n const SelectedIcon = ICON_MAP[stringValue];\n\n return (\n <div className=\"flex items-center gap-2\">\n <Select\n value={stringValue}\n options={ICON_OPTIONS}\n onChange={next => {\n if (next !== value) {\n onChange(next);\n }\n }}\n />\n {SelectedIcon && <SelectedIcon size={18} className=\"shrink-0\" />}\n </div>\n );\n }\n\n if (binding.widget === 'asset-picker' || binding.type === 'asset-picker') {\n const defaultUploadValue: UploadFile[] = stringValue\n ? [\n {\n uid: 'current',\n name: stringValue.split('/').pop() || 'asset',\n url: stringValue,\n },\n ]\n : [];\n\n return (\n <div className=\"space-y-2\">\n <Input\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"Enter an image URL\"\n onBlur={e => {\n const next = e.target.value.trim();\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n if (next !== value) {\n onChange(next);\n }\n }}\n />\n <Upload\n multiple={false}\n maxCount={1}\n accept=\"image/*\"\n defaultValue={defaultUploadValue}\n onChange={files => {\n const next = files[0]?.url ?? '';\n\n if (next !== value) {\n onChange(next);\n }\n }}\n />\n {validationError && (\n <p className=\"mt-1 text-xs text-red-500\">{validationError}</p>\n )}\n </div>\n );\n }\n\n if (binding.type === 'number' || typeof value === 'number') {\n return (\n <div>\n <Input\n type=\"number\"\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"Enter a numeric value\"\n onBlur={e => {\n const raw = e.target.value.trim();\n // Commit a real number, not a numeric string — the AST boundary\n // and `validateBindingValue` (its `min`/`max`) both expect the\n // value as its declared type now. An unparseable entry falls\n // back to the raw text so a genuine mistake still round-trips\n // rather than becoming `NaN`.\n const next: unknown =\n raw !== '' && !Number.isNaN(Number(raw)) ? Number(raw) : raw;\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n if (next !== value) {\n onChange(next);\n }\n }}\n />\n {validationError && (\n <p className=\"mt-1 text-xs text-red-500\">{validationError}</p>\n )}\n </div>\n );\n }\n\n return (\n <div>\n <Input.TextArea\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"Enter a value\"\n onBlur={e => {\n const raw = e.target.value.trim();\n // Untyped field: infer the value's type from the text the user\n // entered (so `42` commits as a number), the way the old boundary\n // did — but here, in the presentation layer, not by re-guessing in\n // the AST pipeline. A declared string-family type keeps the text\n // verbatim, so `\"{x}\"` stays a string.\n const next: unknown = binding.type ? raw : parseValue(raw);\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n if (next !== rawValue) {\n onChange(next);\n }\n }}\n />\n {validationError && (\n <p className=\"mt-1 text-xs text-red-500\">{validationError}</p>\n )}\n </div>\n );\n};\n\nexport default Field;\n","import type { PanelBinding, PanelNodeChange } from '../dnd';\nimport Field from './field';\n\ninterface Props {\n bindings: PanelBinding[];\n onNodeChange?: PanelNodeChange;\n}\n\n// One bordered group per element `id` — the same visual grouping `Node`\n// (panel/node.tsx) renders, but for the top-level panel list, where\n// `bindings` are already resolved PanelBindings (see dnd.tsx's `bindings`\n// useMemo). `Node` stays a separate component: it still parses a raw\n// DataAttrNode itself, which `Items` needs for elements it discovers\n// dynamically inside an array item's `children` (not present in the\n// top-level `bindings` array at all) — see #237's items/children boundary.\nconst FieldGroup = ({ bindings, onNodeChange }: Props) => (\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {bindings.map(binding => (\n <div key={binding.label} className=\"space-y-1\">\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">({binding.property})</span>\n </label>\n <Field binding={binding} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n </div>\n);\n\nexport default FieldGroup;\n","import { Button, Typography } from '@jbpark/ui-kit';\nimport { ChevronDown, ChevronUp, Trash } from 'lucide-react';\n\nimport type { Section } from '~/types';\nimport { cn } from '~/utils';\n\nimport type { PanelBinding, PanelNodeChange } from '../dnd';\nimport FieldGroup from './field-group';\n\n// The built-in property panel. Reached publicly as `Live.Dnd.Panel`, which\n// is this in the container the desktop pane wants, driven from\n// `useDndPanel()` — every field here lines up with what that hook returns\n// (drop `onChange`, which this panel never needed), so the built-in panel and\n// a custom one run on the same data and the public surface can't drift into a\n// subset of it (#237).\n//\n// `onNodeChange` is the node-level escape hatch `Items`/`Children` use to\n// commit a *different* element's edit than any single\n// `PanelBinding.onChange` can express (see field.tsx's items/children\n// boundary note from step 1). Optional here only so this can be rendered\n// read-only for nested edits; leave it out with real data and nested\n// array/children edits silently don't commit (#308).\nexport interface PanelProps {\n item?: Section;\n onDelete?: (id: string) => void;\n // Reordering by dragging a section on the canvas doesn't work from\n // inside this panel on mobile — the canvas sits behind the Drawer this\n // panel renders in, so there's nothing visible to drag onto. These give\n // an explicit alternative that works regardless of layout.\n onMoveUp?: () => void;\n onMoveDown?: () => void;\n canMoveUp?: boolean;\n canMoveDown?: boolean;\n // `item`'s editable fields, already resolved to PanelBindings by Dnd —\n // the same data a custom panel receives, so this panel doesn't re-derive\n // it from DataAttrNode a second time (#237).\n bindings: PanelBinding[];\n onNodeChange?: PanelNodeChange;\n}\n\n// `bindings` is flat (one entry per bound property, across every editable\n// element in the section) — regroup by `id` to render the same \"one\n// bordered box per element\" layout as before. `bindings` is already\n// ordered element-by-element, property-by-property (dnd.tsx builds it by\n// flat-mapping the extracted fields), so a Map preserves both the element\n// order and each element's own property order with no extra sorting.\n//\n// Not memoized: Dnd rebinds `bindings` every render so its commit callbacks\n// can't go stale against the document (#336), which means a dependency on\n// it would miss every time. This is a single pass over an already-parsed\n// list, so the miss costs more than the walk.\nconst groupBindingsById = (bindings: PanelBinding[]): PanelBinding[][] => {\n const groups = new Map<string, PanelBinding[]>();\n\n for (const binding of bindings) {\n const group = groups.get(binding.id);\n\n if (group) {\n group.push(binding);\n } else {\n groups.set(binding.id, [binding]);\n }\n }\n\n return [...groups.values()];\n};\n\nconst Panel = ({\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp = false,\n canMoveDown = false,\n bindings,\n onNodeChange,\n}: PanelProps) => {\n const groups = groupBindingsById(bindings);\n\n if (!item) {\n return (\n <Typography.Paragraph\n className={cn(\n 'p-4 text-sm text-gray-500',\n //\n )}\n >\n Please select a section.\n </Typography.Paragraph>\n );\n }\n\n return (\n <div\n className={cn(\n 'h-full space-y-4 p-4',\n 'overflow-x-hidden overflow-y-auto',\n //\n )}\n >\n <div className=\"flex items-center justify-between\">\n <Typography.Title className=\"text-lg font-semibold\">\n {item.name}\n </Typography.Title>\n <div className=\"flex items-center gap-1\">\n {onMoveUp && (\n <Button\n icon={<ChevronUp />}\n disabled={!canMoveUp}\n onClick={onMoveUp}\n aria-label=\"Move section up\"\n />\n )}\n {onMoveDown && (\n <Button\n icon={<ChevronDown />}\n disabled={!canMoveDown}\n onClick={onMoveDown}\n aria-label=\"Move section down\"\n />\n )}\n {onDelete && (\n <Button\n danger\n icon={<Trash />}\n onClick={() => onDelete(item.id)}\n aria-label=\"Delete section\"\n />\n )}\n </div>\n </div>\n {!groups.length && (\n <Typography.Text className=\"text-xs text-gray-400\">\n No editable elements.\n </Typography.Text>\n )}\n {groups.map(group => (\n <FieldGroup\n key={group[0]!.id}\n bindings={group}\n onNodeChange={onNodeChange}\n />\n ))}\n </div>\n );\n};\n\nexport default Panel;\n","import { Button, Drawer, Space, Splitter } from '@jbpark/ui-kit';\nimport { LayoutGrid } from 'lucide-react';\n\nimport { cn } from '~/utils';\n\nimport { DefaultDraggableItem } from './draggable';\nimport { useDndRegions } from './layout-context';\nimport PropertyPanel from './panel';\n\n// The regions take their content from context, so `children` is never a\n// consumer's to pass — everything else about the wrapper div is (className\n// is tailwind-merged over the defaults, so overriding one of them wins\n// rather than fighting).\nexport type DndRegionProps = Omit<\n React.ComponentPropsWithRef<'div'>,\n 'children'\n>;\n\n// The built-in palette and panel without their region wrapper. Both exist\n// because `Layout` renders them twice on mobile — once in a pane, once in a\n// Drawer that's already the scroll container and shouldn't inherit the\n// pane's background.\nconst PaletteItems = ({ subject }: { subject: string }) => {\n const {\n palette: { items, onAdd },\n isMobile,\n } = useDndRegions(subject);\n\n return (\n <Space orientation=\"vertical\" align=\"start\">\n {items.map(item => (\n <DefaultDraggableItem\n key={item.id}\n item={item}\n onAdd={onAdd}\n tapToAdd={isMobile}\n />\n ))}\n </Space>\n );\n};\n\nconst PanelFields = ({ subject }: { subject: string }) => {\n const {\n panel: {\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp,\n canMoveDown,\n bindings,\n onNodeChange,\n },\n } = useDndRegions(subject);\n\n return (\n <PropertyPanel\n item={item}\n onDelete={onDelete}\n onMoveUp={onMoveUp}\n onMoveDown={onMoveDown}\n canMoveUp={canMoveUp}\n canMoveDown={canMoveDown}\n bindings={bindings}\n onNodeChange={onNodeChange}\n />\n );\n};\n\n// The built-in palette, in the scroll container the desktop pane wants.\n// Replace it by putting your own component in `Layout`'s `palette` slot, or\n// anywhere in `Live.Dnd`'s children — `useDndPalette()` hands over the same\n// items and `onAdd` this reads.\nexport const Palette = ({ className, ...restProps }: DndRegionProps) => (\n <div\n className={cn(\n 'h-full overflow-y-auto bg-gray-50 p-4',\n className,\n //\n )}\n {...restProps}\n >\n <PaletteItems subject=\"<Live.Dnd.Palette>\" />\n </div>\n);\n\n// Owns the scroll container each section's iframe resolves by\n// `closest('[data-frame-container]')` to size itself against (see\n// frame/iframe.tsx), plus the containment/isolation styles that keep a\n// section's compiled CSS out of the editor chrome — hence a region rather\n// than a plain slot: a custom layout can move it, not lose it. Needs a\n// height-constrained parent, since it fills one (`h-full`). Render it\n// exactly once — the droppable and the sortable list inside use fixed ids,\n// and a second instance would duplicate both.\nexport const Canvas = ({ className, style, ...restProps }: DndRegionProps) => {\n const { canvas } = useDndRegions('<Live.Dnd.Canvas>');\n\n return (\n <div\n className={cn(\n 'relative h-full w-full overflow-y-auto',\n className,\n //\n )}\n data-frame-container\n style={{\n isolation: 'isolate',\n contain: 'layout style',\n transform: 'translateZ(0)',\n ...style,\n }}\n {...restProps}\n >\n {canvas}\n </div>\n );\n};\n\n// The built-in property panel. Same deal as `Palette`: replace it via\n// `Layout`'s `panel` slot or by placing your own component in `Live.Dnd`'s\n// children, driving it from `useDndPanel()`.\nexport const Panel = ({ className, ...restProps }: DndRegionProps) => (\n <div\n className={cn(\n 'h-full',\n className,\n //\n )}\n {...restProps}\n >\n <PanelFields subject=\"<Live.Dnd.Panel>\" />\n </div>\n);\n\nexport interface DndLayoutProps {\n // Replacements for the palette/panel regions, kept as slots so swapping\n // one out doesn't mean rebuilding the 3-pane Splitter and the mobile\n // Drawers around it. A slot is placed raw — it owns its own container,\n // unlike the built-in regions, which bring theirs. Drive it from\n // `useDndPalette()` / `useDndPanel()`.\n palette?: React.ReactNode;\n panel?: React.ReactNode;\n}\n\n// What `Live.Dnd` renders when given no children — the 3-pane desktop\n// Splitter, the stacked mobile canvas, and the mobile FAB/Drawers. Exported\n// so children can keep the built-in arrangement while wrapping it (a toolbar\n// above it, say) or while replacing just one region — and because\n// `@jbpark/ui-kit` is a dependency rather than a peer, so `Splitter` isn't\n// necessarily importable on the consumer's side.\nexport const Layout = ({ palette, panel }: DndLayoutProps) => {\n const { isMobile, selectedId, clearSelection, paletteOpen, setPaletteOpen } =\n useDndRegions('<Live.Dnd.Layout>');\n\n return (\n <>\n {isMobile ? (\n <Canvas />\n ) : (\n <Splitter withHandle orientation=\"horizontal\">\n <Splitter.Panel\n defaultSize=\"20%\"\n minSize=\"15%\"\n maxSize=\"35%\"\n collapsible\n >\n {palette ?? <Palette />}\n </Splitter.Panel>\n <Splitter.Panel defaultSize=\"60%\">\n <Canvas />\n </Splitter.Panel>\n <Splitter.Panel\n defaultSize=\"20%\"\n minSize=\"15%\"\n maxSize=\"35%\"\n collapsible\n >\n {panel ?? <Panel />}\n </Splitter.Panel>\n </Splitter>\n )}\n <Button\n type=\"primary\"\n shape=\"circle\"\n icon={<LayoutGrid />}\n aria-label=\"Components\"\n className=\"fixed right-4 bottom-4 z-20 md:hidden\"\n onClick={() => setPaletteOpen(true)}\n />\n {/* A slot goes in as-is; the built-ins go in without their region\n wrapper, since the Drawer is already the scroll container and the\n palette's gray background belongs to the desktop pane. */}\n <Drawer\n open={isMobile && paletteOpen}\n onClose={() => setPaletteOpen(false)}\n direction=\"bottom\"\n size=\"large\"\n title=\"Components\"\n >\n {palette ?? <PaletteItems subject=\"<Live.Dnd.Layout>\" />}\n </Drawer>\n <Drawer\n open={isMobile && Boolean(selectedId)}\n onClose={clearSelection}\n direction=\"bottom\"\n size=\"large\"\n title=\"Properties\"\n >\n {panel ?? <PanelFields subject=\"<Live.Dnd.Layout>\" />}\n </Drawer>\n </>\n );\n};\n\nexport default Layout;\n","import { memo } from 'react';\n\nimport ErrorBoundary from '~/components/error/boundary';\nimport LiveError from '~/components/error/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { useCompiledModule } from '~/components/preview/use-compiled-module';\nimport { useDynamicTailwind } from '~/components/preview/use-dynamic-tailwind';\n\ninterface Props {\n preview: string;\n modules?: Record<string, unknown>;\n headers?: Record<string, boolean>;\n frame?: FrameProps;\n dynamicTailwind?: boolean;\n provider?: (children: React.ReactNode) => React.ReactNode;\n}\n\n// Wrapped in memo() because `preview` is a plain string: for a section that\n// didn't change, the parent hands back the same content it computed last\n// render (see generateSections()/dnd.tsx), so a shallow prop comparison\n// lets React skip both the recompile below and reconciling this section's\n// iframe tree at all — see #97.\nconst Renderer = ({\n preview,\n headers,\n modules,\n frame,\n dynamicTailwind = false,\n provider,\n}: Props) => {\n const module = useCompiledModule(preview, modules);\n\n // In `shadow` mode there's no separate document to load a stylesheet into\n // — the shadow root only gets whatever CSS naturally inherits across the\n // boundary (see `frame/shadow.tsx`), not utility classes. So this section's\n // own Tailwind classes are compiled and portalled in as a `<style>` tag\n // alongside the rendered content, which crosses the shadow boundary fine\n // since it lives inside the same portal target.\n const { ref: wrapperRef, css: dynamicCSS } = useDynamicTailwind(\n preview,\n dynamicTailwind,\n );\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\n };\n\n // Rendered in place of the frame rather than inside it: there is nothing to\n // portal into an iframe for code that never produced a component, and a\n // silent blank slot (the previous behaviour) gives the author no clue why\n // their section vanished. Mirrors preview/client.tsx's compile-error branch.\n if (module?.error) {\n return <LiveError message={module.error} title=\"Compile Error\" />;\n }\n\n const Component = module?.exports?.default;\n\n if (!Component) {\n return null;\n }\n\n return (\n <Frame {...frame} autoHeight>\n {container => (\n <div\n ref={wrapperRef}\n className=\"w-full overflow-x-hidden\"\n data-editor-mode\n >\n {/*\n Without this, a render error in any single canvas section\n propagated past Dnd and unmounted the whole editor — palette,\n canvas and panel — while the same error in <Preview> was caught\n and displayed (see #246). Kept inside the frame so the failure is\n reported in the slot the broken section occupies, and so a\n transient error while the author is mid-edit doesn't tear down and\n rebuild the iframe (script loading, style sync, resize observers)\n on every keystroke. `Error` is inline-styled, so it stays readable\n even in a frame that never received the host's CSS.\n\n resetKeys={[preview]} makes the fix itself the recovery signal: the\n next edit to this section produces a new preview string, which\n clears the caught error without needing a remount.\n\n No `Error.Guard` here, unlike client.tsx: it listens on `window`,\n not on its subtree, so one per section would mean N global\n listeners all tripping on any single error — every section would\n show a runtime error regardless of which one actually threw.\n\n Errors also stay local rather than going to ErrorContext, whose\n `error` is a single string shared by the whole tree: N sections\n reporting into it would overwrite each other with no way to tell\n which section failed.\n */}\n <ErrorBoundary resetKeys={[preview]}>\n {renderProvider(\n <>\n <Component\n headers={headers}\n container={container}\n //\n />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </>,\n )}\n </ErrorBoundary>\n </div>\n )}\n </Frame>\n );\n};\n\nexport default memo(Renderer);\n","import { useSortable } from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport { Button, Space } from '@jbpark/ui-kit';\nimport { Copy, Trash } from 'lucide-react';\n\nimport { cn } from '~/utils';\n\ninterface Props {\n id: string;\n name?: string;\n children: React.ReactNode;\n selected?: boolean;\n onClick?: () => void;\n onDelete?: (id: string) => void;\n onCopy?: (id: string) => void;\n}\n\nconst Sortable = ({\n id,\n children,\n selected,\n onClick,\n onDelete: _onDelete,\n onCopy: _onCopy,\n}: Props) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n isOver,\n active,\n } = useSortable({ id });\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n opacity: isDragging ? 0.5 : 1,\n cursor: 'grab',\n };\n\n const isNewItemOver = isOver && active?.data.current?.type === 'new-item';\n\n const onDelete = (e: React.MouseEvent) => {\n e.stopPropagation();\n _onDelete?.(id);\n };\n\n const onCopy = (e: React.MouseEvent) => {\n e.stopPropagation();\n _onCopy?.(id);\n };\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n {...attributes}\n {...listeners}\n onClick={onClick}\n className={cn(\n 'relative',\n selected && 'z-10 outline-2 outline-offset-2 outline-blue-500',\n isNewItemOver && 'border-t-4 border-t-green-500',\n //\n )}\n >\n <div\n className={cn(\n 'absolute inset-0 z-50',\n //\n )}\n />\n {children}\n {selected && (\n <Space\n className={cn(\n 'absolute top-1 right-1 z-60',\n //\n )}\n >\n <Button icon={<Copy />} onClick={onCopy} />\n <Button danger icon={<Trash />} onClick={onDelete} />\n </Space>\n )}\n </div>\n );\n};\n\nexport default Sortable;\n","import { useDndContext } from '@dnd-kit/core';\n\nimport type { FrameProps } from '~/components/frame';\nimport type { Section } from '~/types';\nimport { generateSection } from '~/utils';\n\nimport { DefaultDraggableItem } from './draggable';\nimport Renderer from './renderer';\nimport Sortable from './sortable';\n\ninterface Props {\n sections: Section[];\n renderProps: {\n fullCode: string;\n modules: Record<string, unknown>;\n frame?: FrameProps;\n dynamicTailwind?: boolean;\n };\n}\n\nconst Overlay = ({ sections, renderProps }: Props) => {\n const { active } = useDndContext();\n\n if (!active) {\n return null;\n }\n\n if (active.data.current?.type === 'new-item') {\n const item = active.data.current.item;\n\n return <DefaultDraggableItem item={item} />;\n }\n\n const section = sections.find(s => s.id === active.id);\n\n if (section) {\n const preview = generateSection(section.code, renderProps.fullCode);\n\n return (\n <Sortable id={section.id} name={section.name}>\n <Renderer\n preview={preview}\n modules={renderProps.modules}\n frame={renderProps.frame}\n dynamicTailwind={renderProps.dynamicTailwind}\n />\n </Sortable>\n );\n }\n\n return null;\n};\n\nexport default Overlay;\n","import { useCallback, useMemo, useState } from 'react';\n\nimport { arrayMove } from '@dnd-kit/sortable';\n\nimport type { Section } from '~/types';\nimport {\n createSectionPreviewCache,\n extractSections,\n replaceSections,\n} from '~/utils';\nimport { fillSectionIds, replaceIds } from '~/utils/ast';\n\nimport { usePreview } from '../context/states';\n\nexport interface SectionDocument {\n sections: Section[];\n previews: string[];\n selectedId: string | null;\n selectedItem?: Section;\n selectedIndex: number;\n select: (id: string) => void;\n clearSelection: () => void;\n add: (item: Pick<Section, 'name' | 'code'>, atIndex?: number) => void;\n remove: (id: string) => void;\n copy: (id: string) => void;\n move: (id: string | null, direction: 'up' | 'down') => void;\n reorder: (activeId: string, overId: string) => void;\n patch: (next: Partial<Section> & { id: string }) => void;\n}\n\n// Owns the document side of the DnD canvas: deriving sections from the code\n// string, tracking which one is selected, and committing every mutation.\n//\n// Extracted from Dnd (#245), where the commit sequence\n// `replaceSections -> onChange -> setCode` was spelled out seven separate\n// times. Naming it once means no mutation can perform half of it, and it\n// puts the section logic somewhere reachable without rendering dnd-kit.\nexport const useSectionDocument = (\n value: string,\n onChange?: (value: string) => void,\n): SectionDocument => {\n const { setCode } = usePreview();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n // Sections identify themselves by `data-id`; `getSections` falls back to a\n // positional id for documents predating that (see #245). Filling the gap\n // here makes the ids below real identities rather than positions, so a\n // held `selectedId` survives an insert, copy, move or delete.\n //\n // Deliberately not committed on its own — like dnd.tsx's existing use of\n // fillIds for field ids, the filled document only reaches\n // `onChange`/`setCode` when a real mutation commits, so merely opening a\n // document never rewrites the author's code.\n const document = useMemo(() => fillSectionIds(value), [value]);\n const sections = useMemo(() => extractSections(document), [document]);\n\n // One cache per hook instance (lazy `useState` initializer, never\n // replaced) — see createSectionPreviewCache (#131). It's stateful by\n // design (remembers the previous render's previews to reuse the ones that\n // didn't change), which a `useMemo`/`useRef` can't do without touching a\n // ref during render; a cache object stored via `useState` and only ever\n // mutated through its own method isn't subject to that restriction the way\n // `ref.current` is.\n const [previewCache] = useState(() => createSectionPreviewCache());\n const previews = useMemo(\n () => previewCache.compute(document, sections),\n [previewCache, sections, document],\n );\n\n const selectedIndex = sections.findIndex(s => s.id === selectedId);\n const selectedItem = selectedIndex >= 0 ? sections[selectedIndex] : undefined;\n\n // The single place a set of sections becomes a new document. Takes only\n // `code` because that is genuinely all a commit reads — ids and names are\n // re-derived from the result, never carried across.\n //\n // Runs `fillSectionIds` on the way out so a section that arrived without\n // one still lands with an id: a palette template is a bare `<section>`\n // snippet with no `#app-container`, so it cannot be filled until after\n // it's spliced in. Returns the resulting sections so a caller that needs\n // to select what it just created can read the real id back rather than\n // inventing one.\n const commit = useCallback(\n (nextSections: { code: string }[]): Section[] => {\n const nextCode = fillSectionIds(\n replaceSections(\n document,\n nextSections.map(s => s.code),\n ),\n );\n\n onChange?.(nextCode);\n setCode(nextCode);\n\n return extractSections(nextCode);\n },\n [document, onChange, setCode],\n );\n\n const select = useCallback((id: string) => {\n setSelectedId(prev => (prev === id ? null : id));\n }, []);\n\n const clearSelection = useCallback(() => setSelectedId(null), []);\n\n const add = useCallback(\n (item: Pick<Section, 'name' | 'code'>, atIndex?: number) => {\n const next = { code: item.code };\n\n commit(\n atIndex === undefined || atIndex < 0\n ? [...sections, next]\n : [...sections.slice(0, atIndex), next, ...sections.slice(atIndex)],\n );\n },\n [commit, sections],\n );\n\n const remove = useCallback(\n (id: string) => {\n // Removes by position, not by predicate: `fillSectionIds` keeps ids\n // unique, but a filter would delete every match if that invariant ever\n // slipped — and this is the one destructive operation here, so it\n // shouldn't be the one relying on it.\n const index = sections.findIndex(s => s.id === id);\n\n if (index < 0) {\n return;\n }\n\n // Only the deleted section loses the selection. The previous\n // implementation cleared it unconditionally, so deleting any section\n // closed the panel for whichever one was open.\n if (id === selectedId) {\n setSelectedId(null);\n }\n\n commit(sections.filter((_, i) => i !== index));\n },\n [commit, sections, selectedId],\n );\n\n const copy = useCallback(\n (id: string) => {\n const index = sections.findIndex(s => s.id === id);\n const source = sections[index];\n\n if (!source) {\n return;\n }\n\n // replaceIds refreshes every data-id in the snippet, the section's own\n // included, so the copy carries a distinct identity into the document.\n const committed = commit([\n ...sections.slice(0, index + 1),\n { code: replaceIds(source.code) },\n ...sections.slice(index + 1),\n ]);\n\n // Read the new id back from the committed document. This used to\n // select a `uuidv4()` that was never written into the code and so\n // didn't exist after the next parse, leaving the panel empty right\n // after a copy (#245).\n setSelectedId(committed[index + 1]?.id ?? null);\n },\n [commit, sections],\n );\n\n const move = useCallback(\n (id: string | null, direction: 'up' | 'down') => {\n const index = sections.findIndex(s => s.id === id);\n const targetIndex = direction === 'up' ? index - 1 : index + 1;\n\n if (index < 0 || targetIndex < 0 || targetIndex >= sections.length) {\n return;\n }\n\n // No `setSelectedId` compensation needed any more: the id travels with\n // the section's own markup, so the selection follows it across a move.\n commit(arrayMove(sections, index, targetIndex));\n },\n [commit, sections],\n );\n\n const reorder = useCallback(\n (activeId: string, overId: string) => {\n const prevIndex = sections.findIndex(s => s.id === activeId);\n const nextIndex = sections.findIndex(s => s.id === overId);\n\n if (prevIndex < 0 || nextIndex < 0 || prevIndex === nextIndex) {\n return;\n }\n\n commit(arrayMove(sections, prevIndex, nextIndex));\n },\n [commit, sections],\n );\n\n const patch = useCallback(\n (next: Partial<Section> & { id: string }) => {\n commit(sections.map(s => (s.id === next.id ? { ...s, ...next } : s)));\n },\n [commit, sections],\n );\n\n return {\n sections,\n previews,\n selectedId,\n selectedItem,\n selectedIndex,\n select,\n clearSelection,\n add,\n remove,\n copy,\n move,\n reorder,\n patch,\n };\n};\n","import { Children, useEffect, useMemo, useState } from 'react';\n\nimport {\n DndContext,\n type DragEndEvent,\n type DragOverEvent,\n DragOverlay,\n type DragStartEvent,\n type Modifier,\n PointerSensor,\n closestCenter,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport { restrictToVerticalAxis } from '@dnd-kit/modifiers';\nimport {\n SortableContext,\n verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { Space, Toast, Typography } from '@jbpark/ui-kit';\nimport { useResponsiveSize } from '@jbpark/use-hooks';\n\nimport { DRAGGABLE_ITEMS } from '~/constants';\nimport type { Section } from '~/types';\nimport {\n type BindingOption,\n type BindingRenderMap,\n type BindingType,\n type DataAttrNode,\n extract,\n fillIds,\n getCurrentValue,\n getStructuredValue,\n parseBinding,\n update,\n} from '~/utils/ast';\nimport type { UpdateFailure } from '~/utils/ast';\n\nimport { DEFAULT_TEMPLATE } from '../../constants';\nimport { cn, preloadScripts } from '../../utils';\nimport { usePreview } from '../context/states';\nimport { type FrameProps } from '../frame';\nimport Droppable from './droppable';\nimport Layout from './layout';\nimport { DndRegionContext } from './layout-context';\nimport Overlay from './overlay';\nimport Renderer from './renderer';\nimport Sortable from './sortable';\nimport { useSectionDocument } from './use-section-document';\n\n// Turn a structured `update` failure into a toast that names the actual\n// fault. Before #270 every failure showed \"Failed to update this field /\n// Check the console for details\" — but nothing was logged, so the console\n// was empty. Most of these are a wrong `property`/`label` in the element's\n// `data-binding`, not the value the author just typed, so the message points\n// there. `description` is only set for paths that genuinely log (parse\n// errors), so \"check the console\" is never a dead end again.\nconst describeUpdateFailure = (\n failure: UpdateFailure | undefined,\n label: string,\n): { title: string; description?: string } => {\n switch (failure?.reason) {\n case 'attribute-not-found':\n return {\n title: `Failed to update \"${label}\"`,\n description: `This element has no \"${failure.property}\" attribute — check the property in its data-binding.`,\n };\n case 'binding-not-declared':\n return {\n title: `Failed to update \"${label}\"`,\n description: `No binding for ${\n failure.property\n ? `property \"${failure.property}\"`\n : `label \"${label}\"`\n } is declared on this element's data-binding.`,\n };\n case 'duplicate-binding':\n return {\n title: `Failed to update \"${label}\"`,\n description: `${failure.count} bindings share ${\n failure.property\n ? `property \"${failure.property}\"`\n : `label \"${label}\"`\n } on this element — remove the duplicate in its data-binding.`,\n };\n case 'no-binding':\n return {\n title: `Failed to update \"${label}\"`,\n description: 'This element has no data-binding declaration.',\n };\n case 'element-not-found':\n return {\n title: `Failed to update \"${label}\"`,\n description: 'The target element could not be found in this section.',\n };\n case 'parse-error':\n return {\n title: `Failed to update \"${label}\"`,\n description:\n failure.error instanceof Error\n ? failure.error.message\n : 'Check the console for details.',\n };\n default:\n return { title: `Failed to update \"${label}\"` };\n }\n};\n\n// What `useDndPalette()` returns. Deliberately just data: the drag wiring is\n// a component (`Live.Dnd.DraggableItem`) and the breakpoint belongs to\n// `useDndLayout()`, so a custom palette takes each from where it lives\n// rather than having all three funnelled through one object.\nexport interface DndPalette {\n items: Section[];\n // Appends the item to the canvas. Closes the mobile palette Drawer too,\n // which is a no-op wherever it isn't open.\n onAdd: (item: Section) => void;\n}\n\n// The node-level commit callback's shape, named because it's part of the\n// public surface in two places (`DndPanel`, `Field`) and was previously\n// spelled out inline in each — see #308.\nexport interface PanelNodeChange {\n (params: {\n id: string;\n label: string;\n property: string;\n value: unknown;\n }): void;\n}\n\n// What `useDndPanel()` returns — everything the built-in property panel runs\n// on, so a custom panel starts from the same place rather than re-deriving\n// any of it.\nexport interface DndPanel {\n item?: Section;\n onChange: (next: Partial<Section>) => void;\n onDelete: (id: string) => void;\n // Alternative to dragging a section to reorder it — needed since the\n // canvas sits behind the mobile Drawer the panel renders in, so\n // there's nothing visible to drag onto there.\n onMoveUp: () => void;\n onMoveDown: () => void;\n canMoveUp: boolean;\n canMoveDown: boolean;\n // `item`'s editable data-binding fields, already flattened to one entry\n // per bound property (across every non-<section> descendant carrying a\n // `data-binding` attribute). Each entry carries the binding's `type` and\n // current `value` plus an `onChange` wired straight into the same\n // AST-update pipeline the built-in panel uses — including the error Toast\n // on a bad edit. Switch on `type` to render your own control (an\n // `<input>`, `<textarea>`, `<select>`, ...) instead of the built-in one.\n bindings: PanelBinding[];\n // Node-level commit for elements that aren't in `bindings` — the nested\n // data-bound JSX held inside an `items`/`children` value, which the\n // built-in Items/Children editors discover by re-extracting that value's\n // own JSX. Those `data-id`s never reach `bindings` (the top-level\n // `extract()` doesn't walk into an attribute expression), and no single\n // `PanelBinding.onChange` can address them since each one closes over a\n // fixed `id` — hence this `(id, label, property, value)` channel. Hand it\n // to `Live.Dnd.Field` along with the binding, otherwise nested\n // array/children edits inside it silently don't commit (#308).\n onNodeChange: PanelNodeChange;\n}\n\n// One editable data-binding, flattened out of the selected section for a\n// custom panel. Exposes just what a consumer needs to render its own\n// control — the declared `type`, the current `value`, and an `onChange`\n// that commits through Dnd's AST-update pipeline — so it never has to touch\n// DataAttrNode/parseBinding/getCurrentValue itself.\nexport interface PanelBinding {\n // `data-id` of the owning element — stable across edits.\n id: string;\n // Human-readable label from the binding definition.\n label: string;\n // The bound prop/attribute name (e.g. `children`, `src`, `color`).\n property: string;\n // The declared data-binding type — switch on this to pick a control\n // (`string`/`url` -> <input>, `jsx`/`richtext` -> <textarea>, `boolean`\n // -> checkbox, ...). `undefined` means a plain string binding.\n type?: BindingType;\n // Presentation, as opposed to `type`'s data kind — an open string, not a\n // closed enum, since a custom panel can declare any widget it wants\n // (e.g. `'slider'`) and switch on it itself. The built-in panel\n // only recognizes `'icon-picker'`/`'asset-picker'`; anything else falls\n // back to the `type`-appropriate default control. See #236.\n widget?: string;\n // Present when the binding defines a fixed option set (render a <select>).\n options?: BindingOption[];\n // Present for `object`/`array` bindings whose nested keys/items declare\n // their own types — the same map the built-in panel uses to type each\n // nested field instead of falling back to a plain string input.\n render?: BindingRenderMap;\n // Constraints declared on the binding. `min`/`max` compare against the\n // real number `value` delivers for `type: 'number'` bindings (see\n // `validateBindingValue`).\n min?: number;\n max?: number;\n pattern?: string;\n required?: boolean;\n // Consumer-defined keys carried straight through from the authored\n // data-binding — namespaced instead of spread onto PanelBinding so they\n // can't collide with a future first-class field. Absent when nothing\n // extra was authored. See #234.\n meta?: Record<string, unknown>;\n // Current value as its real JS type — a number for `type: 'number'`, a\n // boolean for `type: 'boolean'`, an object/array for `object`/`array`,\n // a string otherwise. Switch on this without re-parsing. See #238.\n value: unknown;\n // The exact source text behind `value`, for cases that can't round-trip\n // through a JS value — `jsx`/`richtext` bindings, or an attribute whose\n // source is an expression you want to edit as text.\n rawValue: string;\n // Commit a new value through the same AST-update pipeline the built-in\n // panel uses (including the error Toast on a bad edit). Pass the value as\n // its real type; it's serialized once, at the AST boundary, where the\n // declared `type` is known — so no string quoting/guessing on your side.\n onChange: (value: unknown) => void;\n}\n\nexport interface Props extends Omit<\n React.ComponentPropsWithRef<'div'>,\n 'onChange'\n> {\n value?: string;\n props?: Record<string, unknown>;\n modules?: Record<string, unknown>;\n items?: Section[];\n frame?: FrameProps;\n dynamicTailwind?: boolean;\n provider?: (children: React.ReactNode) => React.ReactNode;\n onChange?: (value: string) => void;\n // The single customization slot. Omit it for the built-in editor. Supply\n // it and you own the arrangement: compose `Live.Dnd.Palette` /\n // `Live.Dnd.Canvas` / `Live.Dnd.Panel` (each the built-in region, in the\n // container it needs) and your own components in any structure you like.\n // The drag context wraps all of it, so drag-and-drop and field editing\n // keep working wherever a region lands. Your components read the same data\n // the built-ins do through `useDndPalette()` / `useDndPanel()` /\n // `useDndLayout()`.\n //\n // Note this replaces the mobile chrome too — the FAB and both Drawers live\n // in `Live.Dnd.Layout`, which is what runs when children are omitted.\n // Render it yourself (`<Live.Dnd.Layout panel={<MyPanel />} />`) to keep\n // the built-in arrangement while swapping one region. Render `Canvas` at\n // most once either way.\n children?: React.ReactNode;\n}\n\nconst conditionalModifiers: Modifier = args => {\n const { active } = args;\n\n if (active?.data.current?.type === 'new-item') {\n return args.transform;\n }\n\n return restrictToVerticalAxis(args);\n};\n\nconst Dnd = ({\n value: _value,\n props,\n modules = {},\n onChange: _onChange,\n className,\n items = [],\n frame,\n dynamicTailwind = false,\n provider,\n children,\n ...restProps\n}: Props) => {\n const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);\n\n const { breakpoint } = useResponsiveSize();\n const isMobile = breakpoint.current === 'xs' || breakpoint.current === 'sm';\n\n // Read-only here — `useSectionDocument` below owns `setCode` (the commit\n // side). `code` is still needed locally: it feeds `value`'s fallback\n // chain just below, and `value` itself is read again further down for\n // the drag overlay's `fullCode` — not something `useSectionDocument`\n // exposes back out.\n const { code } = usePreview();\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 10,\n },\n }),\n );\n\n // Uncontrolled usage (`<Live.Dnd />` with no `value`) used to read\n // nothing but DEFAULT_TEMPLATE forever: every edit committed through\n // useSectionDocument writes into PreviewContext, but this component\n // never read `code` back — so the section a reader just dragged in\n // vanished on the very next render. `Client` (preview/client.tsx)\n // already resolves the same dual-source situation with `_code || code`;\n // mirrored here, with DEFAULT_TEMPLATE kept only as the final fallback\n // for the case neither is set (fresh, empty context) — see #244.\n const value = _value || code || DEFAULT_TEMPLATE;\n\n const {\n sections,\n previews,\n selectedId,\n selectedItem,\n selectedIndex,\n select,\n clearSelection,\n add: addItem,\n remove: onDelete,\n copy: onCopy,\n move: moveSection,\n reorder,\n patch,\n } = useSectionDocument(value, _onChange);\n\n const onDragStart = (_: DragStartEvent) => {};\n\n const onDragOver = (_e: DragOverEvent) => {};\n\n const onDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n\n if (!over) {\n return;\n }\n\n if (active.data.current?.type === 'new-item') {\n const item = active.data.current.item as Section;\n const atBottom =\n over.id === 'sortable-area' || over.id === 'sortable-area-bottom';\n\n addItem(\n item,\n atBottom ? undefined : sections.findIndex(s => s.id === over.id),\n );\n return;\n }\n\n if (active.id !== over.id && sections.some(s => s.id === active.id)) {\n reorder(String(active.id), String(over.id));\n }\n };\n\n const onSelect = (id: string) => select(id);\n\n const onChange = (next: Partial<Section>) => {\n if (!next.id) {\n return;\n }\n\n patch(next as Partial<Section> & { id: string });\n };\n\n // Reads only the extracted `code` local, not `selectedItem`, so the\n // compiler can verify this dependency array actually matches what the\n // body reads — matches Panel's own former version of this same logic,\n // now shared here so both the built-in Panel and a custom one built on\n // `useDndPanel()` get the same extraction/update pipeline instead of each\n // needing it.\n const selectedCode = selectedItem?.code;\n const { fields, updatedCode, parseError } = useMemo(() => {\n if (!selectedCode) {\n return {\n fields: [] as DataAttrNode[],\n updatedCode: '',\n parseError: false,\n };\n }\n\n try {\n const updated = fillIds(selectedCode);\n const allNodes = extract(updated);\n const filtered = allNodes.filter(node => node.tagName !== 'section');\n\n return {\n fields: filtered,\n updatedCode: updated !== selectedCode ? updated : selectedCode,\n parseError: false,\n };\n } catch (e) {\n console.warn('⚠️ Parsing error', e);\n return {\n fields: [] as DataAttrNode[],\n updatedCode: '',\n parseError: true,\n };\n }\n }, [selectedCode]);\n\n useEffect(() => {\n if (parseError) {\n Toast.error('Failed to parse this section', {\n description: 'Check the console for details.',\n });\n }\n }, [parseError]);\n\n const onFieldChange = ({\n id,\n label,\n property,\n value: fieldValue,\n }: {\n id: string;\n label: string;\n property: string;\n value: unknown;\n }) => {\n const result = update(updatedCode, id, label, fieldValue, property);\n\n if (!result.success) {\n const { title, description } = describeUpdateFailure(\n result.failure,\n label,\n );\n Toast.error(title, description ? { description } : undefined);\n return;\n }\n\n if (selectedItem) {\n onChange({ ...selectedItem, code: result.code });\n }\n };\n\n // Flattens the extracted `fields` (one DataAttrNode per element) down to\n // one descriptor per bound property — the same walk the built-in\n // FieldEditor/Node does internally (data-id + parsed data-binding +\n // current value). Everything here is derived from `fields` alone, so the\n // memo key is honest and the parse/read work still happens once per\n // parsed section.\n //\n // Deliberately no `onChange`: a callback belongs to the render that made\n // it, not to the parse. Keeping the two in one memo is what caused #336 —\n // editing another section leaves `selectedCode` (and therefore `fields`)\n // identical, so the memo was reused and handed back callbacks still bound\n // to the previous document, whose commit wrote the sibling's old source\n // back over the newer one.\n const bindingFields = useMemo(() => {\n return fields.flatMap(node => {\n const dataId = node.dataAttributes.find(a => a.name === 'data-id')?.value;\n const bindingAttr = node.dataAttributes.find(\n a => a.name === 'data-binding',\n )?.value;\n\n if (!dataId || !bindingAttr) {\n return [];\n }\n\n const parsed = node.bindings ?? parseBinding(bindingAttr);\n\n return parsed.map(binding => ({\n id: dataId,\n label: binding.label,\n property: binding.property,\n type: binding.type,\n widget: binding.widget,\n options: binding.options,\n render: binding.render,\n min: binding.min,\n max: binding.max,\n pattern: binding.pattern,\n required: binding.required,\n meta: binding.meta,\n value: getStructuredValue(node, binding.property, binding.type),\n rawValue: getCurrentValue(node, binding.property),\n }));\n });\n }, [fields]);\n\n // Bound fresh each render on top of the memo above — the same split\n // `useItemsEditor` uses for its `items`. This is a plain walk of an\n // already-parsed result with no Babel in it, and it's what guarantees a\n // commit reads the current `updatedCode`/`selectedItem`/`onChange`.\n //\n // The identity churn the previous memo was guarding against was never\n // real: the `DndRegionContext` value and the `panel` object holding this\n // array are both fresh object literals every render, so every\n // `useDndPanel()` consumer already re-rendered regardless.\n const bindings: PanelBinding[] = bindingFields.map(field => ({\n ...field,\n onChange: (value: unknown) =>\n onFieldChange({\n id: field.id,\n label: field.label,\n property: field.property,\n value,\n }),\n }));\n\n useEffect(() => {\n if (frame?.scripts?.length) {\n preloadScripts(frame.scripts);\n }\n }, [frame?.scripts]);\n\n // Data, not nodes: the built-in palette and panel read these back through\n // `useDndPalette()`/`useDndPanel()` exactly as a custom one does, so\n // there's a single path and no way for the public surface to drift into a\n // subset of what the built-ins use — the point of #237.\n const palette: DndPalette = {\n items: items?.length ? items : DRAGGABLE_ITEMS,\n onAdd: (item: Section) => {\n addItem(item);\n setMobilePaletteOpen(false);\n },\n };\n\n const panel: DndPanel = {\n item: selectedItem,\n onChange,\n onDelete,\n onMoveUp: () => moveSection(selectedId, 'up'),\n onMoveDown: () => moveSection(selectedId, 'down'),\n canMoveUp: selectedIndex > 0,\n canMoveDown: selectedIndex >= 0 && selectedIndex < sections.length - 1,\n bindings,\n onNodeChange: onFieldChange,\n };\n\n // Content only — the frame container that wraps this (`data-frame-container`\n // plus the containment styles) belongs to `Live.Dnd.Canvas`, so a custom\n // layout can't accidentally drop it while still placing the canvas.\n const canvas = (\n <>\n <Droppable\n className={cn(\n !sections.length && 'h-full',\n //\n )}\n >\n {!sections.length ? (\n <div\n className={cn(\n 'flex items-center justify-center',\n 'h-full',\n 'text-gray-500',\n )}\n >\n <Space orientation=\"vertical\" align=\"center\">\n <Typography.Paragraph>No sections available</Typography.Paragraph>\n <Typography.Text>\n {isMobile\n ? 'Tap a component to add it'\n : 'Drag a component from the left to add it'}\n </Typography.Text>\n </Space>\n </div>\n ) : (\n <SortableContext\n items={sections.map(s => s.id)}\n strategy={verticalListSortingStrategy}\n >\n {sections.map((section, index) => (\n <Sortable\n key={section.id}\n id={section.id}\n name={section.name}\n selected={selectedId === section.id}\n onClick={() => onSelect(section.id)}\n onDelete={onDelete}\n onCopy={onCopy}\n >\n <Renderer\n preview={previews[index]!}\n modules={modules}\n frame={frame}\n dynamicTailwind={dynamicTailwind}\n provider={provider}\n {...props}\n />\n </Sortable>\n ))}\n </SortableContext>\n )}\n </Droppable>\n </>\n );\n\n return (\n <>\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n modifiers={[\n conditionalModifiers,\n //\n ]}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n >\n <div\n className={cn(\n 'relative flex h-full w-full',\n className,\n //\n )}\n {...restProps}\n >\n {/* Not memoized: `palette`, `panel` and `canvas` are all rebuilt\n each render anyway, so a memo would only add a dependency list\n to keep in sync. */}\n <DndRegionContext.Provider\n value={{\n palette,\n panel,\n canvas,\n isMobile,\n selectedId,\n clearSelection,\n paletteOpen: mobilePaletteOpen,\n setPaletteOpen: setMobilePaletteOpen,\n }}\n >\n {/* `Children.toArray` rather than a plain `children ??`: a JSX\n comment, or a `{cond && <MyLayout />}` that fell through,\n leaves `children` set but empty — and honouring that\n literally renders an editor with no regions at all, which\n looks like a broken build rather than a mistake in the\n layout. Falling back keeps the failure legible. */}\n {Children.toArray(children).length ? children : <Layout />}\n </DndRegionContext.Provider>\n </div>\n <DragOverlay>\n <Overlay\n sections={sections}\n renderProps={{\n fullCode: value,\n modules,\n frame,\n dynamicTailwind,\n ...props,\n }}\n />\n </DragOverlay>\n </DndContext>\n </>\n );\n};\n\nexport default Dnd;\n","import DndImpl, {\n type DndPalette,\n type DndPanel,\n type PanelBinding,\n type PanelNodeChange,\n type Props,\n} from './dnd';\nimport DraggableItem, {\n type DraggableItemDragState,\n type DraggableItemProps,\n} from './draggable';\nimport {\n Canvas,\n type DndLayoutProps,\n type DndRegionProps,\n Layout,\n Palette,\n Panel,\n} from './layout';\nimport {\n type DndLayout,\n useDndLayout,\n useDndPalette,\n useDndPanel,\n} from './layout-context';\nimport Field, { type FieldProps } from './panel/field';\nimport { ICON_MAP, ICON_OPTIONS } from './panel/icon-map';\nimport {\n type ItemsEditor,\n type ItemsEditorActions,\n type ItemsEditorItem,\n type ItemsEditorNestedElement,\n type ItemsEditorNestedGroup,\n type ItemsEditorOptions,\n useItemsEditor,\n} from './panel/use-items-editor';\n\ntype DndComponent = typeof DndImpl & {\n // Owns the dnd-kit wiring for a palette item and hands back `ref` /\n // `dragProps` / `isDragging`, so a custom palette decides how an item\n // *looks* without reimplementing how dragging works.\n DraggableItem: typeof DraggableItem;\n // The built-in control for one binding, exported so a custom panel can mix\n // its own controls with the built-in one per binding rather than choosing\n // all-or-nothing. Takes a `PanelBinding` straight out of `bindings` plus\n // `onNodeChange` — both `useDndPanel()` fields, so nothing internal is\n // needed to drive it. Most useful for `items`/`children` bindings, whose\n // editors find nested data-bound elements a consumer can't reach through\n // `bindings`. Renders the control only — supply your own label.\n Field: typeof Field;\n // The three built-in regions, each in the container it needs. Pass them as\n // `children` of `Live.Dnd` in any arrangement to own the layout, mixing in\n // your own components where you want to replace one. `Canvas` is the one\n // that can't be replaced — the droppable, the sortable list and each\n // section's compiled iframe are Dnd's own machinery — so render it exactly\n // once wherever the canvas belongs.\n Palette: typeof Palette;\n Canvas: typeof Canvas;\n Panel: typeof Panel;\n // The built-in arrangement: the 3-pane desktop Splitter, the stacked\n // mobile canvas, and the mobile FAB/Drawers. What `Live.Dnd` renders when\n // given no children, exported so children can wrap it (a toolbar above it,\n // say) or replace one region through its `palette`/`panel` slots without\n // rebuilding the rest. Also the only way to reach the built-in Splitter\n // layout without importing `@jbpark/ui-kit` directly, which a consumer may\n // not have as a direct dependency.\n Layout: typeof Layout;\n};\n\nconst Dnd = DndImpl as DndComponent;\n\nDnd.DraggableItem = DraggableItem;\nDnd.Field = Field;\nDnd.Palette = Palette;\nDnd.Canvas = Canvas;\nDnd.Panel = Panel;\nDnd.Layout = Layout;\n\nexport { DraggableItem, Field };\nexport { Palette, Canvas, Panel, Layout };\n// The data behind each region, so a component placed in `Live.Dnd`'s children\n// can replace one without losing what drives it: the palette's items and\n// `onAdd`, the panel's selected section/bindings/commit callbacks, and the\n// layout state the built-in mobile chrome runs on (`isMobile`, `selectedId` /\n// `clearSelection`, the palette Drawer's open state) — needed because\n// supplying children replaces that chrome along with the Splitter.\nexport { useDndPalette, useDndPanel, useDndLayout };\n// The array-editing engine behind the built-in Items panel, exposed for a\n// consumer who wants their own markup rather than the built-in control\n// (`Field` covers the latter). Everything it returns is `PanelBinding`s, so\n// the two compose: render the hook's own layout and hand individual\n// bindings to `Field` where the built-in control is good enough.\nexport { useChildrenEditor } from './panel/use-children-editor';\nexport type {\n ChildrenEditor,\n ChildrenEditorOptions,\n} from './panel/use-children-editor';\nexport { useItemsEditor };\n// The built-in panel's own `widget: 'icon-picker'` icon set/options —\n// exported so a custom panel can reach icon-picker parity (name ->\n// lucide-react component, and the same label/value pairs fed to Select)\n// instead of reimplementing an icon library, per #236/#237.\nexport { ICON_MAP, ICON_OPTIONS };\nexport type {\n Props,\n DndPalette,\n DndPanel,\n DndLayout,\n DndLayoutProps,\n DndRegionProps,\n PanelBinding,\n PanelNodeChange,\n FieldProps,\n ItemsEditor,\n ItemsEditorActions,\n ItemsEditorItem,\n ItemsEditorNestedElement,\n ItemsEditorNestedGroup,\n ItemsEditorOptions,\n DraggableItemProps,\n DraggableItemDragState,\n};\nexport default Dnd;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"editor-DQSoTCe8.js","names":["Editor","EditorImpl"],"sources":["../src/components/editor/editor.tsx","../src/components/editor/index.ts"],"sourcesContent":["import { useCallback, useEffect } from 'react';\n\nimport { useDebouncedValue } from '@jbpark/use-hooks';\n\nimport { useError, usePreview } from '~/components/context/states';\nimport { DEFAULT_TEMPLATE } from '~/constants';\n\nimport Core, { type Props as CoreProps } from './core';\nimport { useFormatCode } from './use-format-code';\n\nexport interface EditorRenderData {\n value: string;\n onChange: (value: string) => void;\n // Same prettier-based formatting Core's own Cmd+S uses - reused rather\n // than reimplemented, so a custom editor can offer equivalent\n // format-on-save behavior without duplicating the prettier wiring.\n formatCode: (code: string) => Promise<string>;\n}\n\nexport interface Props extends Omit<CoreProps, 'onSave' | 'onError'> {\n defaultValue?: string;\n debounce?: number;\n // Full replacement for the built-in CodeMirror editor. Editor still owns\n // syncing `value` to the shared preview code (debounced), regardless of\n // which UI renders it - only the editing surface itself is customizable.\n renderEditor?: (data: EditorRenderData) => React.ReactNode;\n}\n\nconst Editor = ({\n defaultValue,\n value: _value,\n debounce = 1000,\n onChange: _onChange,\n renderEditor,\n fragment,\n prettierOptions,\n ...props\n}: Props) => {\n const { setCode } = usePreview();\n const { setError } = useError();\n\n const value =\n _value.trim() === '' ? defaultValue || DEFAULT_TEMPLATE : _value;\n\n const onChange = useCallback(\n (value: string) => {\n _onChange?.(value);\n },\n [_onChange],\n );\n\n const onSave = useCallback(\n (formattedCode: string) => {\n setCode(formattedCode);\n },\n [setCode],\n );\n\n const onError = useCallback(\n (error: string | null) => {\n setError(error);\n },\n [setError],\n );\n\n const formatCode = useFormatCode({ fragment, prettierOptions });\n\n const debouncedValue = useDebouncedValue(value, debounce);\n\n useEffect(() => {\n setCode(debouncedValue);\n }, [debouncedValue, setCode]);\n\n if (renderEditor) {\n return renderEditor({ value, onChange, formatCode });\n }\n\n return (\n <Core\n value={value}\n onChange={onChange}\n onSave={onSave}\n onError={onError}\n fragment={fragment}\n prettierOptions={prettierOptions}\n {...props}\n />\n );\n};\n\nexport default Editor;\n","import Core, { type Props as CoreProps } from './core';\nimport EditorImpl, { type EditorRenderData, type Props } from './editor';\n\ntype EditorComponent = typeof EditorImpl & { Core: typeof Core };\n\nconst Editor = EditorImpl as EditorComponent;\n\nEditor.Core = Core;\n\nexport { Core };\nexport type { Props, CoreProps, EditorRenderData };\nexport default Editor;\n"],"mappings":";;;;;;;AA4BA,MAAMA,YAAU,EACd,cACA,OAAO,QACP,WAAW,KACX,UAAU,WACV,cACA,UACA,iBACA,GAAG,YACQ;CACX,MAAM,EAAE,YAAY,WAAW;CAC/B,MAAM,EAAE,aAAa,SAAS;CAE9B,MAAM,QACJ,OAAO,KAAK,MAAM,KAAK,gBAAgB,mBAAmB;CAE5D,MAAM,WAAW,aACd,UAAkB;EACjB,YAAY,KAAK;CACnB,GACA,CAAC,SAAS,CACZ;CAEA,MAAM,SAAS,aACZ,kBAA0B;EACzB,QAAQ,aAAa;CACvB,GACA,CAAC,OAAO,CACV;CAEA,MAAM,UAAU,aACb,UAAyB;EACxB,SAAS,KAAK;CAChB,GACA,CAAC,QAAQ,CACX;CAEA,MAAM,aAAa,cAAc;EAAE;EAAU;CAAgB,CAAC;CAE9D,MAAM,iBAAiB,kBAAkB,OAAO,QAAQ;CAExD,gBAAgB;EACd,QAAQ,cAAc;CACxB,GAAG,CAAC,gBAAgB,OAAO,CAAC;CAE5B,IAAI,cACF,OAAO,aAAa;EAAE;EAAO;EAAU;CAAW,CAAC;CAGrD,OACE,oBAAC,MAAD;EACS;EACG;EACF;EACC;EACC;EACO;EACjB,GAAI;CACL,CAAA;AAEL;;;ACnFA,MAAM,SAASC;AAEf,OAAO,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"preview-DFH-z_JL.js","names":["LiveError"],"sources":["../src/components/preview/client.tsx","../src/components/preview/preview.tsx"],"sourcesContent":["'use client';\n\nimport { useMemo } from 'react';\n\nimport { useError, usePreview } from '~/components/context/states';\nimport LiveError from '~/components/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { cn } from '~/utils';\n\nimport { type Props } from './preview';\nimport { useCompiledModule } from './use-compiled-module';\nimport { useDynamicTailwind } from './use-dynamic-tailwind';\n\nconst Client = ({\n code: _code = '',\n className,\n showError,\n props = {},\n modules = {},\n frame,\n dynamicTailwind = false,\n provider,\n}: Props) => {\n const { code } = usePreview();\n const { error, setError } = useError();\n const isError = !!showError && !!error;\n\n const classNames = cn(isError && 'hidden', className);\n\n const effectiveCode = _code || code;\n\n const module = useCompiledModule(effectiveCode, modules);\n\n // Attached to the wrapper below; scans the rendered DOM so classes coming\n // from an imported component are picked up too. See the hook for details.\n const { ref: contentRef, css: dynamicCSS } = useDynamicTailwind(\n effectiveCode,\n dynamicTailwind,\n );\n\n const componentProps = useMemo(\n () => ({\n ...props,\n }),\n [props],\n );\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\n };\n\n if (module && module.error) {\n return (\n <>\n <div className={cn('relative h-full w-full', classNames)}>\n <LiveError message={module.error} title=\"Compile Error\" />\n </div>\n <LiveError.Runtime open={isError} />\n </>\n );\n }\n\n const Component = module?.exports?.default;\n\n if (!Component) {\n return null;\n }\n\n return (\n <>\n {frame ? (\n <div className={cn('h-full w-full', classNames)}>\n <Frame {...(frame as FrameProps)}>\n {container => (\n <div ref={contentRef} style={{ display: 'contents' }}>\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={(e: Error) => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} container={container} />\n {dynamicTailwind && dynamicCSS && (\n <style>{dynamicCSS}</style>\n )}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n </Frame>\n </div>\n ) : (\n <div\n ref={contentRef}\n className={cn(\n 'relative h-full w-full overflow-x-hidden overflow-y-auto',\n classNames,\n )}\n style={{\n isolation: 'isolate',\n transform: 'translateZ(0)',\n containerType: 'inline-size',\n }}\n >\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={e => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n <LiveError.Runtime open={isError} />\n </>\n );\n};\n\nexport default Client;\n","import type React from 'react';\n\nimport type { FrameProps } from '../frame';\nimport Client from './client';\n\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n code?: string;\n showError?: boolean;\n props?: Record<string, unknown>;\n container?: HTMLElement | null;\n frame?: boolean | FrameProps;\n modules?: Record<string, unknown>;\n dynamicTailwind?: boolean;\n provider?: (children: React.ReactNode) => React.ReactNode;\n}\n\n// A thin wrapper around Client, which does the actual compiling, error\n// handling, and frame wrapping. This used to have its own duplicate\n// compile-and-render branch for the `code` prop that never wrapped its\n// output in <Frame>, so `frame` was silently ignored whenever `code` was\n// passed — see #187. Client already handles `code` (falling back to\n// context when absent) and `frame`, so there is only one render path now.\nconst Preview = ({\n code,\n props = {},\n modules = {},\n dynamicTailwind = false,\n provider,\n ...restProps\n}: Props) => {\n return (\n <Client\n code={code}\n props={props}\n modules={modules}\n dynamicTailwind={dynamicTailwind}\n provider={provider}\n {...restProps}\n />\n );\n};\n\nexport default Preview;\n"],"mappings":";;;;;;;AAaA,MAAM,UAAU,EACd,MAAM,QAAQ,IACd,WACA,WACA,QAAQ,CAAC,GACT,UAAU,CAAC,GACX,OACA,kBAAkB,OAClB,eACW;CACX,MAAM,EAAE,SAAS,WAAW;CAC5B,MAAM,EAAE,OAAO,aAAa,SAAS;CACrC,MAAM,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC;CAEjC,MAAM,aAAa,GAAG,WAAW,UAAU,SAAS;CAEpD,MAAM,gBAAgB,SAAS;CAE/B,MAAM,SAAS,kBAAkB,eAAe,OAAO;CAIvD,MAAM,EAAE,KAAK,YAAY,KAAK,eAAe,mBAC3C,eACA,eACF;CAEA,MAAM,iBAAiB,eACd,EACL,GAAG,MACL,IACA,CAAC,KAAK,CACR;CAEA,MAAM,kBAAkB,cAA+B;EACrD,OAAO,WAAW,SAAS,SAAS,IAAI;CAC1C;CAEA,IAAI,UAAU,OAAO,OACnB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,WAAW,GAAG,0BAA0B,UAAU;EACrD,UAAA,oBAACA,OAAD;GAAW,SAAS,OAAO;GAAO,OAAM;EAAiB,CAAA;CACtD,CAAA,GACL,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;CAIN,MAAM,YAAY,QAAQ,SAAS;CAEnC,IAAI,CAAC,WACH,OAAO;CAGT,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,QACC,oBAAC,OAAD;EAAK,WAAW,GAAG,iBAAiB,UAAU;EAC5C,UAAA,oBAAC,OAAD;GAAO,GAAK;GACT,WAAA,cACC,oBAAC,OAAD;IAAK,KAAK;IAAY,OAAO,EAAE,SAAS,WAAW;IACjD,UAAA,oBAACA,MAAU,UAAX;KACE,WAAW,CAAC,aAAa;KACzB,UAAU,MAAa,SAAS,EAAE,OAAO;KAExC,UAAA,eACC,qBAACA,MAAU,OAAX;MAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;MAAjD,UAAA,CACE,oBAAC,WAAD;OAAW,GAAI;OAA2B;MAAY,CAAA,GACrD,mBAAmB,cAClB,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAEb;KACnB,CAAA,CAAA;IACkB,CAAA;GACjB,CAAA;EAEF,CAAA;CACJ,CAAA,IAEL,oBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,4DACA,UACF;EACA,OAAO;GACL,WAAW;GACX,WAAW;GACX,eAAe;EACjB;EAEA,UAAA,oBAACA,MAAU,UAAX;GACE,WAAW,CAAC,aAAa;GACzB,UAAS,MAAK,SAAS,EAAE,OAAO;GAE/B,UAAA,eACC,qBAACA,MAAU,OAAX;IAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;IAAjD,UAAA,CACE,oBAAC,WAAD,EAAW,GAAI,eAAiB,CAAA,GAC/B,mBAAmB,cAAc,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAC7C;GACnB,CAAA,CAAA;EACkB,CAAA;CACjB,CAAA,GAEP,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;AAEN;;;ACnGA,MAAM,WAAW,EACf,MACA,QAAQ,CAAC,GACT,UAAU,CAAC,GACX,kBAAkB,OAClB,UACA,GAAG,gBACQ;CACX,OACE,oBAAC,QAAD;EACQ;EACC;EACE;EACQ;EACP;EACV,GAAI;CACL,CAAA;AAEL"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-dynamic-tailwind-DqqQu2de.js","names":[],"sources":["../src/components/frame/measure.ts","../src/components/frame/viewport-units.ts","../src/components/frame/iframe.tsx","../src/components/frame/shadow.tsx","../src/components/frame/frame.tsx","../src/components/preview/use-compiled-module.ts","../src/components/preview/use-dynamic-tailwind.ts"],"sourcesContent":["// Pure helpers behind iframe.tsx's autoHeight measurement (#132 stages\n// 2-3) — kept DOM-free so they're testable under this repo's node-\n// environment vitest setup; the DOM walking itself (getComputedStyle,\n// querySelectorAll, offsetHeight reads) has no real layout engine to run\n// against outside a real browser and stays in iframe.tsx, verified\n// separately with a real Chromium instance instead of a unit test.\n\n// A fallback used only when there's no `[data-frame-container]` scroll\n// container to measure against at all — e.g. `Frame` used directly by a\n// library consumer, without `Dnd`. There's no better reference height to\n// wait for in that case (unlike the \"container exists but hasn't laid out\n// yet\" case below, which defers instead), so this just needs to be *some*\n// reasonable default. Matches the source fork's own constant — a common\n// mobile viewport height, chosen there for the same reason.\nexport const FALLBACK_PROBE_HEIGHT = 812;\n\n// The reference height for the preview's CSS containment context (see\n// ensureContainerStyle in iframe.tsx) — everything sized in `vh`-family\n// units (converted to `cqh` by convertViewportUnits) resolves against\n// this instead of the iframe's own height, which is what breaks the old\n// approach's fold-to-0px-then-measure circularity (#132 problem 1).\n//\n// `clientHeight` already excludes the scroll container's own border, but\n// not any padding/border on wrapper elements *between* the iframe and\n// that container (this codebase's own Sortable/Renderer/Frame don't add\n// any today, but a consumer's own `provider` or custom-panel wrapper\n// could) — `wrapperInsets` is the sum of those, added up by the caller\n// while walking from the iframe to the scroll container.\n//\n// Returns `null` (not a guessed fallback) when the container hasn't been\n// laid out yet (`clientHeight` still 0, e.g. mid-transition) — the\n// caller should skip this measurement pass rather than settle on a\n// number that has nothing to do with the actual available space and\n// that no future event would ever correct (see the issue's own\n// reasoning for why a `window.innerHeight` fallback here was wrong).\nexport const computeProbeHeight = (\n scrollContainerClientHeight: number,\n wrapperInsets: number,\n): number | null => {\n const usable = scrollContainerClientHeight - wrapperInsets;\n\n return usable > 0 ? usable : null;\n};\n\n// `visibility:hidden` and `opacity:0` elements keep a non-zero\n// offsetHeight/scrollHeight (unlike `display:none`, which zeroes them\n// out on its own) — without this check, a closed bottom sheet or a\n// not-yet-faded-in overlay sitting in the DOM inflates the measured\n// height by however tall it would be if shown.\nexport const isVisuallyHidden = (computed: {\n visibility: string;\n opacity: string;\n}): boolean => computed.visibility === 'hidden' || computed.opacity === '0';\n\n// `translate(Xpx, Ypx)` / `translateY(Ypx)` / `matrix(a,b,c,d,tx,ty)`'s Y\n// component — a positioned popup/overlay is commonly offset this way\n// (Radix/floating-ui do), so its *effective* bottom edge is `offsetY +\n// offsetHeight` from its positioned ancestor, not just `offsetHeight`\n// alone. Returns 0 for anything else (no transform, or an X-only/\n// unrecognized one) rather than throwing — an unparsed offset is safer\n// treated as \"no extra offset\" than as a measurement failure.\n//\n// iframe.tsx's only caller passes `getComputedStyle(el).transform`, which\n// every real browser normalizes to `matrix(...)` regardless of what\n// syntax (translate/translateY/none of the above) the original CSS used\n// — confirmed against a real Chromium instance, not assumed. The\n// translate()/translateY() branches mainly document intent and cover any\n// future caller that passes an *inline* style's transform instead (which\n// does preserve the author's original syntax).\nexport const parseTranslateY = (transform: string): number => {\n if (!transform || transform === 'none') {\n return 0;\n }\n\n // translateY(y) is single-argument — tried first and separately from\n // translate(x, y), since a naive \"match the arg after a comma\" pattern\n // has no comma to find here at all and would silently fall through to 0.\n const translateYMatch = transform.match(/translateY\\(\\s*([+-]?\\d*\\.?\\d+)/);\n\n if (translateYMatch?.[1]) {\n return parseFloat(translateYMatch[1]);\n }\n\n const translateMatch = transform.match(\n /translate\\([^,]+,\\s*([+-]?\\d*\\.?\\d+)/,\n );\n\n if (translateMatch?.[1]) {\n return parseFloat(translateMatch[1]);\n }\n\n const matrixMatch = transform.match(\n /matrix\\(\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*[^,]+,\\s*([+-]?\\d*\\.?\\d+)/,\n );\n\n return matrixMatch?.[1] ? parseFloat(matrixMatch[1]) : 0;\n};\n\n// A `position:fixed`/`absolute` element is placed relative to the\n// viewport (or the nearest positioned ancestor, which for this preview\n// content is effectively the same scale) — `offsetY + offsetHeight` can\n// legitimately exceed the probe height (e.g. an element deliberately\n// positioned to bleed off-screen), but letting an unbounded value drive\n// the *whole document's* measured height would make one runaway overlay\n// balloon everything below it. Capping at `probeHeight` treats \"this\n// element's bottom edge is somewhere past the viewport\" the same as \"at\n// the viewport edge\" for sizing purposes, without needing to know how far\n// past.\nexport const estimatePositionedElementHeight = (\n offsetHeight: number,\n transform: string,\n probeHeight: number,\n): number => {\n const offsetY = parseTranslateY(transform);\n\n return Math.min(offsetY + offsetHeight, probeHeight);\n};\n","// Part of #132 stage 1 — porting the internal GitLab fork's autoHeight\n// height-measurement redesign into this repo, one verifiable stage at a\n// time (see the issue for the full plan and why the current `updateHeight`\n// implementation needs replacing: folding the iframe to 0px before\n// measuring permanently collapses `vh`-sized content to 0, since `vh`\n// units resolve against the iframe's own height).\n//\n// The fork's fix replaces the iframe height as `vh`'s reference point with\n// a fixed-size CSS containment context (`html { container-type: size;\n// height: <probe>px }`) — see stage 2. That only works if the document's\n// own `vh`/`svh`/`lvh`/`dvh`/`vmin`/`vmax` usages are first rewritten to\n// the matching container-query unit (`cqh`/`cqmin`/`cqmax`), since a size\n// container doesn't retroactively change what `vh` itself resolves\n// against. `vw`/`vi` are deliberately left alone: they resolve against\n// width, which this measurement never touches, so rewriting them would\n// only add risk with no corresponding bug to fix.\nconst UNIT_MAP: Record<string, string> = {\n vh: 'cqh',\n svh: 'cqh',\n lvh: 'cqh',\n dvh: 'cqh',\n vmin: 'cqmin',\n vmax: 'cqmax',\n};\n\n// Longest-unit-first so `svh`/`lvh`/`dvh` aren't shadowed by a shorter\n// alternative matching a prefix of them first.\nconst UNITS_PATTERN = Object.keys(UNIT_MAP)\n .sort((a, b) => b.length - a.length)\n .join('|');\n\n// A CSS dimension token: optional sign, then digits with an optional\n// fractional part on either side of the decimal point (`100`, `50.5`,\n// `-10`, `.5` all match; a bare `-` or `.` alone does not).\nconst NUMBER_PATTERN = '-?(?:\\\\d+\\\\.?\\\\d*|\\\\.\\\\d+)';\n\n// Requires the matched number not to be immediately preceded by a letter,\n// digit, underscore, `.`, or `-` — this is what keeps `url(a5vh.png)`,\n// `.a5vh{}`, and `.hero-100vh{}` untouched (in all three, the digits\n// before `vh` are part of a larger filename/class-name token, not a\n// standalone CSS number) without needing any special-casing for\n// `url(...)`/selectors specifically. `-` has to be excluded too, not just\n// `\\w`/`.`, since a kebab-case identifier like `hero-100vh` uses it as a\n// word separator the same way `a5vh` uses no separator at all — otherwise\n// the number pattern's own optional leading `-?` would happily treat that\n// hyphen as a negative sign instead. This doesn't break real negative\n// values (`margin-top: -10vh`): there the character *before* the `-` is\n// whatever precedes the whole declaration (a space, in practice), so the\n// lookbehind still passes and the leading `-` is captured as part of the\n// number, same as before.\n//\n// Separately, `--my-vh: 10px` was never a candidate to begin with: there's\n// no digit immediately before `vh` there at all (the `y` in `-vh` is a\n// letter, not a number), so the pattern doesn't even try to match it.\nconst VIEWPORT_UNIT_RE = new RegExp(\n `(?<![\\\\w.-])(${NUMBER_PATTERN})(${UNITS_PATTERN})(?![a-zA-Z0-9_-])`,\n 'gi',\n);\n\n// Rewrites vh/svh/lvh/dvh/vmin/vmax to their cqh/cqmin/cqmax equivalent\n// wherever they appear as an actual CSS dimension — including nested\n// inside calc()/var() fallbacks, since this is a plain text substitution\n// rather than a CSS-aware parse. `vw` is left as-is (see UNIT_MAP above).\n//\n// Known limitation, inherited from the source fork and not fixed here:\n// this can't distinguish a real dimension from the same text sitting\n// inside a CSS string literal, e.g. `content: \"100vh\"` — the regex has no\n// concept of quoting, so that string's contents get rewritten too. In\n// practice this is rare (a `content` value that's coincidentally shaped\n// like a viewport dimension) and doesn't affect layout, since `content`\n// strings aren't parsed as CSS values.\nexport const convertViewportUnits = (css: string): string =>\n css.replace(\n VIEWPORT_UNIT_RE,\n (_match, number: string, unit: string) =>\n number + UNIT_MAP[unit.toLowerCase()],\n );\n\n// `convertViewportUnits` only ever runs over CSS *text* that this component\n// controls the injection of — the parent-document `<style>` copies (syncStyle)\n// and the `styles` prop (see iframe.tsx). Two paths carry a viewport unit into\n// the preview document without passing through either, so the container-context\n// fix (#132) never reaches them and their `vh` still resolves against the\n// iframe's own height — re-creating the exact circularity #132 removed:\n//\n// 1. inline `style` attributes — the visual editor's panel edits produce\n// these, so they're a common path here, not an edge case; and\n// 2. author `<style>` elements rendered *inside* the previewed component by\n// React, which never pass through `applyStyle`/`styles`.\n//\n// This rewrites both in place, walking only nodes that could carry a match so\n// the pass stays cheap. It's meant to be called from `updateHeight` right after\n// the container style is (re)applied and before any height is read.\n//\n// Idempotent, and specifically non-perturbing once converted: a rewritten value\n// contains `cqh`/`cqmin`/`cqmax`, none of which match the `vh`/`vmin`/`vmax`\n// attribute selectors, so a second pass re-selects nothing; and each node is\n// written back only when its text actually changed, so an already-converted\n// document isn't mutated — which matters because the write itself would\n// otherwise re-trip the MutationObserver in iframe.tsx and loop.\nexport const rewriteInlineViewportUnits = (root: HTMLElement): void => {\n // `vh` as a substring already covers `svh`/`lvh`/`dvh`; `vmin`/`vmax` need\n // their own terms. Case-insensitive so `100VH` inline is caught too.\n const inlineTargets = root.querySelectorAll<HTMLElement>(\n '[style*=\"vh\" i], [style*=\"vmin\" i], [style*=\"vmax\" i]',\n );\n\n inlineTargets.forEach(el => {\n const current = el.getAttribute('style');\n\n if (current == null) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n el.setAttribute('style', converted);\n }\n });\n\n root.querySelectorAll<HTMLStyleElement>('style').forEach(styleEl => {\n const current = styleEl.textContent;\n\n if (!current) {\n return;\n }\n\n const converted = convertViewportUnits(current);\n\n if (converted !== current) {\n styleEl.textContent = converted;\n }\n });\n};\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useMutationObserver, useResizeObserver } from '@jbpark/use-hooks';\n\nimport { getCachedScriptBlob } from '~/utils';\n\nimport {\n FALLBACK_PROBE_HEIGHT,\n computeProbeHeight,\n estimatePositionedElementHeight,\n isVisuallyHidden,\n} from './measure';\nimport {\n convertViewportUnits,\n rewriteInlineViewportUnits,\n} from './viewport-units';\n\nexport interface Props {\n title?: string;\n /** Forwarded to the iframe's `sandbox` attribute for DOM/CSS isolation only — not a security boundary, since preview code executes in the host window's realm (see `compileModule` in `~/utils`). */\n sandbox?: string;\n style?: React.CSSProperties;\n scripts?: string[];\n styles?: string[];\n stylesheets?: string[];\n autoHeight?: boolean;\n syncStyle?: boolean;\n children: (container: HTMLElement) => ReactNode;\n onLoaded?: () => void;\n}\n\nconst EMPTY_STRING_ARRAY: string[] = [];\n\nconst IFrame = ({\n title = 'Live Preview',\n sandbox,\n style = {},\n scripts = EMPTY_STRING_ARRAY,\n styles = EMPTY_STRING_ARRAY,\n stylesheets = EMPTY_STRING_ARRAY,\n autoHeight = false,\n syncStyle = false,\n children,\n onLoaded,\n ...props\n}: Props) => {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const [mountNode, setMountNode] = useState<HTMLElement | null>(null);\n // Tracks which script srcs have already been injected into this iframe's\n // document, keyed by src rather than a single loaded/not-loaded boolean —\n // a boolean latched to `true` forever meant a later change to `scripts`\n // (new entries) never got loaded once the first batch had.\n const loadedScriptsRef = useRef<Set<string>>(new Set());\n const prevStyleCountRef = useRef(0);\n const prevStylesheetCountRef = useRef(0);\n const shouldAutoHeight = autoHeight && style.height == null;\n\n const styleManagerRef = useRef<{\n copiedLinks: Set<string>;\n copiedStyles: Set<string>;\n }>({\n copiedLinks: new Set(),\n copiedStyles: new Set(),\n });\n\n const applyStyle = useCallback(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc || !syncStyle) {\n return;\n }\n\n const manager = styleManagerRef.current;\n\n const links = document.querySelectorAll<HTMLLinkElement>(\n 'link[rel=\"stylesheet\"]',\n );\n const newLinks = Array.from(links)\n .map(link => link.href)\n .filter(href => !manager.copiedLinks.has(href));\n\n if (newLinks.length) {\n const fragment = doc.createDocumentFragment();\n newLinks.forEach(href => {\n const link = doc.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n fragment.appendChild(link);\n manager.copiedLinks.add(href);\n });\n doc.head.appendChild(fragment);\n }\n\n const styles = document.querySelectorAll<HTMLStyleElement>('style');\n const newStyles = Array.from(styles)\n .map(style => style.textContent || '')\n .filter(content => {\n if (!content) {\n return false;\n }\n const hash = content.length + content.slice(0, 50);\n if (manager.copiedStyles.has(hash)) {\n return false;\n }\n manager.copiedStyles.add(hash);\n return true;\n });\n\n if (newStyles.length) {\n const fragment = doc.createDocumentFragment();\n newStyles.forEach(content => {\n const style = doc.createElement('style');\n // Host styles can legitimately use vh/svh/etc themselves (e.g. a\n // shared design-system stylesheet) — converted the same way as\n // the styles/stylesheets props below, so they resolve against\n // the preview's own probe height instead of the iframe's, once\n // autoHeight's container context (see ensureContainerStyle) is\n // active.\n style.textContent = convertViewportUnits(content);\n fragment.appendChild(style);\n });\n doc.head.appendChild(fragment);\n }\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced so a burst of head mutations (a stylesheet swap can fire\n // several in quick succession) only re-runs applyStyle once, matching the\n // original raw-MutationObserver setup's 50ms debounce.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useEffect(() => {\n return () => clearTimeout(applyStyleTimeoutRef.current);\n }, []);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n useEffect(() => {\n const $iframe = iframeRef.current;\n\n if (!$iframe) {\n return;\n }\n\n const onLoad = () => {\n const doc = $iframe.contentDocument;\n\n if (!doc) {\n return;\n }\n\n doc.body.style.overflowX = 'hidden';\n doc.body.style.margin = '0';\n\n let node = doc.getElementById('iframe-root');\n\n if (!node) {\n node = doc.createElement('div');\n node.id = 'iframe-root';\n doc.body.appendChild(node);\n }\n\n setMountNode(node);\n\n applyStyle();\n\n const pendingScripts = scripts.filter(\n src => !loadedScriptsRef.current.has(src),\n );\n\n if (pendingScripts.length) {\n pendingScripts.forEach(src => loadedScriptsRef.current.add(src));\n\n Promise.all(pendingScripts.map(getCachedScriptBlob)).then(blobUrls => {\n if (!doc.head) {\n return;\n }\n\n const fragment = doc.createDocumentFragment();\n blobUrls.forEach(blobUrl => {\n const script = doc.createElement('script');\n script.src = blobUrl;\n fragment.appendChild(script);\n });\n doc.head.appendChild(fragment);\n });\n }\n\n onLoaded?.();\n };\n\n $iframe.addEventListener('load', onLoad);\n\n if ($iframe.contentDocument?.readyState === 'complete') {\n onLoad();\n }\n\n return () => {\n $iframe.removeEventListener('load', onLoad);\n };\n }, [scripts, onLoaded, applyStyle]);\n\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n styles.forEach((css, index) => {\n const styleId = `injected-style-${index}`;\n let styleEl = doc.getElementById(styleId) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = styleId;\n doc.head.appendChild(styleEl);\n }\n\n // The primary source of vh/svh/etc in a real preview — compiled\n // component CSS (e.g. Tailwind's `h-screen` -> `height: 100vh`).\n // See ensureContainerStyle below for why this needs converting.\n const convertedCss = convertViewportUnits(css);\n\n if (styleEl.textContent !== convertedCss) {\n styleEl.textContent = convertedCss;\n }\n });\n\n // Indices beyond the current array's length are stale from a previous,\n // longer `styles`/`stylesheets` — the loops above only add/update up to\n // the current length, so anything past it (from before an item was\n // removed, or the array shrank) would otherwise stay injected forever.\n for (\n let index = styles.length;\n index < prevStyleCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-style-${index}`)?.remove();\n }\n prevStyleCountRef.current = styles.length;\n\n stylesheets.forEach((href, index) => {\n const linkId = `injected-stylesheet-${index}`;\n let linkEl = doc.getElementById(linkId) as HTMLLinkElement | null;\n\n if (!linkEl) {\n linkEl = doc.createElement('link');\n linkEl.id = linkId;\n linkEl.rel = 'stylesheet';\n doc.head.appendChild(linkEl);\n }\n\n if (linkEl.href !== href) {\n linkEl.href = href;\n }\n });\n\n for (\n let index = stylesheets.length;\n index < prevStylesheetCountRef.current;\n index++\n ) {\n doc.getElementById(`injected-stylesheet-${index}`)?.remove();\n }\n prevStylesheetCountRef.current = stylesheets.length;\n }, [styles, stylesheets]);\n\n // The <html> element's own container-context style — id'd so it can be\n // found/updated/removed across calls without holding a ref to it. Scoped\n // to `html` (not `:root`, which is equivalent but the fork's own\n // convention) so this only ever affects cq*-unit resolution and nothing\n // else about the document.\n const CONTAINER_STYLE_ID = 'autoheight-container';\n\n // Permanently hides the iframe document's own scrollbar chrome while\n // autoHeight is sizing the iframe to its content. autoHeight sets the\n // iframe's height to `Math.ceil(contentHeight)`, so sub-pixel content or\n // a rounding remainder can leave the inner document a fraction taller\n // than its viewport — enough for the browser to draw a vertical\n // scrollbar inside every section's iframe (visual noise once several Dnd\n // sections stack). Unlike the measurement-only override above (toggled\n // off after each read), this one stays on: `scrollbar-width`/\n // `::-webkit-scrollbar` hide only the *chrome*, not scrolling itself, so\n // content that ever genuinely exceeds the measured height is still\n // reachable by wheel/keyboard rather than clipped.\n const HIDE_SCROLLBAR_STYLE_ID = 'autoheight-hide-scrollbar';\n\n // Ties `cqh`/`cqmin`/`cqmax` (what convertViewportUnits rewrote every\n // vh/svh/lvh/dvh/vmin/vmax to) to a *fixed* reference height instead of\n // the iframe's own height — this is what breaks the old approach's\n // circularity (#132 problem 1): folding the iframe to 0px before\n // measuring made vh-sized content resolve to 0 and stay there forever,\n // while measuring without folding never converges (vh content sized\n // against the iframe's own just-grown height keeps growing it further).\n // `container-type: size` requires an explicit height to size against,\n // which `probeHeight` (the *scroll container's* available height, not\n // the iframe's) provides — genuinely independent of whatever height this\n // function goes on to set on the iframe itself.\n const ensureContainerStyle = (doc: Document, probeHeight: number) => {\n let styleEl = doc.getElementById(\n CONTAINER_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = CONTAINER_STYLE_ID;\n doc.head?.appendChild(styleEl);\n }\n\n styleEl.textContent = `html { container-type: size !important; height: ${probeHeight}px !important; }`;\n };\n\n // A second, separate style — inert (`media=\"not all\"`) except for the\n // brief window updateHeight actually measures in, toggled on right\n // before and off right after (#132 stage 4). Two things it guards\n // against:\n //\n // - transitions: if any rule in the preview (or a browser default)\n // gives `html`/an ancestor a `transition` on a property this\n // measurement touches, changing ensureContainerStyle's `height` would\n // animate instead of applying instantly, and a read taken right after\n // would catch a mid-transition value instead of the settled one.\n // - scrollbar chrome: applying a new probe height can make a scrollbar\n // appear/disappear for exactly this measurement pass; on platforms\n // where it takes up layout width (Windows, unlike macOS's overlay\n // scrollbars), that narrows content and skews the height reading.\n // `scrollbar-width: none`/`::-webkit-scrollbar { display: none }`\n // only hides the *chrome* — unlike `overflow: hidden`, scrolling\n // itself still works, so content that ends up taller than its probe\n // height is still reachable rather than silently clipped.\n //\n // A single style element (not two, and never added/removed) so\n // toggling it can't itself trip the MutationObserver watching for\n // *content* changes.\n const MEASUREMENT_OVERRIDE_STYLE_ID = 'autoheight-measurement-overrides';\n\n const withMeasurementOverrides = (doc: Document, measure: () => void) => {\n let styleEl = doc.getElementById(\n MEASUREMENT_OVERRIDE_STYLE_ID,\n ) as HTMLStyleElement | null;\n\n if (!styleEl) {\n styleEl = doc.createElement('style');\n styleEl.id = MEASUREMENT_OVERRIDE_STYLE_ID;\n styleEl.media = 'not all';\n styleEl.textContent = [\n '*, *::before, *::after { transition: none !important; }',\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n ].join('\\n');\n doc.head?.appendChild(styleEl);\n }\n\n styleEl.media = 'all';\n measure();\n styleEl.media = 'not all';\n };\n\n // Not ported from #132 stage 4: a \"settled scrollHeight + settled probe\n // height both unchanged -> skip\" guard, meant to avoid redundant re-runs\n // from updateHeight's own `iframe.style.height` write looping back\n // through the ResizeObserver below (a real path — the iframe's own box\n // size determines its *internal* viewport size, so this can genuinely\n // fire again). Left out deliberately: `scrollHeight` only reflects\n // normal document flow, but a position:fixed/absolute overlay opening or\n // closing (its whole reason for needing the full-subtree walk above)\n // often doesn't touch `scrollHeight` at all. A guard keyed on it would\n // silently skip exactly the kind of update stage 3 exists to catch —\n // reintroducing a narrower version of the bug this file just fixed\n // would be a worse trade than the redundant-recompute cost it'd save.\n const updateHeight = useCallback(() => {\n if (!shouldAutoHeight || !mountNode || !iframeRef.current) {\n return;\n }\n\n const iframe = iframeRef.current;\n const doc = iframe.contentDocument;\n const win = doc?.defaultView;\n\n if (!doc || !win) {\n return;\n }\n\n const scrollParent = iframe.closest<HTMLElement>('[data-frame-container]');\n\n let probeHeight: number;\n\n if (!scrollParent) {\n // No scroll container anywhere in the tree (Frame used directly,\n // without Dnd) — fall back to a fixed default; see\n // FALLBACK_PROBE_HEIGHT's own comment for why this differs from\n // the \"container exists but isn't laid out yet\" case below.\n probeHeight = FALLBACK_PROBE_HEIGHT;\n } else {\n let wrapperInsets = 0;\n let node = iframe.parentElement;\n\n while (node && node !== scrollParent) {\n const style = win.getComputedStyle(node);\n\n wrapperInsets +=\n parseFloat(style.borderTopWidth) +\n parseFloat(style.borderBottomWidth) +\n parseFloat(style.paddingTop) +\n parseFloat(style.paddingBottom);\n\n node = node.parentElement;\n }\n\n const computed = computeProbeHeight(\n scrollParent.clientHeight,\n wrapperInsets,\n );\n\n if (computed === null) {\n // Layout not ready yet (mid-transition, just mounted, etc) —\n // skip this pass instead of guessing; the ResizeObserver/\n // MutationObserver below will call this again once something\n // actually changes, including the layout settling.\n return;\n }\n\n probeHeight = computed;\n }\n\n let contentHeight = 0;\n\n withMeasurementOverrides(doc, () => {\n ensureContainerStyle(doc, probeHeight);\n\n // Rewrite vh-family units the container context can't otherwise reach —\n // inline `style` attributes and in-preview `<style>` tags — so they too\n // resolve against the fixed probe height rather than the iframe's own\n // (see rewriteInlineViewportUnits). Must run after ensureContainerStyle\n // and before the reads below; it's idempotent, so the extra observer\n // pass its first-render rewrites trigger converges immediately.\n rewriteInlineViewportUnits(mountNode);\n\n // No 0px fold before measuring (that was the source of problem 1)\n // — with cq*-unit content now sized against the fixed probe height\n // instead of the iframe's own, a direct read is already stable.\n contentHeight = mountNode.scrollHeight;\n\n // Full subtree, not just direct children (a popup/overlay nested a\n // few components deep was previously invisible to this walk\n // entirely — problem 2's \"중첩된 오버레이는 아예 누락됩니다\").\n const descendants = mountNode.querySelectorAll<HTMLElement>('*');\n\n descendants.forEach(el => {\n const style = win.getComputedStyle(el);\n\n // visibility:hidden/opacity:0 elements (a closed bottom sheet,\n // a not-yet-faded-in overlay) keep a non-zero offsetHeight —\n // display:none doesn't need checking here since the browser\n // already zeroes *its* offsetHeight on its own.\n if (isVisuallyHidden(style)) {\n return;\n }\n\n if (\n (style.position === 'fixed' || style.position === 'absolute') &&\n el.offsetHeight > 0\n ) {\n const estimatedHeight = estimatePositionedElementHeight(\n el.offsetHeight,\n style.transform,\n probeHeight,\n );\n\n contentHeight = Math.max(contentHeight, estimatedHeight);\n }\n });\n });\n\n if (contentHeight > 0) {\n iframe.style.height = `${Math.ceil(contentHeight)}px`;\n }\n }, [shouldAutoHeight, mountNode]);\n\n // updateHeight only ever adds/refreshes the container-context style —\n // if autoHeight is toggled off (or an explicit style.height is passed)\n // at runtime, nothing else would ever remove or update it again,\n // leaving cq*-unit content sized against a stale probe height instead\n // of correctly falling back to real viewport-relative sizing (which\n // cqh does on its own once nothing establishes a size container — see\n // ensureContainerStyle's own comment).\n useEffect(() => {\n if (shouldAutoHeight) {\n return;\n }\n\n iframeRef.current?.contentDocument\n ?.getElementById(CONTAINER_STYLE_ID)\n ?.remove();\n }, [shouldAutoHeight]);\n\n // Keyed on mountNode (not just shouldAutoHeight) so it re-runs once the\n // iframe's document exists — before load there's no head to inject into.\n useEffect(() => {\n const doc = iframeRef.current?.contentDocument;\n\n if (!doc?.head) {\n return;\n }\n\n const existing = doc.getElementById(HIDE_SCROLLBAR_STYLE_ID);\n\n if (!shouldAutoHeight) {\n existing?.remove();\n return;\n }\n\n if (existing) {\n return;\n }\n\n const styleEl = doc.createElement('style');\n styleEl.id = HIDE_SCROLLBAR_STYLE_ID;\n styleEl.textContent = [\n 'html, body { scrollbar-width: none !important; }',\n 'html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }',\n ].join('\\n');\n doc.head.appendChild(styleEl);\n }, [shouldAutoHeight, mountNode]);\n\n useEffect(() => {\n updateHeight();\n }, [updateHeight]);\n\n const [resizeRef, resizeSize] = useResizeObserver<HTMLElement>();\n\n // useResizeObserver's ref callback isn't wired through this component's\n // own JSX (mountNode is the portal's imperatively-created container, not\n // something rendered here), so it's attached/detached imperatively\n // instead. Its reported size is intentionally unused - updateHeight's own\n // walk (every descendant, position:fixed/absolute ones capped and offset\n // by their transform) computes a more accurate height than mountNode's\n // own content-box size would, so a change in `resizeSize` is only used\n // as a trigger to recompute.\n useEffect(() => {\n if (!shouldAutoHeight || !mountNode) {\n return;\n }\n\n resizeRef(mountNode);\n return () => resizeRef(null);\n }, [shouldAutoHeight, mountNode, resizeRef]);\n\n useEffect(() => {\n updateHeight();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [resizeSize]);\n\n useMutationObserver(mountNode, updateHeight, {\n enabled: shouldAutoHeight,\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n });\n\n const content = mountNode\n ? createPortal(children(mountNode), mountNode)\n : null;\n\n return (\n <iframe\n ref={iframeRef}\n style={{\n width: '100%',\n height: '100%',\n border: 'none',\n ...style,\n }}\n title={title}\n sandbox={sandbox}\n {...props}\n >\n {content}\n </iframe>\n );\n};\n\nexport default IFrame;\n","import { useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nimport { useMutationObserver } from '@jbpark/use-hooks';\n\ninterface Props {\n // Clones the host document's <link rel=\"stylesheet\">/<style> tags into the\n // shadow root, mirroring `iframe.tsx`'s option of the same name. Unlike\n // `dynamicTailwind` (which recompiles only the classes it can find in the\n // rendered DOM, and only knows Tailwind's own default theme), this gets\n // the host's *actual* compiled CSS — including a consuming app's own\n // custom utilities/theme tokens — at the cost of only covering classes\n // that were already known at the host's own build time. The two are\n // complementary: this handles anything already in the host's stylesheets,\n // dynamicTailwind covers whatever's left (e.g. a class typed at runtime\n // that no build ever saw).\n syncStyle?: boolean;\n children: (hostContainer: HTMLElement | null) => ReactNode;\n}\n\nconst Shadow = ({ syncStyle = false, children }: Props) => {\n const hostRef = useRef<HTMLDivElement>(null);\n const shadowRootRef = useRef<ShadowRoot | null>(null);\n const renderTargetRef = useRef<HTMLDivElement | null>(null);\n const [renderTarget, setRenderTarget] = useState<HTMLDivElement | null>(null);\n const [hostContainer, setHostContainer] = useState<HTMLElement | null>(null);\n\n // Appended as siblings of the portal target (below), not inside it — that\n // subtree is React-owned via createPortal, and anything appended there\n // directly would get wiped on the next reconcile.\n const styleManagerRef = useRef<{\n copiedLinks: Set<string>;\n copiedStyles: Set<string>;\n }>({\n copiedLinks: new Set(),\n copiedStyles: new Set(),\n });\n\n const applyStyle = useCallback(() => {\n const shadowRoot = shadowRootRef.current;\n\n if (!shadowRoot || !syncStyle) {\n return;\n }\n\n const manager = styleManagerRef.current;\n\n const links = document.querySelectorAll<HTMLLinkElement>(\n 'link[rel=\"stylesheet\"]',\n );\n const newLinks = Array.from(links)\n .map(link => link.href)\n .filter(href => !manager.copiedLinks.has(href));\n\n if (newLinks.length) {\n const fragment = document.createDocumentFragment();\n newLinks.forEach(href => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = href;\n fragment.appendChild(link);\n manager.copiedLinks.add(href);\n });\n shadowRoot.appendChild(fragment);\n }\n\n const styleTags = document.querySelectorAll<HTMLStyleElement>('style');\n const newStyles = Array.from(styleTags)\n .map(style => style.textContent || '')\n .filter(content => {\n if (!content) {\n return false;\n }\n const hash = content.length + content.slice(0, 50);\n if (manager.copiedStyles.has(hash)) {\n return false;\n }\n manager.copiedStyles.add(hash);\n return true;\n });\n\n if (newStyles.length) {\n const fragment = document.createDocumentFragment();\n newStyles.forEach(content => {\n const style = document.createElement('style');\n style.textContent = content;\n fragment.appendChild(style);\n });\n shadowRoot.appendChild(fragment);\n }\n }, [syncStyle]);\n\n const applyStyleTimeoutRef = useRef<number>(undefined);\n\n // Debounced so a burst of head mutations (a stylesheet swap can fire\n // several in quick succession) only re-runs applyStyle once — same\n // rationale as iframe.tsx's identical setup.\n const debouncedApplyStyle = useCallback(() => {\n clearTimeout(applyStyleTimeoutRef.current);\n applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);\n }, [applyStyle]);\n\n useMutationObserver(document.head, debouncedApplyStyle, {\n enabled: syncStyle,\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['href'],\n });\n\n useLayoutEffect(() => {\n if (!hostRef.current) {\n return;\n }\n\n const container = hostRef.current.closest(\n '[data-frame-container]',\n ) as HTMLElement | null;\n\n setHostContainer(container);\n\n let shadowRoot = shadowRootRef.current;\n\n if (!shadowRoot) {\n shadowRoot =\n hostRef.current.shadowRoot ||\n hostRef.current.attachShadow({ mode: 'open' });\n shadowRootRef.current = shadowRoot;\n }\n\n let target = renderTargetRef.current;\n\n if (!target) {\n target = document.createElement('div');\n shadowRoot.appendChild(target);\n renderTargetRef.current = target;\n setRenderTarget(target);\n }\n\n applyStyle();\n // click/pointerdown/pointerup are `composed: true` by spec, so they\n // already retarget across the shadow boundary and reach listeners\n // outside it (document, this host's ancestors, React's own root\n // listener) on their own - manually redispatching them here used to\n // make every one of those listeners see the interaction twice. Anyone\n // needing the real element inside the shadow tree (not the retargeted\n // host) can still read it via event.composedPath()[0], unaffected by\n // this removal. See #92.\n }, [applyStyle]);\n\n useLayoutEffect(() => {\n if (renderTargetRef.current && !renderTarget) {\n setRenderTarget(renderTargetRef.current);\n }\n }, [renderTarget]);\n\n return (\n <div ref={hostRef} style={{ display: 'contents' }}>\n {renderTarget && createPortal(children(hostContainer), renderTarget)}\n </div>\n );\n};\n\nexport default Shadow;\n","import { type ReactNode } from 'react';\n\nimport IFrame, { type Props as IframeProps } from './iframe';\nimport Shadow from './shadow';\n\nexport interface FrameProps extends Omit<IframeProps, 'children'> {\n mode?: 'iframe' | 'shadow';\n}\n\ninterface Props extends FrameProps {\n children: (container: HTMLElement) => ReactNode;\n}\n\nconst Frame = ({ mode, children, ...restProps }: Props) => {\n if (!mode) {\n return children(document.body);\n }\n\n if (mode === 'shadow') {\n return (\n <Shadow syncStyle={restProps.syncStyle}>\n {container => children(container || document.body)}\n </Shadow>\n );\n }\n\n return <IFrame {...restProps}>{children}</IFrame>;\n};\n\nexport default Frame;\n","import { useMemo } from 'react';\n\nimport type { Module } from '~/types';\nimport { baseModules, compile } from '~/utils';\n\n// Shared by `preview/client.tsx` and `dnd/renderer.tsx`, which both turn a\n// code string into a renderable component in exactly the same way. They used\n// to implement this separately, which is how the two paths drifted apart on\n// error handling (see #246).\n//\n// Returns `null` for empty code so a caller can tell \"nothing to render\"\n// apart from \"compiled, but failed\" — the latter is a Module carrying\n// `error`, which callers should surface rather than render as blank.\nexport const useCompiledModule = (\n code: string,\n modules?: Record<string, unknown>,\n): Module | null => {\n const mergedModules = useMemo(\n () => ({ ...baseModules, ...modules }),\n [modules],\n );\n\n return useMemo(() => {\n if (!code) {\n return null;\n }\n\n try {\n return compile(code, mergedModules);\n } catch (e) {\n return {\n exports: {},\n error: e instanceof Error ? e.message : 'Module transformation error',\n };\n }\n }, [code, mergedModules]);\n};\n","import { useCallback, useEffect, useState } from 'react';\n\nimport { generateTailwindCSSFromDOM } from '~/utils/tailwind';\n\n// Compiles the Tailwind classes found in rendered output and returns them as\n// a CSS string for the caller to inject as a `<style>` tag. Shared by\n// `preview/client.tsx` and `dnd/renderer.tsx`, which previously carried\n// byte-identical copies of this logic and of the comments below (see #246).\n//\n// Scans the live DOM (whatever the returned `ref` is attached to) rather than\n// the source text it was rendered from, so classes contributed by an imported\n// component (e.g. ui-kit's `Button`) are picked up too — those never appear as\n// literal text in the previewed source, only in that component's own compiled\n// output.\n//\n// The scanned element is tracked as state via a callback ref rather than a\n// plain `useRef`, because in shadow mode it isn't mounted on the caller's\n// first commit at all — `Shadow` creates its portal target in its own effect\n// and only re-renders with it afterwards, one commit later. A plain ref read\n// in a `[code, enabled]`-keyed effect would see `null` on that first pass and\n// never retry; making the element itself a dependency re-runs the scan once\n// it actually exists.\nexport const useDynamicTailwind = (code: string, enabled: boolean) => {\n const [css, setCss] = useState('');\n const [element, setElement] = useState<HTMLDivElement | null>(null);\n\n const ref = useCallback((node: HTMLDivElement | null) => {\n setElement(node);\n }, []);\n\n useEffect(() => {\n if (!code || !enabled || !element) {\n return;\n }\n\n let cancelled = false;\n\n generateTailwindCSSFromDOM(element).then(next => {\n if (!cancelled) {\n setCss(next);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [code, enabled, element]);\n\n return { ref, css };\n};\n"],"mappings":"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"}