@jbpark/live-editor 1.15.0 → 1.15.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.
package/dist/dnd/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as DraggableItem, t as Dnd } from "../dnd-BdNgmgYB.js";
1
+ import { n as DraggableItem, t as Dnd } from "../dnd-BRQKM3fk.js";
2
2
  export { DraggableItem, Dnd as default };
@@ -2,7 +2,7 @@ import { _ as DEFAULT_TEMPLATE, f as require_lib$1, m as BINDING_PROP, n as crea
2
2
  import { d as replaceSections, i as compile, o as extractSections, r as cn, s as generateSection, t as baseModules, u as preloadScripts } from "./utils-BzfDKU6y.js";
3
3
  import { i as usePreview } from "./states-Ci1AvoQ9.js";
4
4
  import { _ as parseArrayExpression, c as extract, d as getCurrentValue, f as parseBinding, g as extractObjectProperties, h as extractNodeValue, i as replaceIds, l as nanoid, m as createNodeFromValue, n as clone, o as update, p as arrayExpressionToCode, r as fillIds, t as validateBindingValue, u as findEditableChildren, v as parseValue, y as generateCode } from "./ast-Dq1EfxA5.js";
5
- import { t as Frame } from "./frame-C11nuIBH.js";
5
+ import { t as Frame } from "./frame-DQ_9RdeP.js";
6
6
  import { t as generateTailwindCSSFromDOM } from "./tailwind-CbjdLyVX.js";
7
7
  import { t as Core } from "./core-B7igZRDs.js";
8
8
  import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
@@ -1714,4 +1714,4 @@ Dnd.DraggableItem = DraggableItem;
1714
1714
  //#endregion
1715
1715
  export { DraggableItem as n, Dnd as t };
1716
1716
 
1717
- //# sourceMappingURL=dnd-BdNgmgYB.js.map
1717
+ //# sourceMappingURL=dnd-BRQKM3fk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dnd-BdNgmgYB.js","names":["Renderer","t","parseExpression","TiptapEditor","CoreEditor","Dnd","uuidv4","Renderer","DndImpl"],"sources":["../src/components/dnd/draggable.tsx","../src/components/dnd/droppable.tsx","../src/components/dnd/renderer.tsx","../src/components/dnd/sortable.tsx","../src/components/dnd/overlay.tsx","../src/components/editor/tiptap.tsx","../src/components/dnd/panel/selection.ts","../src/components/dnd/panel/items.tsx","../src/components/dnd/panel/children.tsx","../src/components/dnd/panel/icon-map.ts","../src/components/dnd/panel/field.tsx","../src/components/dnd/panel/node.tsx","../src/components/dnd/panel/panel.tsx","../src/components/dnd/dnd.tsx","../src/components/dnd/index.ts"],"sourcesContent":["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 renderPalette 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 { 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 { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { baseModules, compile } from '~/utils';\nimport { generateTailwindCSSFromDOM } from '~/utils/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 memoizedModules = useMemo(\n () => ({\n ...baseModules,\n ...modules,\n }),\n [modules],\n );\n\n const module = useMemo(() => {\n try {\n return compile(preview, memoizedModules);\n } catch (e) {\n return {\n exports: {},\n error: e instanceof Error ? e.message : 'Module transformation error',\n };\n }\n }, [preview, memoizedModules]);\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. Mirrors\n // `preview/client.tsx`'s `dynamicTailwind` handling: compile this\n // section's own Tailwind classes and portal them 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 //\n // Scans the actual rendered DOM (below) rather than the `preview` source\n // text, so classes contributed by an imported component (e.g. ui-kit's\n // `Button`) are picked up too — those never appear as literal text in\n // `preview`, only in the component's own compiled output.\n //\n // The wrapper below is tracked via a callback ref (`wrapperEl` state)\n // rather than a plain `useRef`, because in shadow mode it isn't mounted\n // on this component's first commit at all — `Shadow` creates its portal\n // target in its own effect and only re-renders with it afterwards, one\n // commit later. A plain ref read in a `[preview, dynamicTailwind]`-keyed\n // effect would see `null` on that first pass and never retry; making the\n // element itself a dependency re-runs the scan once it actually exists.\n const [dynamicCSS, setDynamicCSS] = useState('');\n const [wrapperEl, setWrapperEl] = useState<HTMLDivElement | null>(null);\n const wrapperRef = useCallback((el: HTMLDivElement | null) => {\n setWrapperEl(el);\n }, []);\n\n useEffect(() => {\n if (!preview || !dynamicTailwind || !wrapperEl) {\n return;\n }\n\n let cancelled = false;\n\n generateTailwindCSSFromDOM(wrapperEl).then(css => {\n if (!cancelled) {\n setDynamicCSS(css);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [preview, dynamicTailwind, wrapperEl]);\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\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 {renderProvider(\n <>\n <Component\n headers={headers}\n container={container}\n //\n />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </>,\n )}\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 { useEffect } from 'react';\n\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\n\nimport { cn } from '~/utils';\n\nexport interface Props {\n value?: string;\n placeholder?: string;\n className?: string;\n onChange?: (value: string) => void;\n}\n\nconst Tiptap = ({\n value = '',\n placeholder = 'Enter text...',\n className,\n onChange,\n}: Props) => {\n const editor = useEditor({\n extensions: [StarterKit, Placeholder.configure({ placeholder })],\n content: value,\n onBlur: ({ editor: e }) => {\n onChange?.(e.getHTML());\n },\n });\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n const current = editor.getHTML();\n\n if (current !== value) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n }, [value, editor]);\n\n return (\n <EditorContent\n editor={editor}\n className={cn(\n `tiptap-editor min-h-20 rounded border border-gray-200 bg-white px-3\n py-2`,\n 'prose prose-sm max-w-none text-sm text-gray-800',\n '[&_.tiptap]:outline-none',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:float-left',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:h-0',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]',\n className,\n )}\n />\n );\n};\n\nexport default Tiptap;\n","export const removeIndices = <T>(items: T[], indices: Set<number>): T[] => {\n return items.filter((_, index) => !indices.has(index));\n};\n\n/**\n * Shifts every selected index up/down by one step as a block, preserving\n * relative order — scattered selections stop moving individually once they\n * hit an unselected neighbor, so the whole group slides together instead of\n * items passing through each other.\n */\nexport const moveSelectedIndices = <T>(\n items: T[],\n indices: Set<number>,\n direction: 'up' | 'down',\n): { items: T[]; indices: Set<number> } => {\n const next = [...items];\n const nextIndices = new Set(indices);\n\n const ordered = [...indices].sort((a, b) =>\n direction === 'up' ? a - b : b - a,\n );\n\n for (const index of ordered) {\n const target = direction === 'up' ? index - 1 : index + 1;\n\n if (target < 0 || target >= next.length || nextIndices.has(target)) {\n continue;\n }\n\n [next[index], next[target]] = [next[target]!, next[index]!];\n nextIndices.delete(index);\n nextIndices.add(target);\n }\n\n return { items: next, indices: nextIndices };\n};\n","import { useEffect, useMemo } from 'react';\n\nimport { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { Button, Checkbox, Toast } from '@jbpark/ui-kit';\nimport { useMultiSelect } from '@jbpark/use-hooks';\nimport { ArrowDown, ArrowUp, Copy, Plus, X } from 'lucide-react';\nimport { nanoid } from 'nanoid';\n\nimport { BINDING_PROP } from '~/constants';\nimport {\n type BindingRenderLeaf,\n type BindingRenderMap,\n type DataAttrNode,\n type ExtractedNodeValue,\n type NodeValueType,\n arrayExpressionToCode,\n clone,\n createNodeFromValue,\n extract,\n extractNodeValue,\n extractObjectProperties,\n findEditableChildren,\n generateCode,\n parseArrayExpression,\n parseValue,\n} from '~/utils/ast';\n\nimport Field from './field';\nimport Node from './node';\nimport { moveSelectedIndices, removeIndices } from './selection';\n\ninterface ItemProperty extends ExtractedNodeValue {\n astNode: t.Node;\n}\n\ninterface ItemData {\n id: string;\n index: number;\n editableProperties: Record<string, ItemProperty>;\n originalElement: t.ObjectExpression;\n jsxBindings: Record<string, DataAttrNode[]>;\n}\n\ninterface PrimitiveItem {\n id: string;\n index: number;\n value: string | number | boolean | null;\n type: NodeValueType;\n astNode: t.Expression;\n}\n\ninterface Props {\n value: string;\n render?: BindingRenderMap;\n onChange?: (value: string) => void;\n onChildChange?: (params: {\n id: string;\n label: string;\n value: string;\n }) => void;\n}\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\nconst Items = ({ value, render, onChange, onChildChange }: Props) => {\n const { objectItems, primitiveItems, allElements, parseError } =\n useMemo(() => {\n const ast = parseArrayExpression(value);\n\n if (!ast) {\n return {\n objectItems: [],\n primitiveItems: [],\n allElements: [],\n parseError: true,\n };\n }\n\n const objectItems: ItemData[] = [];\n const primitiveItems: PrimitiveItem[] = [];\n const allElements = ast.elements.filter(Boolean) as t.Expression[];\n\n ast.elements.forEach(element => {\n if (!element) {\n return;\n }\n\n if (!t.isObjectExpression(element)) {\n const extracted = extractNodeValue(element);\n primitiveItems.push({\n id: nanoid(6),\n index: primitiveItems.length,\n value: extracted.value,\n type: extracted.type,\n astNode: element as t.Expression,\n });\n return;\n }\n\n const jsxBindings: Record<string, DataAttrNode[]> = {};\n\n element.properties.forEach(prop => {\n if (\n !t.isObjectProperty(prop) ||\n !t.isIdentifier(prop.key) ||\n !t.isJSXElement(prop.value)\n ) {\n return;\n }\n\n const propertyName = prop.key.name;\n\n try {\n const jsxCode = generateCode(prop.value);\n const nodes = extract(jsxCode);\n const bindings: DataAttrNode[] = [];\n\n const bindingContainer = nodes.find(node =>\n node.bindings?.some(b => b.property === 'children'),\n );\n\n if (bindingContainer) {\n bindings.push(bindingContainer);\n } else {\n nodes.forEach(node => {\n if (\n node.bindings &&\n node.bindings.length > 0 &&\n node.dataAttributes.some(a => a.name === 'data-id')\n ) {\n bindings.push(node);\n }\n const editableChildren = findEditableChildren(node);\n bindings.push(...editableChildren);\n });\n }\n\n if (bindings.length > 0) {\n jsxBindings[propertyName] = bindings;\n }\n } catch (error) {\n console.error(\n `Failed to parse JSX in property '${propertyName}':`,\n error,\n );\n }\n });\n\n objectItems.push({\n id: nanoid(6),\n index: objectItems.length,\n editableProperties: extractObjectProperties(element),\n originalElement: element,\n jsxBindings,\n });\n });\n\n return { objectItems, primitiveItems, allElements, parseError: false };\n }, [value]);\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 isPrimitive = primitiveItems.length > 0 && objectItems.length === 0;\n\n const selection = useMultiSelect(\n isPrimitive ? primitiveItems.length : objectItems.length,\n );\n\n const updatePrimitive = (index: number, next: string) => {\n const ast = parseArrayExpression(value);\n\n if (!ast) {\n Toast.error('Failed to update this item', {\n description: 'Check the console for details.',\n });\n return;\n }\n\n const elements = ast.elements.filter(Boolean) as t.Expression[];\n const item = primitiveItems.find(p => p.index === index);\n\n if (!item) {\n return;\n }\n\n const newNode = createNodeFromValue(item.type, parseValue(next));\n\n if (!newNode) {\n return;\n }\n\n elements[index] = newNode;\n\n onChange?.(generateCode(t.arrayExpression(elements)));\n };\n\n const movePrimitive = (fromIndex: number, toIndex: number) => {\n const nextElements = [...allElements];\n const [moved] = nextElements.splice(fromIndex, 1);\n\n nextElements.splice(toIndex, 0, moved!);\n onChange?.(generateCode(t.arrayExpression(nextElements)));\n };\n\n const deleteSelectedPrimitives = (indices: Set<number>) => {\n if (allElements.length - indices.size < 1) {\n return;\n }\n\n const nextElements = removeIndices(allElements, indices);\n\n onChange?.(generateCode(t.arrayExpression(nextElements)));\n };\n\n const deletePrimitive = (index: number) =>\n deleteSelectedPrimitives(new Set([index]));\n\n const addPrimitive = () => {\n const first = primitiveItems[0];\n\n if (!first) {\n return;\n }\n\n const newNode = createNodeFromValue(first.type, first.value);\n\n if (!newNode) {\n return;\n }\n\n onChange?.(generateCode(t.arrayExpression([...allElements, newNode])));\n };\n\n const duplicateSelectedPrimitives = (indices: Set<number>) => {\n const clones = [...indices]\n .sort((a, b) => a - b)\n .map(index => allElements[index])\n .filter((node): node is t.Expression => Boolean(node))\n .map(node => clone(node) as t.Expression);\n\n if (clones.length === 0) {\n return;\n }\n\n onChange?.(generateCode(t.arrayExpression([...allElements, ...clones])));\n };\n\n const moveSelectedPrimitives = (\n indices: Set<number>,\n direction: 'up' | 'down',\n ) => {\n const { items: nextElements, indices: nextIndices } = moveSelectedIndices(\n allElements,\n indices,\n direction,\n );\n\n selection.replace(nextIndices);\n onChange?.(generateCode(t.arrayExpression(nextElements)));\n };\n\n const moveItem = (fromIndex: number, toIndex: number) => {\n const nextItems = [...objectItems];\n const [movedItem] = nextItems.splice(fromIndex, 1);\n nextItems.splice(toIndex, 0, movedItem!);\n\n const nextValue = arrayExpressionToCode(\n nextItems.map(item => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n const updateProperty = (\n itemIndex: number,\n propertyKey: string,\n value: unknown,\n ) => {\n const item = objectItems[itemIndex]!;\n const property = item.editableProperties[propertyKey]!;\n\n const renderLeaf =\n render?.[propertyKey] && 'type' in render[propertyKey]\n ? (render[propertyKey] as BindingRenderLeaf)\n : null;\n\n const isJsx = renderLeaf?.type === 'jsx';\n const isInnerHTML = renderLeaf?.property === BINDING_PROP.INNER_HTML;\n let nextAstValue: t.Expression | null = null;\n\n if (isInnerHTML) {\n const str = String(value);\n nextAstValue = t.templateLiteral(\n [t.templateElement({ raw: str, cooked: str }, true)],\n [],\n );\n } else if (property.type === 'array' || property.type === 'object') {\n try {\n nextAstValue = parseExpression(String(value), {\n plugins: ['jsx', 'typescript'],\n });\n } catch {\n return;\n }\n } else if (!isJsx) {\n nextAstValue = createNodeFromValue(property.type, value);\n }\n\n if (!isJsx && !nextAstValue) {\n return;\n }\n\n const objectExpression = item.originalElement;\n const targetProperty = objectExpression.properties.find(\n (prop: t.ObjectProperty | t.ObjectMethod | t.SpreadElement) =>\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key) &&\n prop.key.name === propertyKey,\n ) as t.ObjectProperty;\n\n const jsxPlaceholders = new Map<string, string>();\n const originalValues = new Map<t.ObjectProperty, t.Expression>();\n\n if (isJsx && targetProperty) {\n const trimmed = String(value).trim();\n if (trimmed.startsWith('<')) {\n const placeholder = `__JSX_${nanoid(6)}__`;\n jsxPlaceholders.set(placeholder, trimmed);\n targetProperty.value = t.identifier(placeholder);\n } else {\n targetProperty.value = t.stringLiteral(trimmed);\n }\n } else if (targetProperty && nextAstValue) {\n targetProperty.value = nextAstValue;\n }\n\n objectItems.forEach(obj => {\n obj.originalElement.properties.forEach(prop => {\n if (!t.isObjectProperty(prop) || !t.isIdentifier(prop.key)) {\n return;\n }\n\n if (t.isJSXElement(prop.value) || t.isJSXFragment(prop.value)) {\n const placeholder = `__JSX_${nanoid(6)}__`;\n jsxPlaceholders.set(placeholder, generateCode(prop.value));\n originalValues.set(prop, prop.value);\n prop.value = t.identifier(placeholder);\n }\n });\n });\n\n let nextValue = arrayExpressionToCode(\n objectItems.map(item => item.originalElement),\n );\n\n for (const [prop, original] of originalValues) {\n prop.value = original;\n }\n\n for (const [placeholder, code] of jsxPlaceholders) {\n // 두 번째 인자가 문자열이면 $&, $$ 같은 특수 치환 패턴으로 해석되어\n // code 안에 그런 문자가 있으면 결과가 깨진다 — 함수형 치환자로 방지.\n nextValue = nextValue.replace(placeholder, () => code);\n }\n\n onChange?.(nextValue);\n };\n\n const deleteSelectedItems = (indices: Set<number>) => {\n if (objectItems.length - indices.size < 1) {\n return;\n }\n\n const nextItems = removeIndices(objectItems, indices);\n const nextValue = arrayExpressionToCode(\n nextItems.map((item: ItemData) => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n const deleteItem = (index: number) => deleteSelectedItems(new Set([index]));\n\n const cloneObjectItemElement = (source: ItemData): t.ObjectExpression => {\n const clonedElement = clone(source.originalElement) as t.ObjectExpression;\n\n clonedElement.properties.forEach(prop => {\n if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {\n const key = prop.key.name;\n const editableProp = source.editableProperties[key];\n\n if (key === 'key' && t.isStringLiteral(prop.value)) {\n const originalKey = prop.value.value;\n const uniqueKey = `${originalKey}-${nanoid(6)}`;\n prop.value = t.stringLiteral(uniqueKey);\n return;\n }\n\n if (editableProp) {\n const nextValue = createNodeFromValue(\n editableProp.type,\n editableProp.value,\n );\n\n if (nextValue) {\n prop.value = nextValue;\n }\n }\n }\n });\n\n return clonedElement;\n };\n\n const addItem = () => {\n const firstItem = objectItems[0];\n\n if (!firstItem) {\n return;\n }\n\n const clonedElement = cloneObjectItemElement(firstItem);\n const editableProperties = extractObjectProperties(clonedElement);\n\n const nextItems = [...objectItems];\n const newItemData: ItemData = {\n id: nanoid(6),\n index: nextItems.length,\n editableProperties,\n originalElement: clonedElement,\n jsxBindings: {},\n };\n\n nextItems.push(newItemData);\n\n const nextValue = arrayExpressionToCode(\n nextItems.map(item => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n const duplicateSelectedItems = (indices: Set<number>) => {\n const sources = [...indices]\n .sort((a, b) => a - b)\n .map(index => objectItems[index])\n .filter((item): item is ItemData => Boolean(item));\n\n if (sources.length === 0) {\n return;\n }\n\n const clonedElements = sources.map(cloneObjectItemElement);\n const nextValue = arrayExpressionToCode([\n ...objectItems.map(item => item.originalElement),\n ...clonedElements,\n ]);\n\n onChange?.(nextValue);\n };\n\n const moveSelectedItems = (\n indices: Set<number>,\n direction: 'up' | 'down',\n ) => {\n const { items: nextItems, indices: nextIndices } = moveSelectedIndices(\n objectItems,\n indices,\n direction,\n );\n\n selection.replace(nextIndices);\n\n const nextValue = arrayExpressionToCode(\n nextItems.map(item => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n if (isPrimitive) {\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold\">\n Items ({primitiveItems.length})\n </div>\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n onClick={addPrimitive}\n >\n Add Item\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={() => duplicateSelectedPrimitives(selection.selected)}\n onMoveUp={() => moveSelectedPrimitives(selection.selected, 'up')}\n onMoveDown={() => moveSelectedPrimitives(selection.selected, 'down')}\n onDelete={() => {\n deleteSelectedPrimitives(selection.selected);\n selection.clear();\n }}\n onClear={selection.clear}\n />\n\n {primitiveItems.map((item, i) => (\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 <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={i === 0}\n onClick={() => movePrimitive(item.index, item.index - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={i === primitiveItems.length - 1}\n onClick={() => movePrimitive(item.index, item.index + 1)}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n disabled={primitiveItems.length <= 1}\n onClick={() => deletePrimitive(item.index)}\n />\n </div>\n </div>\n <Field\n binding={{\n label: `item-${i}`,\n property: item.type,\n }}\n id={`primitive-${item.id}`}\n value={String(item.value ?? '')}\n onChange={({ value: next }) => updatePrimitive(item.index, next)}\n />\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\">\n Items ({objectItems.length})\n </div>\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n disabled={objectItems.length === 0}\n onClick={addItem}\n >\n Add Item\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={() => duplicateSelectedItems(selection.selected)}\n onMoveUp={() => moveSelectedItems(selection.selected, 'up')}\n onMoveDown={() => moveSelectedItems(selection.selected, 'down')}\n onDelete={() => {\n deleteSelectedItems(selection.selected);\n selection.clear();\n }}\n onClear={selection.clear}\n />\n\n {objectItems.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 <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={item.index === 0}\n onClick={() => moveItem(item.index, item.index - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={item.index === objectItems.length - 1}\n onClick={() => moveItem(item.index, item.index + 1)}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n disabled={objectItems.length <= 1}\n onClick={() => deleteItem(item.index)}\n />\n </div>\n </div>\n <div className=\"space-y-2\">\n {Object.entries(item.editableProperties).map(([key, prop]) => (\n <div key={`${item.id}-${key}`}>\n <div className=\"flex flex-col space-y-2\">\n <label className=\"w-20 shrink-0 text-xs font-medium\">\n {key}\n </label>\n <Field\n binding={{\n label: key,\n property:\n render?.[key] && 'type' in render[key]\n ? ((render[key] as BindingRenderLeaf).property ??\n (render[key].type as string))\n : key,\n type:\n render?.[key] && 'type' in render[key]\n ? (render[key] as BindingRenderLeaf).type\n : undefined,\n render:\n render?.[key] && 'type' in render[key]\n ? (render[key] as BindingRenderLeaf).render\n : render?.[key] && !('type' in render[key])\n ? (render[key] as BindingRenderMap)\n : undefined,\n }}\n id={`item-${item.id}-${key}`}\n value={String(prop.value)}\n onChange={({ value: next }) =>\n updateProperty(item.index, key, parseValue(next))\n }\n />\n </div>\n <span className=\"text-right text-xs text-gray-500\">\n ({prop.type})\n </span>\n </div>\n ))}\n </div>\n <div className=\"space-y-3 border-t pt-2\">\n {Object.entries(item.jsxBindings).length > 0 ? (\n Object.entries(item.jsxBindings).map(\n ([propertyName, bindings]) => (\n <div key={propertyName} className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {propertyName} Bindings ({bindings.length}):\n </div>\n {bindings.map((bindingNode, idx) => {\n const nodeId = bindingNode.dataAttributes.find(\n a => a.name === 'data-id',\n )?.value;\n\n return (\n <div\n key={`binding-${item.id}-${propertyName}-${nodeId || idx}`}\n className=\"rounded border border-blue-100 bg-blue-50\n p-2\"\n >\n <div className=\"mb-1 text-xs text-blue-600\">\n &lt;{bindingNode.tagName || 'element'}&gt;\n </div>\n <Node data={bindingNode} onChange={onChildChange} />\n </div>\n );\n })}\n </div>\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;\nexport { BulkActionsBar };\n","import { useMemo } from 'react';\n\nimport { Button, Checkbox } from '@jbpark/ui-kit';\nimport { useMultiSelect } from '@jbpark/use-hooks';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\nimport { nanoid } from 'nanoid';\n\nimport { type DataAttrNode, findEditableChildren } from '~/utils/ast';\n\nimport { BulkActionsBar } from './items';\nimport Node from './node';\nimport { moveSelectedIndices, removeIndices } from './selection';\n\ninterface Props {\n value: DataAttrNode[];\n onChange?: (value: string) => void;\n onNodeChange?: (params: { id: string; label: string; value: string }) => void;\n}\n\nconst Children = ({ value, onChange, onNodeChange }: Props) => {\n const items = useMemo(() => (Array.isArray(value) ? value : []), [value]);\n\n const selection = useMultiSelect(items.length);\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 const moveItem = (fromIndex: number, toIndex: number) => {\n const nextItems = [...items];\n const [movedItem] = nextItems.splice(fromIndex, 1);\n nextItems.splice(toIndex, 0, movedItem!);\n\n onChange?.(JSON.stringify(nextItems));\n };\n\n const moveSelectedItems = (\n indices: Set<number>,\n direction: 'up' | 'down',\n ) => {\n const { items: nextItems, indices: nextIndices } = moveSelectedIndices(\n items,\n indices,\n direction,\n );\n\n selection.replace(nextIndices);\n onChange?.(JSON.stringify(nextItems));\n };\n\n const deleteSelectedItems = (indices: Set<number>) => {\n if (items.length - indices.size < 1) {\n return;\n }\n\n const nextItems = removeIndices(items, indices);\n onChange?.(JSON.stringify(nextItems));\n };\n\n const deleteItem = (index: number) => deleteSelectedItems(new Set([index]));\n\n const addItem = () => {\n const template = items[0] || createDefaultItem();\n const newItem = cloneDataAttrNode(template);\n\n const nextItems = [...items, newItem];\n onChange?.(JSON.stringify(nextItems));\n };\n\n const duplicateSelectedItems = (indices: Set<number>) => {\n const sources = [...indices]\n .sort((a, b) => a - b)\n .map(index => items[index])\n .filter((item): item is DataAttrNode => Boolean(item));\n\n if (sources.length === 0) {\n return;\n }\n\n const clones = sources.map(cloneDataAttrNode);\n onChange?.(JSON.stringify([...items, ...clones]));\n };\n\n const createDefaultItem = (): DataAttrNode => ({\n id: nanoid(6),\n tagName: 'div',\n attributes: [\n { name: 'data-id', value: nanoid(6) },\n { name: 'data-item', value: 'true' },\n ],\n dataAttributes: [\n { name: 'data-id', value: nanoid(6) },\n { name: 'data-item', value: 'true' },\n ],\n textContent: '',\n children: [],\n });\n\n const cloneDataAttrNode = (node: DataAttrNode): DataAttrNode => ({\n ...node,\n id: nanoid(6),\n attributes: node.attributes.map(attr => ({\n ...attr,\n value: attr.name === 'data-id' ? nanoid(6) : attr.value,\n })),\n dataAttributes: node.dataAttributes.map(attr => ({\n ...attr,\n value: attr.name === 'data-id' ? nanoid(6) : attr.value,\n })),\n children: node.children?.map(cloneDataAttrNode),\n });\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 size=\"small\" color=\"green\" icon={<Plus />} onClick={addItem}>\n Add Child\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={() => duplicateSelectedItems(selection.selected)}\n onMoveUp={() => moveSelectedItems(selection.selected, 'up')}\n onMoveDown={() => moveSelectedItems(selection.selected, 'down')}\n onDelete={() => {\n deleteSelectedItems(selection.selected);\n selection.clear();\n }}\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={() => moveItem(itemIndex, itemIndex - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={itemIndex === items.length - 1}\n onClick={() => moveItem(itemIndex, itemIndex + 1)}\n />\n <Button\n title={\n items.length <= 1\n ? 'At least 1 item is required'\n : 'Delete item'\n }\n danger\n size=\"small\"\n icon={<X />}\n disabled={items.length <= 1}\n onClick={() => deleteItem(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-${itemIndex}-${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","import { useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n Checkbox,\n ColorPicker,\n DatePicker,\n Input,\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 TiptapEditor from '~/components/editor/tiptap';\nimport { BINDING_PROP } from '~/constants';\nimport {\n type BindingItem,\n parseValue,\n validateBindingValue,\n} from '~/utils/ast';\n\nimport Children from './children';\nimport { ICON_MAP } from './icon-map';\nimport Items from './items';\n\ninterface Props {\n binding: BindingItem;\n id: string;\n value: string;\n onChange?: (params: { id: string; label: string; value: string }) => void;\n}\n\ninterface Props {\n binding: BindingItem;\n id: string;\n value: string;\n onChange?: (params: { id: string; label: string; value: string }) => void;\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\ninterface ColorPickerFieldProps {\n id: string;\n label: string;\n value: string;\n onChange?: (params: { id: string; label: string; value: string }) => void;\n}\n\nconst ColorPickerField = ({\n id,\n label,\n value,\n onChange,\n}: 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?.({ id, label, value: 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 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\nconst Field = ({ binding, id, value, onChange }: Props) => {\n const parsedValue = useMemo(() => {\n return parseValue(value);\n }, [value]);\n\n const [validationError, setValidationError] = useState<string | null>(null);\n\n if (\n binding.property === 'items' ||\n binding.property === 'data' ||\n binding.type === 'array'\n ) {\n return (\n <Items\n value={value}\n render={binding.render}\n onChange={next => {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\n }}\n onChildChange={onChange}\n />\n );\n }\n\n if (binding.type === 'richtext') {\n return (\n <TiptapEditor\n value={value}\n onChange={next => {\n if (next !== value) {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\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={value}\n height=\"150px\"\n fragment={!isHTML}\n raw={isHTML}\n onSave={next => {\n if (next !== value) {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\n }\n }}\n />\n );\n }\n\n if (binding.property === 'children' && Array.isArray(parsedValue)) {\n return (\n <Children\n value={parsedValue}\n onChange={next => {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\n }}\n onNodeChange={onChange}\n />\n );\n }\n\n if (\n typeof parsedValue === 'object' &&\n parsedValue !== null &&\n !Array.isArray(parsedValue)\n ) {\n return (\n <div className=\"space-y-2 rounded border border-gray-200 bg-gray-50 p-2\">\n {Object.entries(parsedValue).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 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: BindingItem['type'] })\n .type\n : undefined,\n render:\n binding.render?.[key] && !('type' in binding.render[key])\n ? (binding.render[key] as BindingItem['render'])\n : undefined,\n }}\n id={id}\n value={\n typeof val === 'object' ? JSON.stringify(val) : String(val)\n }\n onChange={({ value: next }) => {\n const convertedValue = parseValue(next);\n\n const updated = {\n ...parsedValue,\n [key]: convertedValue,\n };\n\n onChange?.({\n id,\n label: binding.label,\n value: JSON.stringify(updated),\n });\n }}\n />\n </div>\n ))}\n </div>\n );\n }\n\n if (binding.type === 'boolean' || typeof parsedValue === 'boolean') {\n return (\n <Checkbox\n checked={parsedValue === true || parsedValue === 'true'}\n onChange={checked => {\n onChange?.({\n id,\n label: binding.label,\n value: checked.toString(),\n });\n }}\n />\n );\n }\n\n const stringValue = String(value);\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?.({\n id,\n label: binding.label,\n value: next,\n });\n }\n }}\n />\n );\n }\n\n if (binding.type === 'color' || isColorProperty(binding.property)) {\n return (\n <ColorPickerField\n id={id}\n label={binding.label}\n value={normalizeToHex(stringValue)}\n onChange={onChange}\n />\n );\n }\n\n if (binding.type === 'date') {\n return (\n <div>\n <DatePicker\n defaultValue={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?.({\n id,\n label: binding.label,\n value: next,\n });\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 defaultValue={stringValue}\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 === '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?.({\n id,\n label: binding.label,\n value: next,\n });\n }\n }}\n />\n {SelectedIcon && <SelectedIcon size={18} className=\"shrink-0\" />}\n </div>\n );\n }\n\n if (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 defaultValue={stringValue}\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?.({\n id,\n label: binding.label,\n value: next,\n });\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 (typeof parsedValue === 'number') {\n return (\n <div>\n <Input\n type=\"number\"\n defaultValue={stringValue}\n placeholder=\"Enter a numeric value\"\n onBlur={e => {\n const next = e.target.value.trim();\n const result = validateBindingValue(\n binding,\n next ? Number(next) : '',\n );\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 defaultValue={value}\n placeholder=\"Enter a value\"\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 DataAttrNode, getCurrentValue, parseBinding } from '~/utils/ast';\n\nimport Field from './field';\n\nexport interface FieldEditorProps {\n data: DataAttrNode;\n onChange?: (params: { id: string; label: string; value: string }) => 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\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 id={dataId}\n binding={binding}\n value={currentValue}\n onChange={onChange}\n />\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default Node;\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';\nimport type { DataAttrNode } from '~/utils/ast';\n\nimport Node from './node';\n\ninterface Props {\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 data-binding fields — extraction (and the AST\n // update + error-toast handling behind onFieldChange) lives in Dnd, so\n // it's shared with a custom renderPanel instead of computed here too.\n fields: DataAttrNode[];\n onFieldChange: (params: { id: string; label: string; value: string }) => void;\n}\n\nconst Panel = ({\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp = false,\n canMoveDown = false,\n fields,\n onFieldChange,\n}: Props) => {\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 {!fields.length && (\n <Typography.Text className=\"text-xs text-gray-400\">\n No editable elements.\n </Typography.Text>\n )}\n {fields.map((node, index) => (\n <Node\n key={`${item.id}-${index}`}\n data={node}\n onChange={onFieldChange}\n />\n ))}\n </div>\n );\n};\n\nexport default Panel;\n","import { 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 arrayMove,\n verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { Button, Drawer, Space, Toast, Typography } from '@jbpark/ui-kit';\nimport { useResponsiveSize } from '@jbpark/use-hooks';\nimport { LayoutGrid } from 'lucide-react';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { DRAGGABLE_ITEMS } from '~/constants';\nimport type { Section } from '~/types';\nimport {\n type BindingOption,\n type BindingType,\n type DataAttrNode,\n extract,\n fillIds,\n getCurrentValue,\n parseBinding,\n replaceIds,\n update,\n} from '~/utils/ast';\n\nimport { DEFAULT_TEMPLATE } from '../../constants';\nimport {\n cn,\n createSectionPreviewCache,\n extractSections,\n preloadScripts,\n replaceSections,\n} from '../../utils';\nimport { usePreview } from '../context/states';\nimport { type FrameProps } from '../frame';\nimport DraggableItem, { DefaultDraggableItem } from './draggable';\nimport Droppable from './droppable';\nimport Overlay from './overlay';\nimport Panel from './panel';\nimport Renderer from './renderer';\nimport Sortable from './sortable';\n\nexport interface PaletteRenderData {\n items: Section[];\n onAdd: (item: Section) => void;\n DraggableItem: typeof DraggableItem;\n // True when the palette is rendering inside the mobile Drawer, where a\n // tap can't be a failed drag attempt (there's nothing to drag onto —\n // the canvas is stacked behind the Drawer) and native dblclick synthesis\n // from double-tap is unreliable on touch. Custom renderPalette\n // implementations should treat a single click/tap as \"add\" here instead\n // of relying on onDoubleClick.\n isMobile: boolean;\n}\n\nexport interface PanelRenderData {\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 this 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}\n\n// One editable data-binding, flattened out of the selected section for a\n// custom renderPanel. 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 // Present when the binding defines a fixed option set (render a <select>).\n options?: BindingOption[];\n // Current serialized value — the same string the built-in field receives.\n value: 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).\n onChange: (value: string) => 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 // Full replacements for the built-in left palette / right panel — receive\n // the same data/callbacks Dnd itself uses, so drag-and-drop and field\n // editing keep working exactly as before, just with custom markup. Used\n // for both the desktop layout and the mobile drawer, since those already\n // render identical content today.\n renderPalette?: (data: PaletteRenderData) => React.ReactNode;\n renderPanel?: (data: PanelRenderData) => 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 renderPalette,\n renderPanel,\n ...restProps\n}: Props) => {\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);\n\n const { breakpoint } = useResponsiveSize();\n const isMobile = breakpoint.current === 'xs' || breakpoint.current === 'sm';\n\n const { setCode } = usePreview();\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 10,\n },\n }),\n );\n\n const value = _value || DEFAULT_TEMPLATE;\n const sections = useMemo(() => extractSections(value), [value]);\n const selectedItem = useMemo(\n () => sections.find(s => s.id === selectedId),\n [sections, selectedId],\n );\n\n // One cache per Dnd 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\n // that didn't change), which a `useMemo`/`useRef` can't do without\n // touching a ref during render; a cache object stored via `useState`\n // and only ever mutated through its own method isn't subject to that\n // restriction the way `ref.current` is.\n const [previewCache] = useState(() => createSectionPreviewCache());\n const previews = useMemo(\n () => previewCache.compute(value, sections),\n [previewCache, sections, value],\n );\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 newItem = active.data.current.item;\n const newSection = {\n id: uuidv4(),\n name: newItem.name,\n code: newItem.code,\n };\n\n let nextSections: typeof sections;\n\n if (over.id === 'sortable-area' || over.id === 'sortable-area-bottom') {\n nextSections = [...sections, newSection];\n } else {\n const overIndex = sections.findIndex(s => s.id === over.id);\n if (overIndex >= 0) {\n nextSections = [\n ...sections.slice(0, overIndex),\n newSection,\n ...sections.slice(overIndex),\n ];\n } else {\n nextSections = [...sections, newSection];\n }\n }\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n return;\n }\n\n if (active.id !== over.id && sections.some(s => s.id === active.id)) {\n const prevIndex = sections.findIndex(s => s.id === active.id);\n const nextIndex = sections.findIndex(s => s.id === over.id);\n\n if (prevIndex >= 0 && nextIndex >= 0) {\n const nextSections = arrayMove(sections, prevIndex, nextIndex);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n }\n }\n };\n\n const addItem = (item: (typeof DRAGGABLE_ITEMS)[0]) => {\n const newSection = {\n id: uuidv4(),\n name: item.name,\n code: item.code,\n };\n\n const nextSections = [...sections, newSection];\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n };\n\n const onDelete = (id: string) => {\n const nextSections = sections.filter(s => s.id !== id);\n\n setSelectedId(null);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n };\n\n const moveSection = (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 const nextSections = arrayMove(sections, index, targetIndex);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n // Section ids are just the section's positional index, re-derived from\n // scratch on every parse (getSections) rather than a stable identity —\n // so once `sections` recomputes after this reorder, `selectedId`\n // (unchanged) would silently point at whatever content now sits at its\n // old position instead of following the section that actually moved.\n setSelectedId(String(targetIndex));\n };\n\n const onCopy = (id: string) => {\n const sectionIndex = sections.findIndex(s => s.id === id);\n const sectionToCopy = sections[sectionIndex];\n\n if (sectionToCopy) {\n const nextId = uuidv4();\n const nextSection = {\n id: nextId,\n code: replaceIds(sectionToCopy.code),\n name: sectionToCopy.name,\n };\n\n const nextSections = [\n ...sections.slice(0, sectionIndex + 1),\n nextSection,\n ...sections.slice(sectionIndex + 1),\n ];\n\n setSelectedId(nextId);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n }\n };\n\n const onSelect = (id: string) => {\n setSelectedId(prev => (prev === id ? null : id));\n };\n\n const onChange = (next: Partial<Section>) => {\n const nextSections = sections.map(s =>\n s.id === next.id ? { ...s, ...next } : s,\n );\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\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 renderPanel\n // get the same extraction/update pipeline instead of each 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 value: fieldValue,\n }: {\n id: string;\n label: string;\n value: string;\n }) => {\n const result = update(updatedCode, id, label, fieldValue);\n\n if (!result.success) {\n Toast.error('Failed to update this field', {\n description: 'Check the console for details.',\n });\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 PanelBinding per bound property — the same walk the built-in\n // FieldEditor/Node does internally (data-id + parsed data-binding +\n // current value), but handed to a custom renderPanel as plain data so it\n // can render its own controls. Kept in a useMemo keyed on `fields` alone;\n // `onFieldChange` closes over `updatedCode`/`selectedItem` but is stable\n // enough per render, and rebuilding on every render would defeat the memo\n // guarding renderPanel's children.\n const bindings = useMemo<PanelBinding[]>(() => {\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 options: binding.options,\n value: getCurrentValue(node, binding.property),\n onChange: (value: string) =>\n onFieldChange({ id: dataId, label: binding.label, value }),\n }));\n });\n // onFieldChange is intentionally omitted — it's recreated every render\n // but only ever called from a user event, so closing over the latest\n // one via the render that produced these bindings is fine.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fields]);\n\n useEffect(() => {\n if (frame?.scripts?.length) {\n preloadScripts(frame.scripts);\n }\n }, [frame?.scripts]);\n\n const renderPaletteItems = (\n onAdd: (item: Section) => void,\n forMobileDrawer = false,\n ) => {\n const paletteItems = items?.length ? items : DRAGGABLE_ITEMS;\n\n if (renderPalette) {\n return renderPalette({\n items: paletteItems,\n onAdd,\n DraggableItem,\n isMobile: forMobileDrawer,\n });\n }\n\n return (\n <Space orientation=\"vertical\" align=\"start\">\n {paletteItems.map(item => (\n <DefaultDraggableItem\n key={item.id}\n item={item}\n onAdd={onAdd}\n tapToAdd={forMobileDrawer}\n />\n ))}\n </Space>\n );\n };\n\n const renderPanelContent = () => {\n const selectedIndex = sections.findIndex(s => s.id === selectedId);\n const canMoveUp = selectedIndex > 0;\n const canMoveDown =\n selectedIndex >= 0 && selectedIndex < sections.length - 1;\n\n if (renderPanel) {\n return renderPanel({\n item: selectedItem,\n onChange,\n onDelete,\n onMoveUp: () => moveSection(selectedId, 'up'),\n onMoveDown: () => moveSection(selectedId, 'down'),\n canMoveUp,\n canMoveDown,\n bindings,\n });\n }\n\n return (\n <Panel\n item={selectedItem}\n onDelete={onDelete}\n onMoveUp={() => moveSection(selectedId, 'up')}\n onMoveDown={() => moveSection(selectedId, 'down')}\n canMoveUp={canMoveUp}\n canMoveDown={canMoveDown}\n fields={fields}\n onFieldChange={onFieldChange}\n />\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 w-full',\n className,\n //\n )}\n {...restProps}\n >\n <div className=\"hidden w-1/5 overflow-y-auto md:block\">\n <div className=\"h-full bg-gray-50 p-4\">\n {renderPaletteItems(addItem)}\n </div>\n </div>\n <div\n className={cn(\n 'relative',\n 'h-full w-full md:w-3/5',\n 'overflow-y-auto',\n //\n )}\n data-frame-container\n style={{\n isolation: 'isolate',\n contain: 'layout style',\n transform: 'translateZ(0)',\n }}\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>\n No sections available\n </Typography.Paragraph>\n <Typography.Text>\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 </div>\n <div className=\"hidden w-1/5 md:block\">{renderPanelContent()}</div>\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={() => setMobilePaletteOpen(true)}\n />\n <Drawer\n open={isMobile && mobilePaletteOpen}\n onClose={() => setMobilePaletteOpen(false)}\n direction=\"bottom\"\n size=\"large\"\n title=\"Components\"\n >\n {renderPaletteItems(item => {\n addItem(item);\n setMobilePaletteOpen(false);\n }, true)}\n </Drawer>\n <Drawer\n open={isMobile && Boolean(selectedId)}\n onClose={() => setSelectedId(null)}\n direction=\"bottom\"\n size=\"large\"\n title=\"Properties\"\n >\n {renderPanelContent()}\n </Drawer>\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 PaletteRenderData,\n type PanelBinding,\n type PanelRenderData,\n type Props,\n} from './dnd';\nimport DraggableItem, {\n type DraggableItemDragState,\n type DraggableItemProps,\n} from './draggable';\n\ntype DndComponent = typeof DndImpl & {\n DraggableItem: typeof DraggableItem;\n};\n\nconst Dnd = DndImpl as DndComponent;\n\nDnd.DraggableItem = DraggableItem;\n\nexport { DraggableItem };\nexport type {\n Props,\n PaletteRenderData,\n PanelRenderData,\n PanelBinding,\n DraggableItemProps,\n DraggableItemDragState,\n};\nexport default Dnd;\n"],"mappings":"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"}
1
+ {"version":3,"file":"dnd-BRQKM3fk.js","names":["Renderer","t","parseExpression","TiptapEditor","CoreEditor","Dnd","uuidv4","Renderer","DndImpl"],"sources":["../src/components/dnd/draggable.tsx","../src/components/dnd/droppable.tsx","../src/components/dnd/renderer.tsx","../src/components/dnd/sortable.tsx","../src/components/dnd/overlay.tsx","../src/components/editor/tiptap.tsx","../src/components/dnd/panel/selection.ts","../src/components/dnd/panel/items.tsx","../src/components/dnd/panel/children.tsx","../src/components/dnd/panel/icon-map.ts","../src/components/dnd/panel/field.tsx","../src/components/dnd/panel/node.tsx","../src/components/dnd/panel/panel.tsx","../src/components/dnd/dnd.tsx","../src/components/dnd/index.ts"],"sourcesContent":["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 renderPalette 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 { 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 { memo, useCallback, useEffect, useMemo, useState } from 'react';\n\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { baseModules, compile } from '~/utils';\nimport { generateTailwindCSSFromDOM } from '~/utils/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 memoizedModules = useMemo(\n () => ({\n ...baseModules,\n ...modules,\n }),\n [modules],\n );\n\n const module = useMemo(() => {\n try {\n return compile(preview, memoizedModules);\n } catch (e) {\n return {\n exports: {},\n error: e instanceof Error ? e.message : 'Module transformation error',\n };\n }\n }, [preview, memoizedModules]);\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. Mirrors\n // `preview/client.tsx`'s `dynamicTailwind` handling: compile this\n // section's own Tailwind classes and portal them 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 //\n // Scans the actual rendered DOM (below) rather than the `preview` source\n // text, so classes contributed by an imported component (e.g. ui-kit's\n // `Button`) are picked up too — those never appear as literal text in\n // `preview`, only in the component's own compiled output.\n //\n // The wrapper below is tracked via a callback ref (`wrapperEl` state)\n // rather than a plain `useRef`, because in shadow mode it isn't mounted\n // on this component's first commit at all — `Shadow` creates its portal\n // target in its own effect and only re-renders with it afterwards, one\n // commit later. A plain ref read in a `[preview, dynamicTailwind]`-keyed\n // effect would see `null` on that first pass and never retry; making the\n // element itself a dependency re-runs the scan once it actually exists.\n const [dynamicCSS, setDynamicCSS] = useState('');\n const [wrapperEl, setWrapperEl] = useState<HTMLDivElement | null>(null);\n const wrapperRef = useCallback((el: HTMLDivElement | null) => {\n setWrapperEl(el);\n }, []);\n\n useEffect(() => {\n if (!preview || !dynamicTailwind || !wrapperEl) {\n return;\n }\n\n let cancelled = false;\n\n generateTailwindCSSFromDOM(wrapperEl).then(css => {\n if (!cancelled) {\n setDynamicCSS(css);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [preview, dynamicTailwind, wrapperEl]);\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\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 {renderProvider(\n <>\n <Component\n headers={headers}\n container={container}\n //\n />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </>,\n )}\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 { useEffect } from 'react';\n\nimport Placeholder from '@tiptap/extension-placeholder';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\n\nimport { cn } from '~/utils';\n\nexport interface Props {\n value?: string;\n placeholder?: string;\n className?: string;\n onChange?: (value: string) => void;\n}\n\nconst Tiptap = ({\n value = '',\n placeholder = 'Enter text...',\n className,\n onChange,\n}: Props) => {\n const editor = useEditor({\n extensions: [StarterKit, Placeholder.configure({ placeholder })],\n content: value,\n onBlur: ({ editor: e }) => {\n onChange?.(e.getHTML());\n },\n });\n\n useEffect(() => {\n if (!editor) {\n return;\n }\n\n const current = editor.getHTML();\n\n if (current !== value) {\n editor.commands.setContent(value, { emitUpdate: false });\n }\n }, [value, editor]);\n\n return (\n <EditorContent\n editor={editor}\n className={cn(\n `tiptap-editor min-h-20 rounded border border-gray-200 bg-white px-3\n py-2`,\n 'prose prose-sm max-w-none text-sm text-gray-800',\n '[&_.tiptap]:outline-none',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:float-left',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:h-0',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400',\n '[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]',\n className,\n )}\n />\n );\n};\n\nexport default Tiptap;\n","export const removeIndices = <T>(items: T[], indices: Set<number>): T[] => {\n return items.filter((_, index) => !indices.has(index));\n};\n\n/**\n * Shifts every selected index up/down by one step as a block, preserving\n * relative order — scattered selections stop moving individually once they\n * hit an unselected neighbor, so the whole group slides together instead of\n * items passing through each other.\n */\nexport const moveSelectedIndices = <T>(\n items: T[],\n indices: Set<number>,\n direction: 'up' | 'down',\n): { items: T[]; indices: Set<number> } => {\n const next = [...items];\n const nextIndices = new Set(indices);\n\n const ordered = [...indices].sort((a, b) =>\n direction === 'up' ? a - b : b - a,\n );\n\n for (const index of ordered) {\n const target = direction === 'up' ? index - 1 : index + 1;\n\n if (target < 0 || target >= next.length || nextIndices.has(target)) {\n continue;\n }\n\n [next[index], next[target]] = [next[target]!, next[index]!];\n nextIndices.delete(index);\n nextIndices.add(target);\n }\n\n return { items: next, indices: nextIndices };\n};\n","import { useEffect, useMemo } from 'react';\n\nimport { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { Button, Checkbox, Toast } from '@jbpark/ui-kit';\nimport { useMultiSelect } from '@jbpark/use-hooks';\nimport { ArrowDown, ArrowUp, Copy, Plus, X } from 'lucide-react';\nimport { nanoid } from 'nanoid';\n\nimport { BINDING_PROP } from '~/constants';\nimport {\n type BindingRenderLeaf,\n type BindingRenderMap,\n type DataAttrNode,\n type ExtractedNodeValue,\n type NodeValueType,\n arrayExpressionToCode,\n clone,\n createNodeFromValue,\n extract,\n extractNodeValue,\n extractObjectProperties,\n findEditableChildren,\n generateCode,\n parseArrayExpression,\n parseValue,\n} from '~/utils/ast';\n\nimport Field from './field';\nimport Node from './node';\nimport { moveSelectedIndices, removeIndices } from './selection';\n\ninterface ItemProperty extends ExtractedNodeValue {\n astNode: t.Node;\n}\n\ninterface ItemData {\n id: string;\n index: number;\n editableProperties: Record<string, ItemProperty>;\n originalElement: t.ObjectExpression;\n jsxBindings: Record<string, DataAttrNode[]>;\n}\n\ninterface PrimitiveItem {\n id: string;\n index: number;\n value: string | number | boolean | null;\n type: NodeValueType;\n astNode: t.Expression;\n}\n\ninterface Props {\n value: string;\n render?: BindingRenderMap;\n onChange?: (value: string) => void;\n onChildChange?: (params: {\n id: string;\n label: string;\n value: string;\n }) => void;\n}\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\nconst Items = ({ value, render, onChange, onChildChange }: Props) => {\n const { objectItems, primitiveItems, allElements, parseError } =\n useMemo(() => {\n const ast = parseArrayExpression(value);\n\n if (!ast) {\n return {\n objectItems: [],\n primitiveItems: [],\n allElements: [],\n parseError: true,\n };\n }\n\n const objectItems: ItemData[] = [];\n const primitiveItems: PrimitiveItem[] = [];\n const allElements = ast.elements.filter(Boolean) as t.Expression[];\n\n ast.elements.forEach(element => {\n if (!element) {\n return;\n }\n\n if (!t.isObjectExpression(element)) {\n const extracted = extractNodeValue(element);\n primitiveItems.push({\n id: nanoid(6),\n index: primitiveItems.length,\n value: extracted.value,\n type: extracted.type,\n astNode: element as t.Expression,\n });\n return;\n }\n\n const jsxBindings: Record<string, DataAttrNode[]> = {};\n\n element.properties.forEach(prop => {\n if (\n !t.isObjectProperty(prop) ||\n !t.isIdentifier(prop.key) ||\n !t.isJSXElement(prop.value)\n ) {\n return;\n }\n\n const propertyName = prop.key.name;\n\n try {\n const jsxCode = generateCode(prop.value);\n const nodes = extract(jsxCode);\n const bindings: DataAttrNode[] = [];\n\n const bindingContainer = nodes.find(node =>\n node.bindings?.some(b => b.property === 'children'),\n );\n\n if (bindingContainer) {\n bindings.push(bindingContainer);\n } else {\n nodes.forEach(node => {\n if (\n node.bindings &&\n node.bindings.length > 0 &&\n node.dataAttributes.some(a => a.name === 'data-id')\n ) {\n bindings.push(node);\n }\n const editableChildren = findEditableChildren(node);\n bindings.push(...editableChildren);\n });\n }\n\n if (bindings.length > 0) {\n jsxBindings[propertyName] = bindings;\n }\n } catch (error) {\n console.error(\n `Failed to parse JSX in property '${propertyName}':`,\n error,\n );\n }\n });\n\n objectItems.push({\n id: nanoid(6),\n index: objectItems.length,\n editableProperties: extractObjectProperties(element),\n originalElement: element,\n jsxBindings,\n });\n });\n\n return { objectItems, primitiveItems, allElements, parseError: false };\n }, [value]);\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 isPrimitive = primitiveItems.length > 0 && objectItems.length === 0;\n\n const selection = useMultiSelect(\n isPrimitive ? primitiveItems.length : objectItems.length,\n );\n\n const updatePrimitive = (index: number, next: string) => {\n const ast = parseArrayExpression(value);\n\n if (!ast) {\n Toast.error('Failed to update this item', {\n description: 'Check the console for details.',\n });\n return;\n }\n\n const elements = ast.elements.filter(Boolean) as t.Expression[];\n const item = primitiveItems.find(p => p.index === index);\n\n if (!item) {\n return;\n }\n\n const newNode = createNodeFromValue(item.type, parseValue(next));\n\n if (!newNode) {\n return;\n }\n\n elements[index] = newNode;\n\n onChange?.(generateCode(t.arrayExpression(elements)));\n };\n\n const movePrimitive = (fromIndex: number, toIndex: number) => {\n const nextElements = [...allElements];\n const [moved] = nextElements.splice(fromIndex, 1);\n\n nextElements.splice(toIndex, 0, moved!);\n onChange?.(generateCode(t.arrayExpression(nextElements)));\n };\n\n const deleteSelectedPrimitives = (indices: Set<number>) => {\n if (allElements.length - indices.size < 1) {\n return;\n }\n\n const nextElements = removeIndices(allElements, indices);\n\n onChange?.(generateCode(t.arrayExpression(nextElements)));\n };\n\n const deletePrimitive = (index: number) =>\n deleteSelectedPrimitives(new Set([index]));\n\n const addPrimitive = () => {\n const first = primitiveItems[0];\n\n if (!first) {\n return;\n }\n\n const newNode = createNodeFromValue(first.type, first.value);\n\n if (!newNode) {\n return;\n }\n\n onChange?.(generateCode(t.arrayExpression([...allElements, newNode])));\n };\n\n const duplicateSelectedPrimitives = (indices: Set<number>) => {\n const clones = [...indices]\n .sort((a, b) => a - b)\n .map(index => allElements[index])\n .filter((node): node is t.Expression => Boolean(node))\n .map(node => clone(node) as t.Expression);\n\n if (clones.length === 0) {\n return;\n }\n\n onChange?.(generateCode(t.arrayExpression([...allElements, ...clones])));\n };\n\n const moveSelectedPrimitives = (\n indices: Set<number>,\n direction: 'up' | 'down',\n ) => {\n const { items: nextElements, indices: nextIndices } = moveSelectedIndices(\n allElements,\n indices,\n direction,\n );\n\n selection.replace(nextIndices);\n onChange?.(generateCode(t.arrayExpression(nextElements)));\n };\n\n const moveItem = (fromIndex: number, toIndex: number) => {\n const nextItems = [...objectItems];\n const [movedItem] = nextItems.splice(fromIndex, 1);\n nextItems.splice(toIndex, 0, movedItem!);\n\n const nextValue = arrayExpressionToCode(\n nextItems.map(item => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n const updateProperty = (\n itemIndex: number,\n propertyKey: string,\n value: unknown,\n ) => {\n const item = objectItems[itemIndex]!;\n const property = item.editableProperties[propertyKey]!;\n\n const renderLeaf =\n render?.[propertyKey] && 'type' in render[propertyKey]\n ? (render[propertyKey] as BindingRenderLeaf)\n : null;\n\n const isJsx = renderLeaf?.type === 'jsx';\n const isInnerHTML = renderLeaf?.property === BINDING_PROP.INNER_HTML;\n let nextAstValue: t.Expression | null = null;\n\n if (isInnerHTML) {\n const str = String(value);\n nextAstValue = t.templateLiteral(\n [t.templateElement({ raw: str, cooked: str }, true)],\n [],\n );\n } else if (property.type === 'array' || property.type === 'object') {\n try {\n nextAstValue = parseExpression(String(value), {\n plugins: ['jsx', 'typescript'],\n });\n } catch {\n return;\n }\n } else if (!isJsx) {\n nextAstValue = createNodeFromValue(property.type, value);\n }\n\n if (!isJsx && !nextAstValue) {\n return;\n }\n\n const objectExpression = item.originalElement;\n const targetProperty = objectExpression.properties.find(\n (prop: t.ObjectProperty | t.ObjectMethod | t.SpreadElement) =>\n t.isObjectProperty(prop) &&\n t.isIdentifier(prop.key) &&\n prop.key.name === propertyKey,\n ) as t.ObjectProperty;\n\n const jsxPlaceholders = new Map<string, string>();\n const originalValues = new Map<t.ObjectProperty, t.Expression>();\n\n if (isJsx && targetProperty) {\n const trimmed = String(value).trim();\n if (trimmed.startsWith('<')) {\n const placeholder = `__JSX_${nanoid(6)}__`;\n jsxPlaceholders.set(placeholder, trimmed);\n targetProperty.value = t.identifier(placeholder);\n } else {\n targetProperty.value = t.stringLiteral(trimmed);\n }\n } else if (targetProperty && nextAstValue) {\n targetProperty.value = nextAstValue;\n }\n\n objectItems.forEach(obj => {\n obj.originalElement.properties.forEach(prop => {\n if (!t.isObjectProperty(prop) || !t.isIdentifier(prop.key)) {\n return;\n }\n\n if (t.isJSXElement(prop.value) || t.isJSXFragment(prop.value)) {\n const placeholder = `__JSX_${nanoid(6)}__`;\n jsxPlaceholders.set(placeholder, generateCode(prop.value));\n originalValues.set(prop, prop.value);\n prop.value = t.identifier(placeholder);\n }\n });\n });\n\n let nextValue = arrayExpressionToCode(\n objectItems.map(item => item.originalElement),\n );\n\n for (const [prop, original] of originalValues) {\n prop.value = original;\n }\n\n for (const [placeholder, code] of jsxPlaceholders) {\n // 두 번째 인자가 문자열이면 $&, $$ 같은 특수 치환 패턴으로 해석되어\n // code 안에 그런 문자가 있으면 결과가 깨진다 — 함수형 치환자로 방지.\n nextValue = nextValue.replace(placeholder, () => code);\n }\n\n onChange?.(nextValue);\n };\n\n const deleteSelectedItems = (indices: Set<number>) => {\n if (objectItems.length - indices.size < 1) {\n return;\n }\n\n const nextItems = removeIndices(objectItems, indices);\n const nextValue = arrayExpressionToCode(\n nextItems.map((item: ItemData) => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n const deleteItem = (index: number) => deleteSelectedItems(new Set([index]));\n\n const cloneObjectItemElement = (source: ItemData): t.ObjectExpression => {\n const clonedElement = clone(source.originalElement) as t.ObjectExpression;\n\n clonedElement.properties.forEach(prop => {\n if (t.isObjectProperty(prop) && t.isIdentifier(prop.key)) {\n const key = prop.key.name;\n const editableProp = source.editableProperties[key];\n\n if (key === 'key' && t.isStringLiteral(prop.value)) {\n const originalKey = prop.value.value;\n const uniqueKey = `${originalKey}-${nanoid(6)}`;\n prop.value = t.stringLiteral(uniqueKey);\n return;\n }\n\n if (editableProp) {\n const nextValue = createNodeFromValue(\n editableProp.type,\n editableProp.value,\n );\n\n if (nextValue) {\n prop.value = nextValue;\n }\n }\n }\n });\n\n return clonedElement;\n };\n\n const addItem = () => {\n const firstItem = objectItems[0];\n\n if (!firstItem) {\n return;\n }\n\n const clonedElement = cloneObjectItemElement(firstItem);\n const editableProperties = extractObjectProperties(clonedElement);\n\n const nextItems = [...objectItems];\n const newItemData: ItemData = {\n id: nanoid(6),\n index: nextItems.length,\n editableProperties,\n originalElement: clonedElement,\n jsxBindings: {},\n };\n\n nextItems.push(newItemData);\n\n const nextValue = arrayExpressionToCode(\n nextItems.map(item => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n const duplicateSelectedItems = (indices: Set<number>) => {\n const sources = [...indices]\n .sort((a, b) => a - b)\n .map(index => objectItems[index])\n .filter((item): item is ItemData => Boolean(item));\n\n if (sources.length === 0) {\n return;\n }\n\n const clonedElements = sources.map(cloneObjectItemElement);\n const nextValue = arrayExpressionToCode([\n ...objectItems.map(item => item.originalElement),\n ...clonedElements,\n ]);\n\n onChange?.(nextValue);\n };\n\n const moveSelectedItems = (\n indices: Set<number>,\n direction: 'up' | 'down',\n ) => {\n const { items: nextItems, indices: nextIndices } = moveSelectedIndices(\n objectItems,\n indices,\n direction,\n );\n\n selection.replace(nextIndices);\n\n const nextValue = arrayExpressionToCode(\n nextItems.map(item => item.originalElement),\n );\n\n onChange?.(nextValue);\n };\n\n if (isPrimitive) {\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold\">\n Items ({primitiveItems.length})\n </div>\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n onClick={addPrimitive}\n >\n Add Item\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={() => duplicateSelectedPrimitives(selection.selected)}\n onMoveUp={() => moveSelectedPrimitives(selection.selected, 'up')}\n onMoveDown={() => moveSelectedPrimitives(selection.selected, 'down')}\n onDelete={() => {\n deleteSelectedPrimitives(selection.selected);\n selection.clear();\n }}\n onClear={selection.clear}\n />\n\n {primitiveItems.map((item, i) => (\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 <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={i === 0}\n onClick={() => movePrimitive(item.index, item.index - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={i === primitiveItems.length - 1}\n onClick={() => movePrimitive(item.index, item.index + 1)}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n disabled={primitiveItems.length <= 1}\n onClick={() => deletePrimitive(item.index)}\n />\n </div>\n </div>\n <Field\n binding={{\n label: `item-${i}`,\n property: item.type,\n }}\n id={`primitive-${item.id}`}\n value={String(item.value ?? '')}\n onChange={({ value: next }) => updatePrimitive(item.index, next)}\n />\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\">\n Items ({objectItems.length})\n </div>\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n disabled={objectItems.length === 0}\n onClick={addItem}\n >\n Add Item\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={() => duplicateSelectedItems(selection.selected)}\n onMoveUp={() => moveSelectedItems(selection.selected, 'up')}\n onMoveDown={() => moveSelectedItems(selection.selected, 'down')}\n onDelete={() => {\n deleteSelectedItems(selection.selected);\n selection.clear();\n }}\n onClear={selection.clear}\n />\n\n {objectItems.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 <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={item.index === 0}\n onClick={() => moveItem(item.index, item.index - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={item.index === objectItems.length - 1}\n onClick={() => moveItem(item.index, item.index + 1)}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n disabled={objectItems.length <= 1}\n onClick={() => deleteItem(item.index)}\n />\n </div>\n </div>\n <div className=\"space-y-2\">\n {Object.entries(item.editableProperties).map(([key, prop]) => (\n <div key={`${item.id}-${key}`}>\n <div className=\"flex flex-col space-y-2\">\n <label className=\"w-20 shrink-0 text-xs font-medium\">\n {key}\n </label>\n <Field\n binding={{\n label: key,\n property:\n render?.[key] && 'type' in render[key]\n ? ((render[key] as BindingRenderLeaf).property ??\n (render[key].type as string))\n : key,\n type:\n render?.[key] && 'type' in render[key]\n ? (render[key] as BindingRenderLeaf).type\n : undefined,\n render:\n render?.[key] && 'type' in render[key]\n ? (render[key] as BindingRenderLeaf).render\n : render?.[key] && !('type' in render[key])\n ? (render[key] as BindingRenderMap)\n : undefined,\n }}\n id={`item-${item.id}-${key}`}\n value={String(prop.value)}\n onChange={({ value: next }) =>\n updateProperty(item.index, key, parseValue(next))\n }\n />\n </div>\n <span className=\"text-right text-xs text-gray-500\">\n ({prop.type})\n </span>\n </div>\n ))}\n </div>\n <div className=\"space-y-3 border-t pt-2\">\n {Object.entries(item.jsxBindings).length > 0 ? (\n Object.entries(item.jsxBindings).map(\n ([propertyName, bindings]) => (\n <div key={propertyName} className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {propertyName} Bindings ({bindings.length}):\n </div>\n {bindings.map((bindingNode, idx) => {\n const nodeId = bindingNode.dataAttributes.find(\n a => a.name === 'data-id',\n )?.value;\n\n return (\n <div\n key={`binding-${item.id}-${propertyName}-${nodeId || idx}`}\n className=\"rounded border border-blue-100 bg-blue-50\n p-2\"\n >\n <div className=\"mb-1 text-xs text-blue-600\">\n &lt;{bindingNode.tagName || 'element'}&gt;\n </div>\n <Node data={bindingNode} onChange={onChildChange} />\n </div>\n );\n })}\n </div>\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;\nexport { BulkActionsBar };\n","import { useMemo } from 'react';\n\nimport { Button, Checkbox } from '@jbpark/ui-kit';\nimport { useMultiSelect } from '@jbpark/use-hooks';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\nimport { nanoid } from 'nanoid';\n\nimport { type DataAttrNode, findEditableChildren } from '~/utils/ast';\n\nimport { BulkActionsBar } from './items';\nimport Node from './node';\nimport { moveSelectedIndices, removeIndices } from './selection';\n\ninterface Props {\n value: DataAttrNode[];\n onChange?: (value: string) => void;\n onNodeChange?: (params: { id: string; label: string; value: string }) => void;\n}\n\nconst Children = ({ value, onChange, onNodeChange }: Props) => {\n const items = useMemo(() => (Array.isArray(value) ? value : []), [value]);\n\n const selection = useMultiSelect(items.length);\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 const moveItem = (fromIndex: number, toIndex: number) => {\n const nextItems = [...items];\n const [movedItem] = nextItems.splice(fromIndex, 1);\n nextItems.splice(toIndex, 0, movedItem!);\n\n onChange?.(JSON.stringify(nextItems));\n };\n\n const moveSelectedItems = (\n indices: Set<number>,\n direction: 'up' | 'down',\n ) => {\n const { items: nextItems, indices: nextIndices } = moveSelectedIndices(\n items,\n indices,\n direction,\n );\n\n selection.replace(nextIndices);\n onChange?.(JSON.stringify(nextItems));\n };\n\n const deleteSelectedItems = (indices: Set<number>) => {\n if (items.length - indices.size < 1) {\n return;\n }\n\n const nextItems = removeIndices(items, indices);\n onChange?.(JSON.stringify(nextItems));\n };\n\n const deleteItem = (index: number) => deleteSelectedItems(new Set([index]));\n\n const addItem = () => {\n const template = items[0] || createDefaultItem();\n const newItem = cloneDataAttrNode(template);\n\n const nextItems = [...items, newItem];\n onChange?.(JSON.stringify(nextItems));\n };\n\n const duplicateSelectedItems = (indices: Set<number>) => {\n const sources = [...indices]\n .sort((a, b) => a - b)\n .map(index => items[index])\n .filter((item): item is DataAttrNode => Boolean(item));\n\n if (sources.length === 0) {\n return;\n }\n\n const clones = sources.map(cloneDataAttrNode);\n onChange?.(JSON.stringify([...items, ...clones]));\n };\n\n const createDefaultItem = (): DataAttrNode => ({\n id: nanoid(6),\n tagName: 'div',\n attributes: [\n { name: 'data-id', value: nanoid(6) },\n { name: 'data-item', value: 'true' },\n ],\n dataAttributes: [\n { name: 'data-id', value: nanoid(6) },\n { name: 'data-item', value: 'true' },\n ],\n textContent: '',\n children: [],\n });\n\n const cloneDataAttrNode = (node: DataAttrNode): DataAttrNode => ({\n ...node,\n id: nanoid(6),\n attributes: node.attributes.map(attr => ({\n ...attr,\n value: attr.name === 'data-id' ? nanoid(6) : attr.value,\n })),\n dataAttributes: node.dataAttributes.map(attr => ({\n ...attr,\n value: attr.name === 'data-id' ? nanoid(6) : attr.value,\n })),\n children: node.children?.map(cloneDataAttrNode),\n });\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 size=\"small\" color=\"green\" icon={<Plus />} onClick={addItem}>\n Add Child\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={() => duplicateSelectedItems(selection.selected)}\n onMoveUp={() => moveSelectedItems(selection.selected, 'up')}\n onMoveDown={() => moveSelectedItems(selection.selected, 'down')}\n onDelete={() => {\n deleteSelectedItems(selection.selected);\n selection.clear();\n }}\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={() => moveItem(itemIndex, itemIndex - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={itemIndex === items.length - 1}\n onClick={() => moveItem(itemIndex, itemIndex + 1)}\n />\n <Button\n title={\n items.length <= 1\n ? 'At least 1 item is required'\n : 'Delete item'\n }\n danger\n size=\"small\"\n icon={<X />}\n disabled={items.length <= 1}\n onClick={() => deleteItem(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-${itemIndex}-${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","import { useEffect, useMemo, useRef, useState } from 'react';\n\nimport {\n Checkbox,\n ColorPicker,\n DatePicker,\n Input,\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 TiptapEditor from '~/components/editor/tiptap';\nimport { BINDING_PROP } from '~/constants';\nimport {\n type BindingItem,\n parseValue,\n validateBindingValue,\n} from '~/utils/ast';\n\nimport Children from './children';\nimport { ICON_MAP } from './icon-map';\nimport Items from './items';\n\ninterface Props {\n binding: BindingItem;\n id: string;\n value: string;\n onChange?: (params: { id: string; label: string; value: string }) => void;\n}\n\ninterface Props {\n binding: BindingItem;\n id: string;\n value: string;\n onChange?: (params: { id: string; label: string; value: string }) => void;\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\ninterface ColorPickerFieldProps {\n id: string;\n label: string;\n value: string;\n onChange?: (params: { id: string; label: string; value: string }) => void;\n}\n\nconst ColorPickerField = ({\n id,\n label,\n value,\n onChange,\n}: 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?.({ id, label, value: 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 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\nconst Field = ({ binding, id, value, onChange }: Props) => {\n const parsedValue = useMemo(() => {\n return parseValue(value);\n }, [value]);\n\n const [validationError, setValidationError] = useState<string | null>(null);\n\n if (\n binding.property === 'items' ||\n binding.property === 'data' ||\n binding.type === 'array'\n ) {\n return (\n <Items\n value={value}\n render={binding.render}\n onChange={next => {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\n }}\n onChildChange={onChange}\n />\n );\n }\n\n if (binding.type === 'richtext') {\n return (\n <TiptapEditor\n value={value}\n onChange={next => {\n if (next !== value) {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\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={value}\n height=\"150px\"\n fragment={!isHTML}\n raw={isHTML}\n onSave={next => {\n if (next !== value) {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\n }\n }}\n />\n );\n }\n\n if (binding.property === 'children' && Array.isArray(parsedValue)) {\n return (\n <Children\n value={parsedValue}\n onChange={next => {\n onChange?.({\n id,\n label: binding.label,\n value: next,\n });\n }}\n onNodeChange={onChange}\n />\n );\n }\n\n if (\n typeof parsedValue === 'object' &&\n parsedValue !== null &&\n !Array.isArray(parsedValue)\n ) {\n return (\n <div className=\"space-y-2 rounded border border-gray-200 bg-gray-50 p-2\">\n {Object.entries(parsedValue).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 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: BindingItem['type'] })\n .type\n : undefined,\n render:\n binding.render?.[key] && !('type' in binding.render[key])\n ? (binding.render[key] as BindingItem['render'])\n : undefined,\n }}\n id={id}\n value={\n typeof val === 'object' ? JSON.stringify(val) : String(val)\n }\n onChange={({ value: next }) => {\n const convertedValue = parseValue(next);\n\n const updated = {\n ...parsedValue,\n [key]: convertedValue,\n };\n\n onChange?.({\n id,\n label: binding.label,\n value: JSON.stringify(updated),\n });\n }}\n />\n </div>\n ))}\n </div>\n );\n }\n\n if (binding.type === 'boolean' || typeof parsedValue === 'boolean') {\n return (\n <Checkbox\n checked={parsedValue === true || parsedValue === 'true'}\n onChange={checked => {\n onChange?.({\n id,\n label: binding.label,\n value: checked.toString(),\n });\n }}\n />\n );\n }\n\n const stringValue = String(value);\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?.({\n id,\n label: binding.label,\n value: next,\n });\n }\n }}\n />\n );\n }\n\n if (binding.type === 'color' || isColorProperty(binding.property)) {\n return (\n <ColorPickerField\n id={id}\n label={binding.label}\n value={normalizeToHex(stringValue)}\n onChange={onChange}\n />\n );\n }\n\n if (binding.type === 'date') {\n return (\n <div>\n <DatePicker\n defaultValue={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?.({\n id,\n label: binding.label,\n value: next,\n });\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 defaultValue={stringValue}\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 === '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?.({\n id,\n label: binding.label,\n value: next,\n });\n }\n }}\n />\n {SelectedIcon && <SelectedIcon size={18} className=\"shrink-0\" />}\n </div>\n );\n }\n\n if (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 defaultValue={stringValue}\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?.({\n id,\n label: binding.label,\n value: next,\n });\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 (typeof parsedValue === 'number') {\n return (\n <div>\n <Input\n type=\"number\"\n defaultValue={stringValue}\n placeholder=\"Enter a numeric value\"\n onBlur={e => {\n const next = e.target.value.trim();\n const result = validateBindingValue(\n binding,\n next ? Number(next) : '',\n );\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 defaultValue={value}\n placeholder=\"Enter a value\"\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?.({\n id,\n label: binding.label,\n value: next,\n });\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 DataAttrNode, getCurrentValue, parseBinding } from '~/utils/ast';\n\nimport Field from './field';\n\nexport interface FieldEditorProps {\n data: DataAttrNode;\n onChange?: (params: { id: string; label: string; value: string }) => 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\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 id={dataId}\n binding={binding}\n value={currentValue}\n onChange={onChange}\n />\n </div>\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default Node;\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';\nimport type { DataAttrNode } from '~/utils/ast';\n\nimport Node from './node';\n\ninterface Props {\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 data-binding fields — extraction (and the AST\n // update + error-toast handling behind onFieldChange) lives in Dnd, so\n // it's shared with a custom renderPanel instead of computed here too.\n fields: DataAttrNode[];\n onFieldChange: (params: { id: string; label: string; value: string }) => void;\n}\n\nconst Panel = ({\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp = false,\n canMoveDown = false,\n fields,\n onFieldChange,\n}: Props) => {\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 {!fields.length && (\n <Typography.Text className=\"text-xs text-gray-400\">\n No editable elements.\n </Typography.Text>\n )}\n {fields.map((node, index) => (\n <Node\n key={`${item.id}-${index}`}\n data={node}\n onChange={onFieldChange}\n />\n ))}\n </div>\n );\n};\n\nexport default Panel;\n","import { 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 arrayMove,\n verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { Button, Drawer, Space, Toast, Typography } from '@jbpark/ui-kit';\nimport { useResponsiveSize } from '@jbpark/use-hooks';\nimport { LayoutGrid } from 'lucide-react';\nimport { v4 as uuidv4 } from 'uuid';\n\nimport { DRAGGABLE_ITEMS } from '~/constants';\nimport type { Section } from '~/types';\nimport {\n type BindingOption,\n type BindingType,\n type DataAttrNode,\n extract,\n fillIds,\n getCurrentValue,\n parseBinding,\n replaceIds,\n update,\n} from '~/utils/ast';\n\nimport { DEFAULT_TEMPLATE } from '../../constants';\nimport {\n cn,\n createSectionPreviewCache,\n extractSections,\n preloadScripts,\n replaceSections,\n} from '../../utils';\nimport { usePreview } from '../context/states';\nimport { type FrameProps } from '../frame';\nimport DraggableItem, { DefaultDraggableItem } from './draggable';\nimport Droppable from './droppable';\nimport Overlay from './overlay';\nimport Panel from './panel';\nimport Renderer from './renderer';\nimport Sortable from './sortable';\n\nexport interface PaletteRenderData {\n items: Section[];\n onAdd: (item: Section) => void;\n DraggableItem: typeof DraggableItem;\n // True when the palette is rendering inside the mobile Drawer, where a\n // tap can't be a failed drag attempt (there's nothing to drag onto —\n // the canvas is stacked behind the Drawer) and native dblclick synthesis\n // from double-tap is unreliable on touch. Custom renderPalette\n // implementations should treat a single click/tap as \"add\" here instead\n // of relying on onDoubleClick.\n isMobile: boolean;\n}\n\nexport interface PanelRenderData {\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 this 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}\n\n// One editable data-binding, flattened out of the selected section for a\n// custom renderPanel. 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 // Present when the binding defines a fixed option set (render a <select>).\n options?: BindingOption[];\n // Current serialized value — the same string the built-in field receives.\n value: 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).\n onChange: (value: string) => 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 // Full replacements for the built-in left palette / right panel — receive\n // the same data/callbacks Dnd itself uses, so drag-and-drop and field\n // editing keep working exactly as before, just with custom markup. Used\n // for both the desktop layout and the mobile drawer, since those already\n // render identical content today.\n renderPalette?: (data: PaletteRenderData) => React.ReactNode;\n renderPanel?: (data: PanelRenderData) => 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 renderPalette,\n renderPanel,\n ...restProps\n}: Props) => {\n const [selectedId, setSelectedId] = useState<string | null>(null);\n const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);\n\n const { breakpoint } = useResponsiveSize();\n const isMobile = breakpoint.current === 'xs' || breakpoint.current === 'sm';\n\n const { setCode } = usePreview();\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 10,\n },\n }),\n );\n\n const value = _value || DEFAULT_TEMPLATE;\n const sections = useMemo(() => extractSections(value), [value]);\n const selectedItem = useMemo(\n () => sections.find(s => s.id === selectedId),\n [sections, selectedId],\n );\n\n // One cache per Dnd 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\n // that didn't change), which a `useMemo`/`useRef` can't do without\n // touching a ref during render; a cache object stored via `useState`\n // and only ever mutated through its own method isn't subject to that\n // restriction the way `ref.current` is.\n const [previewCache] = useState(() => createSectionPreviewCache());\n const previews = useMemo(\n () => previewCache.compute(value, sections),\n [previewCache, sections, value],\n );\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 newItem = active.data.current.item;\n const newSection = {\n id: uuidv4(),\n name: newItem.name,\n code: newItem.code,\n };\n\n let nextSections: typeof sections;\n\n if (over.id === 'sortable-area' || over.id === 'sortable-area-bottom') {\n nextSections = [...sections, newSection];\n } else {\n const overIndex = sections.findIndex(s => s.id === over.id);\n if (overIndex >= 0) {\n nextSections = [\n ...sections.slice(0, overIndex),\n newSection,\n ...sections.slice(overIndex),\n ];\n } else {\n nextSections = [...sections, newSection];\n }\n }\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n return;\n }\n\n if (active.id !== over.id && sections.some(s => s.id === active.id)) {\n const prevIndex = sections.findIndex(s => s.id === active.id);\n const nextIndex = sections.findIndex(s => s.id === over.id);\n\n if (prevIndex >= 0 && nextIndex >= 0) {\n const nextSections = arrayMove(sections, prevIndex, nextIndex);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n }\n }\n };\n\n const addItem = (item: (typeof DRAGGABLE_ITEMS)[0]) => {\n const newSection = {\n id: uuidv4(),\n name: item.name,\n code: item.code,\n };\n\n const nextSections = [...sections, newSection];\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n };\n\n const onDelete = (id: string) => {\n const nextSections = sections.filter(s => s.id !== id);\n\n setSelectedId(null);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n };\n\n const moveSection = (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 const nextSections = arrayMove(sections, index, targetIndex);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n // Section ids are just the section's positional index, re-derived from\n // scratch on every parse (getSections) rather than a stable identity —\n // so once `sections` recomputes after this reorder, `selectedId`\n // (unchanged) would silently point at whatever content now sits at its\n // old position instead of following the section that actually moved.\n setSelectedId(String(targetIndex));\n };\n\n const onCopy = (id: string) => {\n const sectionIndex = sections.findIndex(s => s.id === id);\n const sectionToCopy = sections[sectionIndex];\n\n if (sectionToCopy) {\n const nextId = uuidv4();\n const nextSection = {\n id: nextId,\n code: replaceIds(sectionToCopy.code),\n name: sectionToCopy.name,\n };\n\n const nextSections = [\n ...sections.slice(0, sectionIndex + 1),\n nextSection,\n ...sections.slice(sectionIndex + 1),\n ];\n\n setSelectedId(nextId);\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\n }\n };\n\n const onSelect = (id: string) => {\n setSelectedId(prev => (prev === id ? null : id));\n };\n\n const onChange = (next: Partial<Section>) => {\n const nextSections = sections.map(s =>\n s.id === next.id ? { ...s, ...next } : s,\n );\n\n const nextCode = replaceSections(\n value,\n nextSections.map(s => s.code),\n );\n\n _onChange?.(nextCode);\n setCode(nextCode);\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 renderPanel\n // get the same extraction/update pipeline instead of each 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 value: fieldValue,\n }: {\n id: string;\n label: string;\n value: string;\n }) => {\n const result = update(updatedCode, id, label, fieldValue);\n\n if (!result.success) {\n Toast.error('Failed to update this field', {\n description: 'Check the console for details.',\n });\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 PanelBinding per bound property — the same walk the built-in\n // FieldEditor/Node does internally (data-id + parsed data-binding +\n // current value), but handed to a custom renderPanel as plain data so it\n // can render its own controls. Kept in a useMemo keyed on `fields` alone;\n // `onFieldChange` closes over `updatedCode`/`selectedItem` but is stable\n // enough per render, and rebuilding on every render would defeat the memo\n // guarding renderPanel's children.\n const bindings = useMemo<PanelBinding[]>(() => {\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 options: binding.options,\n value: getCurrentValue(node, binding.property),\n onChange: (value: string) =>\n onFieldChange({ id: dataId, label: binding.label, value }),\n }));\n });\n // onFieldChange is intentionally omitted — it's recreated every render\n // but only ever called from a user event, so closing over the latest\n // one via the render that produced these bindings is fine.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [fields]);\n\n useEffect(() => {\n if (frame?.scripts?.length) {\n preloadScripts(frame.scripts);\n }\n }, [frame?.scripts]);\n\n const renderPaletteItems = (\n onAdd: (item: Section) => void,\n forMobileDrawer = false,\n ) => {\n const paletteItems = items?.length ? items : DRAGGABLE_ITEMS;\n\n if (renderPalette) {\n return renderPalette({\n items: paletteItems,\n onAdd,\n DraggableItem,\n isMobile: forMobileDrawer,\n });\n }\n\n return (\n <Space orientation=\"vertical\" align=\"start\">\n {paletteItems.map(item => (\n <DefaultDraggableItem\n key={item.id}\n item={item}\n onAdd={onAdd}\n tapToAdd={forMobileDrawer}\n />\n ))}\n </Space>\n );\n };\n\n const renderPanelContent = () => {\n const selectedIndex = sections.findIndex(s => s.id === selectedId);\n const canMoveUp = selectedIndex > 0;\n const canMoveDown =\n selectedIndex >= 0 && selectedIndex < sections.length - 1;\n\n if (renderPanel) {\n return renderPanel({\n item: selectedItem,\n onChange,\n onDelete,\n onMoveUp: () => moveSection(selectedId, 'up'),\n onMoveDown: () => moveSection(selectedId, 'down'),\n canMoveUp,\n canMoveDown,\n bindings,\n });\n }\n\n return (\n <Panel\n item={selectedItem}\n onDelete={onDelete}\n onMoveUp={() => moveSection(selectedId, 'up')}\n onMoveDown={() => moveSection(selectedId, 'down')}\n canMoveUp={canMoveUp}\n canMoveDown={canMoveDown}\n fields={fields}\n onFieldChange={onFieldChange}\n />\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 w-full',\n className,\n //\n )}\n {...restProps}\n >\n <div className=\"hidden w-1/5 overflow-y-auto md:block\">\n <div className=\"h-full bg-gray-50 p-4\">\n {renderPaletteItems(addItem)}\n </div>\n </div>\n <div\n className={cn(\n 'relative',\n 'h-full w-full md:w-3/5',\n 'overflow-y-auto',\n //\n )}\n data-frame-container\n style={{\n isolation: 'isolate',\n contain: 'layout style',\n transform: 'translateZ(0)',\n }}\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>\n No sections available\n </Typography.Paragraph>\n <Typography.Text>\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 </div>\n <div className=\"hidden w-1/5 md:block\">{renderPanelContent()}</div>\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={() => setMobilePaletteOpen(true)}\n />\n <Drawer\n open={isMobile && mobilePaletteOpen}\n onClose={() => setMobilePaletteOpen(false)}\n direction=\"bottom\"\n size=\"large\"\n title=\"Components\"\n >\n {renderPaletteItems(item => {\n addItem(item);\n setMobilePaletteOpen(false);\n }, true)}\n </Drawer>\n <Drawer\n open={isMobile && Boolean(selectedId)}\n onClose={() => setSelectedId(null)}\n direction=\"bottom\"\n size=\"large\"\n title=\"Properties\"\n >\n {renderPanelContent()}\n </Drawer>\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 PaletteRenderData,\n type PanelBinding,\n type PanelRenderData,\n type Props,\n} from './dnd';\nimport DraggableItem, {\n type DraggableItemDragState,\n type DraggableItemProps,\n} from './draggable';\n\ntype DndComponent = typeof DndImpl & {\n DraggableItem: typeof DraggableItem;\n};\n\nconst Dnd = DndImpl as DndComponent;\n\nDnd.DraggableItem = DraggableItem;\n\nexport { DraggableItem };\nexport type {\n Props,\n PaletteRenderData,\n PanelRenderData,\n PanelBinding,\n DraggableItemProps,\n DraggableItemDragState,\n};\nexport default Dnd;\n"],"mappings":"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"}
@@ -309,12 +309,63 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
309
309
  };
310
310
  //#endregion
311
311
  //#region src/components/frame/shadow.tsx
312
- const Shadow = ({ children }) => {
312
+ const Shadow = ({ syncStyle = false, children }) => {
313
313
  const hostRef = useRef(null);
314
314
  const shadowRootRef = useRef(null);
315
315
  const renderTargetRef = useRef(null);
316
316
  const [renderTarget, setRenderTarget] = useState(null);
317
317
  const [hostContainer, setHostContainer] = useState(null);
318
+ const styleManagerRef = useRef({
319
+ copiedLinks: /* @__PURE__ */ new Set(),
320
+ copiedStyles: /* @__PURE__ */ new Set()
321
+ });
322
+ const applyStyle = useCallback(() => {
323
+ const shadowRoot = shadowRootRef.current;
324
+ if (!shadowRoot || !syncStyle) return;
325
+ const manager = styleManagerRef.current;
326
+ const links = document.querySelectorAll("link[rel=\"stylesheet\"]");
327
+ const newLinks = Array.from(links).map((link) => link.href).filter((href) => !manager.copiedLinks.has(href));
328
+ if (newLinks.length) {
329
+ const fragment = document.createDocumentFragment();
330
+ newLinks.forEach((href) => {
331
+ const link = document.createElement("link");
332
+ link.rel = "stylesheet";
333
+ link.href = href;
334
+ fragment.appendChild(link);
335
+ manager.copiedLinks.add(href);
336
+ });
337
+ shadowRoot.appendChild(fragment);
338
+ }
339
+ const styleTags = document.querySelectorAll("style");
340
+ const newStyles = Array.from(styleTags).map((style) => style.textContent || "").filter((content) => {
341
+ if (!content) return false;
342
+ const hash = content.length + content.slice(0, 50);
343
+ if (manager.copiedStyles.has(hash)) return false;
344
+ manager.copiedStyles.add(hash);
345
+ return true;
346
+ });
347
+ if (newStyles.length) {
348
+ const fragment = document.createDocumentFragment();
349
+ newStyles.forEach((content) => {
350
+ const style = document.createElement("style");
351
+ style.textContent = content;
352
+ fragment.appendChild(style);
353
+ });
354
+ shadowRoot.appendChild(fragment);
355
+ }
356
+ }, [syncStyle]);
357
+ const applyStyleTimeoutRef = useRef(void 0);
358
+ const debouncedApplyStyle = useCallback(() => {
359
+ clearTimeout(applyStyleTimeoutRef.current);
360
+ applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);
361
+ }, [applyStyle]);
362
+ useMutationObserver(document.head, debouncedApplyStyle, {
363
+ enabled: syncStyle,
364
+ childList: true,
365
+ subtree: true,
366
+ attributes: true,
367
+ attributeFilter: ["href"]
368
+ });
318
369
  useLayoutEffect(() => {
319
370
  if (!hostRef.current) return;
320
371
  const container = hostRef.current.closest("[data-frame-container]");
@@ -331,7 +382,8 @@ const Shadow = ({ children }) => {
331
382
  renderTargetRef.current = target;
332
383
  setRenderTarget(target);
333
384
  }
334
- }, []);
385
+ applyStyle();
386
+ }, [applyStyle]);
335
387
  useLayoutEffect(() => {
336
388
  if (renderTargetRef.current && !renderTarget) setRenderTarget(renderTargetRef.current);
337
389
  }, [renderTarget]);
@@ -345,7 +397,10 @@ const Shadow = ({ children }) => {
345
397
  //#region src/components/frame/frame.tsx
346
398
  const Frame = ({ mode, children, ...restProps }) => {
347
399
  if (!mode) return children(document.body);
348
- if (mode === "shadow") return /* @__PURE__ */ jsx(Shadow, { children: (container) => children(container || document.body) });
400
+ if (mode === "shadow") return /* @__PURE__ */ jsx(Shadow, {
401
+ syncStyle: restProps.syncStyle,
402
+ children: (container) => children(container || document.body)
403
+ });
349
404
  return /* @__PURE__ */ jsx(IFrame, {
350
405
  ...restProps,
351
406
  children
@@ -354,4 +409,4 @@ const Frame = ({ mode, children, ...restProps }) => {
354
409
  //#endregion
355
410
  export { Frame as t };
356
411
 
357
- //# sourceMappingURL=frame-C11nuIBH.js.map
412
+ //# sourceMappingURL=frame-DQ_9RdeP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame-C11nuIBH.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"],"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`/`renderPanel` 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 { useLayoutEffect, useRef, useState } from 'react';\nimport type { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\ninterface Props {\n children: (hostContainer: HTMLElement | null) => ReactNode;\n}\n\nconst Shadow = ({ 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 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 // 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 }, []);\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 <Shadow>{container => children(container || document.body)}</Shadow>;\n }\n\n return <IFrame {...restProps}>{children}</IFrame>;\n};\n\nexport default Frame;\n"],"mappings":"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"}
1
+ {"version":3,"file":"frame-DQ_9RdeP.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"],"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`/`renderPanel` 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"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { t as ContextProvider } from "./context-DrqO0VVu.js";
2
- import { t as Dnd } from "./dnd-BdNgmgYB.js";
2
+ import { t as Dnd } from "./dnd-BRQKM3fk.js";
3
3
  import { t as Editor } from "./editor-DmgTeTcG.js";
4
4
  import { t as Error } from "./error-DRMGumEj.js";
5
- import { t as Preview } from "./preview-DkLLqgKE.js";
5
+ import { t as Preview } from "./preview-CgJE-pwO.js";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  //#region src/index.tsx
8
8
  const App = ({ children }) => {
@@ -1,2 +1,2 @@
1
- import { t as Preview } from "../preview-DkLLqgKE.js";
1
+ import { t as Preview } from "../preview-CgJE-pwO.js";
2
2
  export { Preview as default };
@@ -1,6 +1,6 @@
1
1
  import { i as compile, r as cn, t as baseModules } from "./utils-BzfDKU6y.js";
2
2
  import { i as usePreview, r as useError } from "./states-Ci1AvoQ9.js";
3
- import { t as Frame } from "./frame-C11nuIBH.js";
3
+ import { t as Frame } from "./frame-DQ_9RdeP.js";
4
4
  import { t as generateTailwindCSSFromDOM } from "./tailwind-CbjdLyVX.js";
5
5
  import { t as Error$1 } from "./error-DRMGumEj.js";
6
6
  import { useCallback, useEffect, useMemo, useState } from "react";
@@ -110,4 +110,4 @@ const Preview = ({ code, props = {}, modules = {}, dynamicTailwind = false, prov
110
110
  //#endregion
111
111
  export { Preview as t };
112
112
 
113
- //# sourceMappingURL=preview-DkLLqgKE.js.map
113
+ //# sourceMappingURL=preview-CgJE-pwO.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"preview-DkLLqgKE.js","names":["LiveError"],"sources":["../src/components/preview/client.tsx","../src/components/preview/preview.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { useError, usePreview } from '~/components/context/states';\nimport LiveError from '~/components/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { baseModules, cn, compile } from '~/utils';\nimport { generateTailwindCSSFromDOM } from '~/utils/tailwind';\n\nimport { type Props } from './preview';\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 mergedModules = { ...baseModules, ...modules };\n const effectiveCode = _code || code;\n\n // Scans the actual rendered DOM (via `contentRef`, attached below) rather\n // than `effectiveCode`'s source text, so classes contributed by an\n // imported component (e.g. ui-kit's `Button`) are picked up too — those\n // never appear as literal text in the previewed source, only in that\n // component's own compiled output.\n //\n // The wrapper below is tracked via a callback ref (`contentEl` state)\n // rather than a plain `useRef`, because in shadow mode it isn't mounted\n // on this component's first commit at all — `Shadow` creates its portal\n // target in its own effect and only re-renders with it afterwards, one\n // commit later. A plain ref read in an `[effectiveCode, dynamicTailwind]`\n // -keyed effect would see `null` on that first pass and never retry;\n // making the element itself a dependency re-runs the scan once it\n // actually exists.\n const [dynamicCSS, setDynamicCSS] = useState('');\n const [contentEl, setContentEl] = useState<HTMLDivElement | null>(null);\n const contentRef = useCallback((el: HTMLDivElement | null) => {\n setContentEl(el);\n }, []);\n\n useEffect(() => {\n if (!effectiveCode || !dynamicTailwind || !contentEl) {\n return;\n }\n\n let cancelled = false;\n\n generateTailwindCSSFromDOM(contentEl).then(css => {\n if (!cancelled) {\n setDynamicCSS(css);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [effectiveCode, dynamicTailwind, contentEl]);\n\n let module = null;\n\n if (effectiveCode) {\n try {\n module = compile(effectiveCode, mergedModules);\n } catch (e) {\n module = {\n exports: {},\n error: e instanceof Error ? e.message : 'Module transformation error',\n };\n }\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":";;;;;;;;AAYA,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;EAAE,GAAG;EAAa,GAAG;CAAQ;CACnD,MAAM,gBAAgB,SAAS;CAgB/B,MAAM,CAAC,YAAY,iBAAiB,SAAS,EAAE;CAC/C,MAAM,CAAC,WAAW,gBAAgB,SAAgC,IAAI;CACtE,MAAM,aAAa,aAAa,OAA8B;EAC5D,aAAa,EAAE;CACjB,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,IAAI,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,WACzC;EAGF,IAAI,YAAY;EAEhB,2BAA2B,SAAS,CAAC,CAAC,MAAK,QAAO;GAChD,IAAI,CAAC,WACH,cAAc,GAAG;EAErB,CAAC;EAED,aAAa;GACX,YAAY;EACd;CACF,GAAG;EAAC;EAAe;EAAiB;CAAS,CAAC;CAE9C,IAAI,SAAS;CAEb,IAAI,eACF,IAAI;EACF,SAAS,QAAQ,eAAe,aAAa;CAC/C,SAAS,GAAG;EACV,SAAS;GACP,SAAS,CAAC;GACV,OAAO,aAAa,QAAQ,EAAE,UAAU;EAC1C;CACF;CAGF,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,SAAD;GAAW,SAAS,OAAO;GAAO,OAAM;EAAiB,CAAA;CACtD,CAAA,GACL,oBAACA,QAAU,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,QAAU,UAAX;KACE,WAAW,CAAC,aAAa;KACzB,UAAU,MAAa,SAAS,EAAE,OAAO;KAExC,UAAA,eACC,qBAACA,QAAU,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,QAAU,UAAX;GACE,WAAW,CAAC,aAAa;GACzB,UAAS,MAAK,SAAS,EAAE,OAAO;GAE/B,UAAA,eACC,qBAACA,QAAU,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,QAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;AAEN;;;AC7IA,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
+ {"version":3,"file":"preview-CgJE-pwO.js","names":["LiveError"],"sources":["../src/components/preview/client.tsx","../src/components/preview/preview.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { useError, usePreview } from '~/components/context/states';\nimport LiveError from '~/components/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { baseModules, cn, compile } from '~/utils';\nimport { generateTailwindCSSFromDOM } from '~/utils/tailwind';\n\nimport { type Props } from './preview';\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 mergedModules = { ...baseModules, ...modules };\n const effectiveCode = _code || code;\n\n // Scans the actual rendered DOM (via `contentRef`, attached below) rather\n // than `effectiveCode`'s source text, so classes contributed by an\n // imported component (e.g. ui-kit's `Button`) are picked up too — those\n // never appear as literal text in the previewed source, only in that\n // component's own compiled output.\n //\n // The wrapper below is tracked via a callback ref (`contentEl` state)\n // rather than a plain `useRef`, because in shadow mode it isn't mounted\n // on this component's first commit at all — `Shadow` creates its portal\n // target in its own effect and only re-renders with it afterwards, one\n // commit later. A plain ref read in an `[effectiveCode, dynamicTailwind]`\n // -keyed effect would see `null` on that first pass and never retry;\n // making the element itself a dependency re-runs the scan once it\n // actually exists.\n const [dynamicCSS, setDynamicCSS] = useState('');\n const [contentEl, setContentEl] = useState<HTMLDivElement | null>(null);\n const contentRef = useCallback((el: HTMLDivElement | null) => {\n setContentEl(el);\n }, []);\n\n useEffect(() => {\n if (!effectiveCode || !dynamicTailwind || !contentEl) {\n return;\n }\n\n let cancelled = false;\n\n generateTailwindCSSFromDOM(contentEl).then(css => {\n if (!cancelled) {\n setDynamicCSS(css);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [effectiveCode, dynamicTailwind, contentEl]);\n\n let module = null;\n\n if (effectiveCode) {\n try {\n module = compile(effectiveCode, mergedModules);\n } catch (e) {\n module = {\n exports: {},\n error: e instanceof Error ? e.message : 'Module transformation error',\n };\n }\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":"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"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "1.15.0",
7
+ "version": "1.15.1",
8
8
  "type": "module",
9
9
  "module": "./dist/index.js",
10
10
  "types": "./dist/index.d.ts",