@jbpark/live-editor 4.3.0 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"dnd-Z1KS16Fy.js","names":["Children","CSS","t","CoreEditor","Children","Panel","PropertyPanel","LiveError","CSS","Renderer","Dnd","Renderer","DndImpl"],"sources":["../src/components/dnd/droppable.tsx","../src/components/dnd/edit-options.ts","../src/components/dnd/inspector.ts","../src/components/dnd/inspector-highlight.tsx","../src/components/dnd/draggable.tsx","../src/components/dnd/layout-context.ts","../src/components/dnd/panel-binding.ts","../src/components/dnd/panel/bulk-actions-bar.tsx","../src/components/dnd/panel/node.tsx","../src/components/dnd/panel/use-structural-selection.ts","../src/components/dnd/panel/use-dnd-children.ts","../src/components/dnd/panel/children.tsx","../src/components/dnd/panel/field-kind.ts","../src/components/dnd/panel/sortable-items.tsx","../src/components/dnd/panel/use-dnd-items.ts","../src/components/dnd/panel/items.tsx","../src/components/dnd/panel/field.tsx","../src/components/dnd/panel/field-group.tsx","../src/components/dnd/panel/panel.tsx","../src/components/dnd/layout.tsx","../src/components/dnd/section-fallback-context.ts","../src/components/dnd/section-fallback.tsx","../src/components/dnd/renderer.tsx","../src/components/dnd/sortable.tsx","../src/components/dnd/overlay.tsx","../src/components/dnd/use-section-document.ts","../src/components/dnd/dnd.tsx","../src/components/dnd/index.ts"],"sourcesContent":["import { useDroppable } from '@dnd-kit/core';\nimport { Typography } from '@jbpark/ui-kit';\n\nimport { cn } from '~/utils/cn';\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 { createContext, useContext } from 'react';\n\nimport { Toast } from '@jbpark/ui-kit';\n\nimport type { UpdateFailure } from '~/utils/ast';\n\nimport type { FieldProps } from './panel/field';\n\n// Everything the editor reports instead of applying an edit. `title` and\n// `description` are the messages the built-in toast shows, so a host that\n// routes these elsewhere can reuse them rather than rewording every case.\nexport type DndEditError =\n | {\n // `update()` rejected a field edit. `failure.reason` says why — most\n // often a `property`/`label` in the element's data-binding that doesn't\n // match its markup.\n type: 'update';\n id: string;\n label: string;\n property: string;\n failure: UpdateFailure | undefined;\n title: string;\n description?: string;\n }\n | {\n // The selected section's source, or an `items` value inside it, did\n // not parse. Nothing in it can be edited from the panel until it does.\n type: 'parse';\n target: 'section' | 'items';\n error?: unknown;\n title: string;\n description?: string;\n }\n | {\n // An edit was refused because the document doesn't parse. The canvas\n // and panel show the last version that did, and nothing can be\n // committed against it (#433). Reported when an edit is attempted, not\n // whenever the source stops parsing.\n type: 'parse';\n target: 'document';\n reason: 'parse-error';\n error: unknown;\n title: string;\n description?: string;\n }\n | {\n // The document has no element with the container id, so it has no\n // sections and nothing added from the palette can land. Reported once\n // each time a document reaches this state, not on every edit (#449).\n type: 'parse';\n target: 'document';\n reason: 'container-not-found';\n containerId: string;\n title: string;\n description?: string;\n }\n | {\n // An array edit could not be applied without losing source (a spread,\n // a hole, unsupported syntax). The source was left unchanged.\n type: 'items';\n title: string;\n description?: string;\n };\n\n// Called before the built-in control for every field — top-level, nested\n// object keys and array item properties alike. Return a node to render it\n// instead, `null` to render nothing, or `undefined` to keep `builtin`.\n// `builtin` is the control that would have rendered, so a renderer can wrap\n// it rather than replace it; don't render `<Live.Dnd.Field>` from here, since\n// that calls this function again.\nexport type DndRenderField = (\n props: FieldProps,\n builtin: React.ReactElement,\n) => React.ReactNode | undefined;\n\ninterface DndEditOptions {\n renderField?: DndRenderField;\n reportError: (error: DndEditError) => void;\n}\n\nexport const toastEditError = (error: DndEditError) => {\n Toast.error(\n error.title,\n error.description ? { description: error.description } : undefined,\n );\n};\n\n// A context rather than props threaded through every editor: `Field` renders\n// itself recursively and inside `Items`/`Children`, and a custom panel\n// renders it directly, so this is the one way every field sees the same\n// options. The default keeps `Field`/`useDndItems` working outside\n// `Live.Dnd`, reporting through the toast as before.\nexport const DndEditOptionsContext = createContext<DndEditOptions>({\n reportError: toastEditError,\n});\n\nexport const useDndEditOptions = () => useContext(DndEditOptionsContext);\n","import { createContext, useContext } from 'react';\n\nimport { DATA_ATTR } from '~/constants';\n\n// What `Live.Dnd` reports when an element is picked in the canvas preview:\n// the element's `data-id`, the key its fields carry in `useDndPanel()`, and\n// the section it belongs to (#432).\nexport interface DndNodePick {\n id: string;\n sectionId: string;\n}\n\n// The element picker. While `active`, pointing at a section in the canvas\n// outlines the element under the pointer, and clicking selects that section\n// and reports the element. Section dragging is off for as long as it's on.\nexport interface DndInspector {\n active: boolean;\n activate: () => void;\n deactivate: () => void;\n toggle: () => void;\n // The last element picked, or `null`. Cleared when the selection moves to\n // another section.\n picked: DndNodePick | null;\n}\n\nexport const DndInspectorContext = createContext<DndInspector | null>(null);\n\nexport const useDndInspector = (): DndInspector => {\n const inspector = useContext(DndInspectorContext);\n\n if (!inspector) {\n throw new Error('useDndInspector() must be used inside <Live.Dnd>.');\n }\n\n return inspector;\n};\n\n// A shadow root's `elementsFromPoint` lists the host page's elements under\n// the point too, the canvas overlay among them, so a nested lookup keeps only\n// its own tree's.\nconst outside = (root: Document | ShadowRoot) => (element: Element) =>\n element.getRootNode() !== root;\n\n// The deepest element at a point, looking into iframes and shadow roots on\n// the way down. Every canvas section sits under a transparent overlay that\n// takes the pointer, so the hit test has to skip it and go through to the\n// preview: in the host document for a section rendered in place, then inside\n// the iframe document or shadow root for the other frame modes.\nconst deepestAt = (\n root: Document | ShadowRoot,\n x: number,\n y: number,\n skip: (element: Element) => boolean,\n): Element | null => {\n const element = root\n .elementsFromPoint(x, y)\n .find(candidate => !skip(candidate));\n\n if (!element) {\n return null;\n }\n\n if (element instanceof HTMLIFrameElement) {\n const document = element.contentDocument;\n\n if (!document) {\n return element;\n }\n\n const rect = element.getBoundingClientRect();\n\n return (\n deepestAt(document, x - rect.left, y - rect.top, outside(document)) ??\n element\n );\n }\n\n if (element.shadowRoot && element.shadowRoot !== root) {\n return (\n deepestAt(element.shadowRoot, x, y, outside(element.shadowRoot)) ??\n element\n );\n }\n\n return element;\n};\n\nconst hasId = (element: Element) => Boolean(element.getAttribute(DATA_ATTR.ID));\n\n// The picked element inside `section`, as the nearest element at or above the\n// point that carries a non-empty `data-id`. `null` outside the section, or\n// when nothing there carries an id.\nexport const pickElement = (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n): Element | null => {\n let element = deepestAt(\n section.ownerDocument,\n x,\n y,\n candidate =>\n candidate === overlay ||\n candidate === section ||\n !section.contains(candidate),\n );\n\n // Stops at the section's wrapper, so an id on the host page around the\n // canvas is never picked.\n while (element && element !== section && !hasId(element)) {\n element =\n element.parentElement ??\n // Past a shadow root, carry on from its host.\n (element.parentNode as ShadowRoot | null)?.host ??\n null;\n }\n\n return element === section ? null : element;\n};\n\n// The picked element's box in the host viewport, adding the offset of each\n// iframe it's nested in.\nexport const viewportRect = (element: Element): DOMRect => {\n const rect = element.getBoundingClientRect();\n let x = rect.left;\n let y = rect.top;\n let frame = element.ownerDocument.defaultView?.frameElement ?? null;\n\n while (frame) {\n const frameRect = frame.getBoundingClientRect();\n\n x += frameRect.left;\n y += frameRect.top;\n frame = frame.ownerDocument.defaultView?.frameElement ?? null;\n }\n\n return new DOMRect(x, y, rect.width, rect.height);\n};\n","import { createPortal } from 'react-dom';\n\n// The outline drawn over the element under the pointer. Portaled to the host\n// body with fixed coordinates: the canvas sets `transform`, which would make\n// a fixed box inside it relative to the canvas instead of the viewport.\nconst InspectorHighlight = ({ rect }: { rect: DOMRect | null }) =>\n rect\n ? createPortal(\n <div\n aria-hidden\n data-dnd-inspector-highlight\n style={{\n position: 'fixed',\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n pointerEvents: 'none',\n outline: '2px solid #3b82f6',\n outlineOffset: -1,\n background: 'rgba(59, 130, 246, 0.12)',\n zIndex: 2147483647,\n }}\n />,\n document.body,\n )\n : null;\n\nexport default InspectorHighlight;\n","import { useDraggable } from '@dnd-kit/core';\nimport { Card } from '@jbpark/ui-kit';\n\nimport type { Section } from '~/types';\nimport { cn } from '~/utils/cn';\n\nexport interface DraggableItemDragState {\n ref: (node: HTMLElement | null) => void;\n dragProps: React.HTMLAttributes<HTMLElement>;\n isDragging: boolean;\n}\n\nexport interface DraggableItemProps {\n item: Section;\n children: (drag: DraggableItemDragState) => React.ReactNode;\n}\n\n// Owns the dnd-kit wiring (useDraggable + the `type: 'new-item'` data shape\n// Dnd's onDragEnd expects) so a custom palette only has to decide how\n// an item *looks*, not how dragging itself works. Exported as\n// Dnd.DraggableItem for that purpose; also used internally for the default\n// palette rendering, so both paths share the exact same drag wiring.\nconst DraggableItem = ({ item, children }: DraggableItemProps) => {\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({\n id: item.id,\n data: { type: 'new-item', item },\n });\n\n return children({\n ref: setNodeRef,\n dragProps: { ...listeners, ...attributes },\n isDragging,\n });\n};\n\n// The built-in card look, shared by the default (non-custom) palette\n// rendering and the drag overlay's floating preview — both rendered a plain\n// `<Draggable>` before this became a children-render-prop component.\nexport interface DefaultDraggableItemProps {\n item: Section;\n onAdd?: (item: Section) => void;\n // Double-click is the desktop convenience shortcut alongside drag — a\n // single click there would fire on every aborted/failed drag attempt.\n // On mobile there's nowhere to drag *to* (the palette lives in a Drawer\n // stacked over the canvas), so a tap can't be a failed drag, and\n // double-tap-to-dblclick synthesis from touch is unreliable anyway\n // (iOS Safari inconsistently fires it, and it can compete with the\n // browser's native double-tap-to-zoom gesture). Tapping just adds there.\n tapToAdd?: boolean;\n}\n\nexport const DefaultDraggableItem = ({\n item,\n onAdd,\n tapToAdd = false,\n}: DefaultDraggableItemProps) => (\n <DraggableItem item={item}>\n {({ ref, dragProps, isDragging }) => (\n <Card\n ref={ref}\n style={{ opacity: isDragging ? 0.5 : 1 }}\n {...dragProps}\n className={cn(\n 'cursor-grab',\n // A visible ring for keyboard focus only, instead of no outline at\n // all: the card is reachable with Tab (#435).\n 'outline-none focus-visible:ring-2 focus-visible:ring-blue-500',\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 // The card is a `role=\"button\"`: Enter adds it, the keyboard\n // counterpart of the double-click above. Space stays with dnd-kit,\n // which picks the card up (#435).\n onKeyDown={event => {\n dragProps.onKeyDown?.(event);\n\n if (\n onAdd &&\n event.key === 'Enter' &&\n event.target === event.currentTarget &&\n !event.defaultPrevented\n ) {\n event.preventDefault();\n onAdd(item);\n }\n }}\n >\n {item.name}\n </Card>\n )}\n </DraggableItem>\n);\n\nexport default DraggableItem;\n","import { createContext, useContext } from 'react';\n\nimport type { DndPalette, DndPanel } from './dnd';\n\n// The layout state a custom arrangement needs. Separate from the palette and\n// panel data because a layout decides *where* things go, not what they\n// contain — the built-in layout reads only this slice.\nexport interface DndLayout {\n // From `useResponsiveSize` — the same value that picks the stacked mobile\n // arrangement, so a custom layout can branch on it without repeating the\n // breakpoint check. Also what the built-in palette reads to decide\n // tap-to-add: at a mobile breakpoint a tap can't be a failed drag attempt\n // (there's nothing visible to drag onto behind the Drawer) and dblclick\n // synthesis from double-tap is unreliable, so a single tap adds.\n isMobile: boolean;\n // `null` when nothing is selected. The built-in layout uses it to open the\n // properties Drawer on mobile, where the panel has nowhere else to go.\n selectedId: string | null;\n clearSelection: () => void;\n // The palette Drawer's open state. Dnd owns it because adding an item\n // closes the Drawer; a layout only opens it.\n paletteOpen: boolean;\n setPaletteOpen: (open: boolean) => void;\n // Why the document can't be edited right now, or `null`. `'parse-error'`\n // while the source doesn't parse: the canvas shows the last version that\n // did, read-only (#433). `'container-not-found'` when it has no container\n // element, so it has no sections (#449).\n documentError: 'parse-error' | 'container-not-found' | null;\n}\n\n// Everything `Live.Dnd` publishes to its children, read back through the\n// three hooks below rather than as one object — a custom panel has no\n// business seeing the palette's items, and narrow hooks say which part of\n// Dnd a component actually depends on.\n//\n// `canvas` is the one node here rather than data: the droppable, the\n// sortable list and each section's compiled iframe are Dnd's own machinery,\n// so `Live.Dnd.Canvas` places it but nobody reproduces it.\ninterface DndRegions extends DndLayout {\n palette: DndPalette;\n panel: DndPanel;\n canvas: React.ReactNode;\n}\n\nexport const DndRegionContext = createContext<DndRegions | null>(null);\n\n// Internal, and takes a `subject` the public hooks don't: the caller as it\n// appears in source — a hook call, or the region element that wraps one — so\n// rendering `<Live.Dnd.Palette />` outside `Live.Dnd` reports the element the\n// reader actually wrote rather than the hook behind it.\nexport const useDndRegions = (subject: string): DndRegions => {\n const regions = useContext(DndRegionContext);\n\n if (!regions) {\n throw new Error(`${subject} must be used inside <Live.Dnd>.`);\n }\n\n return regions;\n};\n\n// The palette's items and the callback that adds one to the canvas. Pair it\n// with `Live.Dnd.DraggableItem` for the drag wiring and you have the whole\n// built-in palette's input.\nexport const useDndPalette = (): DndPalette =>\n useDndRegions('useDndPalette()').palette;\n\n// The selected section, its editable bindings, and the callbacks that commit\n// through Dnd's AST-update pipeline — everything the built-in property panel\n// runs on.\nexport const useDndPanel = (): DndPanel => useDndRegions('useDndPanel()').panel;\n\n// Returns the context object itself, narrowed: identity is stable across\n// renders, so this is safe in a dependency array.\nexport const useDndLayout = (): DndLayout => useDndRegions('useDndLayout()');\n","import { RESERVED_BINDING_PROPERTIES } from '~/constants';\nimport {\n type BindingItem,\n type BindingOption,\n type BindingRenderLeaf,\n type BindingRenderMap,\n type BindingType,\n type BindingWidget,\n type DataAttrNode,\n canLosslesslyEvaluateSource,\n getCurrentValue,\n getStructuredValue,\n parseBinding,\n} from '~/utils/ast';\n\n// The node-level commit callback's shape, named because it's part of the\n// public surface in two places (`DndPanel`, `Field`) and was previously\n// spelled out inline in each — see #308.\nexport interface PanelNodeChange {\n (params: {\n id: string;\n label: string;\n property: string;\n value: unknown;\n }): void;\n}\n\n// Several `PanelNodeChange`s committed as one edit (#425). They apply in array\n// order, all or none: if any is refused nothing is committed and the error\n// names the one that failed. That is what makes it worth using over calling\n// `PanelNodeChange` in a row, which lands as one document change per call and\n// leaves the earlier ones applied when a later one fails. An empty array does\n// nothing.\nexport interface PanelNodesChange {\n (changes: Parameters<PanelNodeChange>[0][]): void;\n}\n\n// One editable data-binding, flattened out of the selected section for a\n// custom panel. Exposes just what a consumer needs to render its own\n// control — the declared `type`, the current `value`, and an `onChange`\n// that commits through Dnd's AST-update pipeline — so it never has to touch\n// DataAttrNode/parseBinding/getCurrentValue itself.\nexport interface PanelBinding {\n // `data-id` of the owning element — stable across edits.\n id: string;\n // Human-readable label from the binding definition.\n label: string;\n // The bound prop/attribute name (e.g. `children`, `src`, `color`).\n property: string;\n // The declared data-binding type — switch on this to pick a control\n // (`string`/`url` -> <input>, `jsx`/`richtext` -> <textarea>, `boolean`\n // -> checkbox, ...). `undefined` means a plain string binding.\n type?: BindingType;\n // Presentation, as opposed to `type`'s data kind — switch on `widget.type`,\n // an open string rather than a closed enum, since a custom panel can\n // declare any control it wants (e.g. `'slider'`) along with that control's\n // own config (`step`, `unit`, ...). Always the object form even when\n // authored as a bare string. Passed through untouched: the built-in panel\n // ignores it and renders the `type`-appropriate default control.\n //\n // Value constraints are *not* in here — `min`/`max`/`pattern`/`required`\n // below apply with or without a widget.\n widget?: BindingWidget;\n // Present when the binding defines a fixed option set (render a <select>).\n options?: BindingOption[];\n // Present for `object`/`array` bindings whose nested keys/items declare\n // their own types — the same map the built-in panel uses to type each\n // nested field instead of falling back to a plain string input.\n render?: BindingRenderMap;\n // Constraints declared on the binding. `min`/`max` compare against the\n // real number `value` delivers for `type: 'number'` bindings (see\n // `validateBindingValue`).\n min?: number;\n max?: number;\n pattern?: string;\n required?: boolean;\n // Consumer-defined keys carried straight through from the authored\n // data-binding — namespaced instead of spread onto PanelBinding so they\n // can't collide with a future first-class field. Absent when nothing\n // extra was authored. See #234.\n meta?: Record<string, unknown>;\n // Current value as its real JS type — a number for `type: 'number'`, a\n // boolean for `type: 'boolean'`, an object/array for `object`/`array`,\n // a string otherwise. Switch on this without re-parsing. See #238.\n value: unknown;\n // The exact source text behind `value`, for cases that can't round-trip\n // through a JS value — `jsx`/`richtext` bindings, or an attribute whose\n // source is an expression you want to edit as text.\n rawValue: string;\n // False when the built-in control would have to reconstruct a partial\n // literal and could discard an expression, spread, hole or reference.\n // Raw array/JSX editors retain their own narrower source-safe contracts.\n canEditValue?: boolean;\n // `false` when the binding names an attribute the element doesn't carry.\n // Absent otherwise, including for content (`innerText`, `innerHTML`,\n // `children`), which is always there. `onChange(undefined)` removes an\n // attribute and `onChange(value)` adds one back, so this is what a panel\n // reads to draw an on/off control. `prop=\"\"` counts as present (#426).\n present?: boolean;\n // Commit a new value through the same AST-update pipeline the built-in\n // panel uses (including the error Toast on a bad edit). Pass the value as\n // its real type; it's serialized once, at the AST boundary, where the\n // declared `type` is known — so no string quoting/guessing on your side.\n onChange: (value: unknown) => void;\n}\n\n// A `PanelBinding` before a commit callback is attached. The split is the\n// point of this module: reading a node is pure and cacheable, while\n// `onChange` belongs to the render that made it. Binding the two together\n// too early is what caused #336 — a memo keyed on the parsed section handed\n// back callbacks still closed over a previous document.\nexport type PanelBindingData = Omit<PanelBinding, 'onChange'>;\n\n// One data-bound element resolved into panel currency.\nexport interface PanelBindingSource {\n // `data-id` of the element every binding below belongs to.\n id: string;\n // Falls back to `'element'` so a caller rendering a heading never has to\n // repeat that default.\n tagName: string;\n bindings: PanelBindingData[];\n}\n\nconst readAttribute = (node: DataAttrNode, name: string) =>\n node.dataAttributes.find(attribute => attribute.name === name)?.value;\n\nconst canEditBindingValue = (node: DataAttrNode, binding: BindingItem) => {\n // The editor owns these attributes; `update()` refuses them too (#429).\n if (RESERVED_BINDING_PROPERTIES.includes(binding.property)) {\n return false;\n }\n\n if (\n binding.property === 'children' ||\n binding.property === 'innerText' ||\n binding.property === 'innerHTML' ||\n binding.property === 'items' ||\n binding.property === 'data' ||\n binding.type === 'array' ||\n binding.type === 'jsx' ||\n binding.type === 'richtext'\n ) {\n return true;\n }\n\n const attribute = node.attributes.find(\n candidate => candidate.name === binding.property,\n );\n\n // Not in the source yet: nothing to lose, and a value adds it (#426).\n if (!attribute) {\n return true;\n }\n\n return (\n attribute.isStringLiteral === true ||\n canLosslesslyEvaluateSource(attribute?.value ?? '')\n );\n};\n\n// Every field a binding declares, listed exactly once. The mapped return type\n// makes leaving one out a type error, so a field added to `BindingItem`\n// reaches the built-in panel, a custom panel, nested item editors and\n// render-map leaves together instead of whichever path the author happened\n// to edit (#340, #383).\nexport const toBindingFields = (\n binding: BindingItem,\n): { [K in keyof Required<BindingItem>]: BindingItem[K] } => ({\n label: binding.label,\n property: binding.property,\n type: binding.type,\n widget: binding.widget,\n options: binding.options,\n render: binding.render,\n min: binding.min,\n max: binding.max,\n pattern: binding.pattern,\n required: binding.required,\n meta: binding.meta,\n});\n\n// The binding a nested key of an `object`/`array` value would have if it were\n// declared at the top level. A render-map leaf carries its own field spec;\n// `label` and `property` fall back to the key, which is what the property is\n// actually called. A nested map (or nothing) yields an untyped field that\n// still hands its sub-map down.\nexport const resolveRenderEntry = (\n render: BindingRenderMap | undefined,\n key: string,\n): BindingItem => {\n const entry = render?.[key];\n\n if (entry && 'type' in entry) {\n const leaf = entry as BindingRenderLeaf;\n\n return {\n ...leaf,\n label: leaf.label ?? key,\n property: leaf.property ?? key,\n };\n }\n\n return { label: key, property: key, render: entry as BindingRenderMap };\n};\n\n// Properties that are the element's content rather than one of its\n// attributes, so there's nothing to be absent.\nconst CONTENT_PROPERTIES = new Set(['innerText', 'innerHTML', 'children']);\n\nconst isAttributeAbsent = (node: DataAttrNode, binding: BindingItem) =>\n !CONTENT_PROPERTIES.has(binding.property) &&\n !node.attributes.some(candidate => candidate.name === binding.property);\n\nconst toPanelBindingData = (\n node: DataAttrNode,\n id: string,\n binding: BindingItem,\n): PanelBindingData => ({\n ...toBindingFields(binding),\n id,\n value: getStructuredValue(node, binding.property, binding.type),\n rawValue: getCurrentValue(node, binding.property),\n ...(!canEditBindingValue(node, binding) && { canEditValue: false }),\n ...(isAttributeAbsent(node, binding) && { present: false }),\n});\n\n// Read one extracted element's `data-id`/`data-binding` into panel bindings.\n// Returns `null` for anything not editable — a node missing either\n// attribute, or one whose `data-binding` parses to nothing — so callers keep\n// a single \"skip this node\" branch instead of re-deriving the rule.\n//\n// Reuses `node.bindings` when `extract()` already parsed the attribute and\n// only falls back to `parseBinding` otherwise, which is what keeps this\n// cheap enough to run on every node of a section.\nexport const resolvePanelBindings = (\n node: DataAttrNode,\n): PanelBindingSource | null => {\n const id = readAttribute(node, 'data-id');\n const bindingAttr = readAttribute(node, 'data-binding');\n\n if (!id || !bindingAttr) {\n return null;\n }\n\n const parsed = node.bindings ?? parseBinding(bindingAttr);\n\n if (!parsed.length) {\n return null;\n }\n\n return {\n id,\n tagName: node.tagName || 'element',\n bindings: parsed.map(binding => toPanelBindingData(node, id, binding)),\n };\n};\n\n// Attach the node-level commit to already-read bindings. Call this during\n// render, not inside a memo keyed on the parsed source: `commit` closes over\n// the current document, and reusing a stale one writes an older source back\n// over a newer one (#336).\nexport const withPanelCommit = (\n bindings: PanelBindingData[],\n commit: PanelNodeChange | undefined,\n): PanelBinding[] =>\n bindings.map(binding => ({\n ...binding,\n onChange: (value: unknown) =>\n commit?.({\n id: binding.id,\n label: binding.label,\n property: binding.property,\n value,\n }),\n }));\n","import { Button } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Copy, X } from 'lucide-react';\n\ninterface BulkActionsBarProps {\n count: number;\n disabled?: boolean;\n onDuplicate: () => void;\n onMoveUp: () => void;\n onMoveDown: () => void;\n onDelete: () => void;\n onClear: () => void;\n}\n\nconst BulkActionsBar = ({\n count,\n disabled = false,\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 disabled={disabled}\n onClick={onDuplicate}\n />\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n title=\"Move selected up\"\n disabled={disabled}\n onClick={onMoveUp}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n title=\"Move selected down\"\n disabled={disabled}\n onClick={onMoveDown}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n title=\"Delete selected\"\n disabled={disabled}\n onClick={onDelete}\n />\n <Button size=\"small\" onClick={onClear}>\n Clear\n </Button>\n </div>\n </div>\n );\n};\n\nexport default BulkActionsBar;\n","import type { DataAttrNode } from '~/utils/ast';\n\nimport {\n type PanelNodeChange,\n resolvePanelBindings,\n withPanelCommit,\n} from '../panel-binding';\nimport Field from './field';\n\nexport interface FieldEditorProps {\n data: DataAttrNode;\n onChange?: PanelNodeChange;\n}\n\nconst Node = ({ data, onChange }: FieldEditorProps) => {\n const source = resolvePanelBindings(data);\n\n if (!source) {\n return null;\n }\n\n // Keyed by `property`, never `label`: two bindings on one element may\n // share a label, and using it as identity is what #318 fixed elsewhere.\n return (\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {withPanelCommit(source.bindings, onChange).map(binding => (\n <div key={`${binding.id}-${binding.property}`} className=\"space-y-1\">\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">({binding.property})</span>\n </label>\n <Field binding={binding} onNodeChange={onChange} />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default Node;\n","import { useState } from 'react';\n\nimport { useMultiSelect } from '@jbpark/use-hooks';\n\nimport type { ChildrenAction } from '~/utils/ast';\nimport { moveSelectedIndices } from '~/utils/selection';\n\n// The structural commands both list editors issue (#342). Children sends them\n// to the AST layer as-is; Items translates them to array element positions.\nexport type StructuralCommand = ChildrenAction;\n\n// Where the selection stands after a command succeeds. Commands that leave\n// every existing position in place keep it; a bulk move carries the block to\n// its new positions; anything else shifts positions under the selection, so\n// it is cleared rather than left pointing at different items (#285).\nexport const selectionAfter = (\n command: StructuralCommand,\n selected: ReadonlySet<number>,\n count: number,\n): Set<number> => {\n switch (command.type) {\n case 'append':\n case 'duplicate':\n // Both add at the end, so no existing item moves.\n return new Set(selected);\n case 'move-selected':\n return moveSelectedIndices(\n Array.from({ length: count }, (_, index) => index),\n new Set(command.indices),\n command.direction,\n ).indices;\n default:\n return new Set();\n }\n};\n\ninterface Pending {\n // Recognizes the source this command produced, as opposed to one that\n // came from somewhere else (another field, undo, an external edit).\n matches: (revision: string) => boolean;\n selection: Set<number>;\n}\n\nexport interface RecordOptions {\n // Apply the selection now as well, for a caller that already knows the\n // command succeeded. Otherwise it applies when the source arrives.\n now?: boolean;\n}\n\n// Positional multi-selection for a list whose source can change under it.\n// `revision` identifies the current source. When it changes to the source a\n// recorded command produced, that command's selection applies; when it\n// changes for any other reason, the selection is cleared, since positions in\n// an unrelated source no longer name the same items. A refused command\n// produces no new source, so it changes nothing.\nexport const useStructuralSelection = (count: number, revision: string) => {\n const selection = useMultiSelect(count);\n const [seen, setSeen] = useState(revision);\n const [pending, setPending] = useState<Pending | null>(null);\n\n // Adjusted during render rather than in an effect, so a frame with the\n // previous source's selection never paints.\n if (revision !== seen) {\n setSeen(revision);\n setPending(null);\n\n if (pending?.matches(revision) && pending.selection.size > 0) {\n selection.replace(pending.selection);\n } else {\n selection.clear();\n }\n }\n\n const record = (\n next: Set<number>,\n matches: Pending['matches'],\n { now = false }: RecordOptions = {},\n ) => {\n setPending({ matches, selection: next });\n\n if (!now) {\n return;\n }\n\n // `clear` also drops the shift-range anchor, which `replace` keeps.\n if (next.size > 0) {\n selection.replace(next);\n } else {\n selection.clear();\n }\n };\n\n return { selection, record };\n};\n","import { useMemo } from 'react';\n\nimport {\n type ChildrenAction,\n type ChildrenEdit,\n type DataAttrNode,\n getChildrenSignatures,\n} from '~/utils/ast';\nimport { moveSelectedIndices } from '~/utils/selection';\n\nimport {\n selectionAfter,\n useStructuralSelection,\n} from './use-structural-selection';\n\nexport interface DndChildrenOptions {\n onChange?: (value: string) => void;\n}\n\n// The signature list a successful command produces, as far as it can be\n// known up front: a reorder is a permutation of the current signatures, and\n// an append or duplicate leaves them all in place as a prefix. Lets the\n// selection tell this command's result apart from an unrelated edit.\nconst producedBy = (\n expected: string[],\n action: ChildrenAction,\n): ((revision: string) => boolean) => {\n if (action.type === 'move-selected') {\n const moved = JSON.stringify(\n moveSelectedIndices(expected, new Set(action.indices), action.direction)\n .items,\n );\n\n return revision => revision === moved;\n }\n\n const added =\n action.type === 'append'\n ? 1\n : action.type === 'duplicate'\n ? action.indices.length\n : 0;\n\n return revision => {\n const next = JSON.parse(revision) as string[];\n\n return (\n next.length === expected.length + added &&\n expected.every((signature, index) => next[index] === signature)\n );\n };\n};\n\n// Domain adapter: serializes a structural command for the existing binding\n// onChange/update path. The AST layer owns source validation and mutation;\n// selection follows the shared rule in useStructuralSelection.\nexport const useDndChildren = (\n items: DataAttrNode[],\n { onChange }: DndChildrenOptions = {},\n) => {\n const expected = useMemo(() => getChildrenSignatures(items), [items]);\n const revision = JSON.stringify(expected);\n const { selection, record } = useStructuralSelection(items.length, revision);\n\n // The outcome is only known when new source arrives, so the selection is\n // recorded here and applied then. A rejected edit produces no new source\n // and leaves the selection as it was.\n const commit = (action: ChildrenAction) => {\n const edit: ChildrenEdit = { kind: 'children-edit', expected, action };\n const next = selectionAfter(action, selection.selected, items.length);\n\n if (next.size > 0) {\n record(next, producedBy(expected, action));\n }\n\n onChange?.(JSON.stringify(edit));\n };\n\n return {\n items,\n selection,\n actions: {\n move: (from: number, to: number) => commit({ type: 'move', from, to }),\n remove: (index: number) => commit({ type: 'remove', indices: [index] }),\n add: () => commit({ type: 'append' }),\n duplicateSelected: () =>\n commit({ type: 'duplicate', indices: [...selection.selected] }),\n moveSelected: (direction: 'up' | 'down') =>\n commit({\n type: 'move-selected',\n indices: [...selection.selected],\n direction,\n }),\n removeSelected: () =>\n commit({ type: 'remove', indices: [...selection.selected] }),\n },\n };\n};\n\nexport type DndChildren = ReturnType<typeof useDndChildren>;\n","import { useMemo } from 'react';\n\nimport { Button, Checkbox } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\n\nimport { type DataAttrNode, findEditableChildren } from '~/utils/ast';\n\nimport type { PanelNodeChange } from '../dnd';\nimport BulkActionsBar from './bulk-actions-bar';\nimport Node from './node';\nimport { useDndChildren } from './use-dnd-children';\n\ninterface Props {\n value: DataAttrNode[];\n onChange?: (value: string) => void;\n onNodeChange?: PanelNodeChange;\n}\n\nconst Children = ({ value, onChange, onNodeChange }: Props) => {\n const items = useMemo(() => (Array.isArray(value) ? value : []), [value]);\n\n const { selection, actions } = useDndChildren(items, { onChange });\n\n const editableChildrenMap = useMemo(() => {\n const map = new Map<number, DataAttrNode[]>();\n items.forEach((item, index) => {\n const editableNodes = findEditableChildren(item);\n if (editableNodes.length > 0) {\n map.set(index, editableNodes);\n }\n });\n return map;\n }, [items]);\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold text-green-700\">\n Children Items ({items.length})\n </div>\n <Button\n size=\"small\"\n color=\"green\"\n icon={<Plus />}\n onClick={actions.add}\n >\n Add Child\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={actions.duplicateSelected}\n onMoveUp={() => actions.moveSelected('up')}\n onMoveDown={() => actions.moveSelected('down')}\n onDelete={actions.removeSelected}\n onClear={selection.clear}\n />\n\n {items.map((item, itemIndex) => (\n <div\n key={item.id || itemIndex}\n className=\"space-y-2 rounded border border-green-200 bg-green-50 p-3\"\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-2\">\n <div\n onClick={e => selection.toggle(itemIndex, e.shiftKey)}\n className=\"inline-flex\"\n >\n <Checkbox\n checked={selection.isSelected(itemIndex)}\n onChange={() => {}}\n />\n </div>\n <div className=\"text-xs font-medium text-green-800\">\n Child {itemIndex + 1} ({item.tagName || 'fragment'})\n </div>\n </div>\n\n <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={itemIndex === 0}\n onClick={() => actions.move(itemIndex, itemIndex - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={itemIndex === items.length - 1}\n onClick={() => actions.move(itemIndex, itemIndex + 1)}\n />\n <Button\n title=\"Delete item\"\n danger\n size=\"small\"\n icon={<X />}\n onClick={() => actions.remove(itemIndex)}\n />\n </div>\n </div>\n\n {editableChildrenMap.has(itemIndex) && (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-green-700\">\n Editable Bindings:\n </div>\n {editableChildrenMap.get(itemIndex)!.map((editableNode, idx) => {\n const nodeId = editableNode.dataAttributes.find(\n a => a.name === 'data-id',\n )?.value;\n\n return (\n <div\n key={`editable-${nodeId || idx}`}\n data-node-id={nodeId}\n className=\"rounded border border-green-100 bg-white p-2\n data-[picked]:ring-2 data-[picked]:ring-blue-400\"\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 { BINDING_PROP } from '~/constants';\n\nimport type { PanelBinding } from '../panel-binding';\n\n// Which built-in control `Field` renders for a binding. `BuiltinField`\n// dispatches on this, so a custom panel that asks the same question (most\n// often \"does this binding need a structural editor?\") gets the library's\n// answer rather than a copy of it that can drift.\nexport type FieldKind =\n // `canEditValue: false` — shown as preserved source, not editable.\n | 'readonly'\n // An array literal (`items`/`data` or `type: 'array'`) — the Items editor,\n // or `useDndItems` for your own markup.\n | 'items'\n // Element children given as extracted nodes — the Children editor, or\n // `useDndChildren` for your own markup.\n | 'children'\n | 'richtext'\n | 'jsx'\n | 'html'\n // A plain object value — one nested field per key.\n | 'object'\n | 'boolean'\n | 'select'\n | 'color'\n | 'date'\n | 'url'\n | 'number'\n | 'text';\n\nexport type FieldKindBinding = Pick<\n PanelBinding,\n 'property' | 'type' | 'value' | 'options' | 'canEditValue'\n>;\n\nconst isColorProperty = (property: string): boolean =>\n property.toLowerCase().includes('color');\n\n// Order matters: the first match wins, exactly as the built-in control\n// chooses. `renderField` runs before any of this and can replace the result,\n// so this describes the built-in control, not what a `renderField` override\n// draws.\nexport const getFieldKind = (binding: FieldKindBinding): FieldKind => {\n const { property, type, value } = binding;\n\n if (binding.canEditValue === false) {\n return 'readonly';\n }\n\n if (property === 'items' || property === 'data' || type === 'array') {\n return 'items';\n }\n\n if (type === 'richtext') {\n return 'richtext';\n }\n\n if (property === BINDING_PROP.INNER_HTML) {\n return 'html';\n }\n\n if (type === 'jsx') {\n return 'jsx';\n }\n\n if (property === 'children' && Array.isArray(value)) {\n return 'children';\n }\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return 'object';\n }\n\n if (type === 'boolean' || typeof value === 'boolean') {\n return 'boolean';\n }\n\n if (binding.options && Array.isArray(binding.options)) {\n return 'select';\n }\n\n if (type === 'color' || isColorProperty(property)) {\n return 'color';\n }\n\n if (type === 'date') {\n return 'date';\n }\n\n if (type === 'url') {\n return 'url';\n }\n\n if (type === 'number' || typeof value === 'number') {\n return 'number';\n }\n\n return 'text';\n};\n\n// True for the two kinds whose value holds further data-bound elements, so a\n// flat input can't edit them: route these to `Field` or to the matching hook.\nexport const isStructuralFieldKind = (\n kind: FieldKind,\n): kind is 'items' | 'children' => kind === 'items' || kind === 'children';\n","import {\n type Announcements,\n DndContext,\n type DragEndEvent,\n KeyboardSensor,\n MouseSensor,\n TouchSensor,\n closestCenter,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport {\n restrictToParentElement,\n restrictToVerticalAxis,\n} from '@dnd-kit/modifiers';\nimport {\n SortableContext,\n sortableKeyboardCoordinates,\n useSortable,\n verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport { ChevronDown, ChevronRight, GripVertical } from 'lucide-react';\n\nimport { cn } from '~/utils/cn';\n\nimport type { DndItemsItem } from './use-dnd-items';\n\nconst label = (items: DndItemsItem[], id: string | number) => {\n const index = items.findIndex(item => item.id === id);\n\n return index >= 0 ? `Item ${index + 1}` : 'Item';\n};\n\n// Drag sorting for the built-in Items editor (#436). It has a context of its\n// own, so a drag here never reaches the canvas's section sorting. Moves go\n// through `actions.move`, the same edit the up/down buttons make.\n//\n// A mouse drag starts after a few pixels of movement. A touch drag starts\n// after a long press, so a short tap still scrolls the panel. The handle is\n// a button, so the keyboard can pick an item up with Space or Enter and move\n// it with the arrow keys.\nexport const SortableItems = ({\n items,\n disabled,\n onMove,\n children,\n}: {\n items: DndItemsItem[];\n disabled?: boolean;\n onMove: (item: DndItemsItem, toIndex: number) => void;\n children: (item: DndItemsItem) => React.ReactNode;\n}) => {\n const sensors = useSensors(\n useSensor(MouseSensor, { activationConstraint: { distance: 4 } }),\n useSensor(TouchSensor, {\n activationConstraint: { delay: 250, tolerance: 5 },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n }),\n );\n\n const onDragEnd = ({ active, over }: DragEndEvent) => {\n const from = items.find(item => item.id === active.id);\n const to = items.find(item => item.id === over?.id);\n\n if (from && to && from !== to) {\n onMove(from, to.index);\n }\n };\n\n // The default announcements read out the items' generated ids.\n const announcements: Announcements = {\n onDragStart: ({ active }) => `Picked up ${label(items, active.id)}.`,\n onDragOver: ({ active, over }) =>\n over\n ? `${label(items, active.id)} is over ${label(items, over.id)}.`\n : undefined,\n onDragEnd: ({ active, over }) =>\n over\n ? `${label(items, active.id)} was moved to the place of ${label(items, over.id)}.`\n : `${label(items, active.id)} was dropped.`,\n onDragCancel: ({ active }) =>\n `Moving ${label(items, active.id)} was cancelled.`,\n };\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n modifiers={[restrictToVerticalAxis, restrictToParentElement]}\n accessibility={{ announcements }}\n onDragEnd={onDragEnd}\n >\n <SortableContext\n items={items.map(item => item.id)}\n strategy={verticalListSortingStrategy}\n disabled={disabled}\n >\n <div className=\"space-y-4\">{items.map(children)}</div>\n </SortableContext>\n </DndContext>\n );\n};\n\n// One item in the Items editor: a header with a drag handle, the selection\n// checkbox and a toggle that shows or hides the item's fields.\nexport const ItemCard = ({\n id,\n title,\n disabled,\n expanded,\n onToggle,\n checkbox,\n controls,\n className,\n children,\n}: {\n id: string;\n title: string;\n disabled?: boolean;\n expanded: boolean;\n onToggle: () => void;\n checkbox: React.ReactNode;\n controls: React.ReactNode;\n className?: string;\n children: React.ReactNode;\n}) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n setActivatorNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id, disabled });\n\n return (\n <div\n ref={setNodeRef}\n style={{ transform: CSS.Translate.toString(transform), transition }}\n className={cn(className, isDragging && 'relative z-10 shadow-md')}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-1\">\n <button\n type=\"button\"\n ref={setActivatorNodeRef}\n {...attributes}\n {...listeners}\n aria-label={`Reorder ${title}`}\n disabled={disabled}\n className=\"cursor-grab rounded p-0.5 text-gray-400\n hover:text-gray-700 disabled:cursor-not-allowed\n disabled:opacity-40\"\n >\n <GripVertical size={14} />\n </button>\n {checkbox}\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={onToggle}\n className=\"inline-flex items-center space-x-1 rounded px-1 text-xs\n font-medium\"\n >\n {expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}\n <span>{title}</span>\n </button>\n </div>\n {controls}\n </div>\n {expanded && children}\n </div>\n );\n};\n","import { useEffect, useMemo, useRef, useState } from 'react';\n\nimport * as t from '@babel/types';\nimport type { useMultiSelect } from '@jbpark/use-hooks';\nimport { nanoid } from 'nanoid';\n\nimport {\n type BindingRenderMap,\n type DataAttrNode,\n appendArrayItem,\n canLosslesslyEvaluateSource,\n canStructurallyEditArray,\n duplicateArrayItems,\n extract,\n extractNodeValue,\n extractObjectProperties,\n findEditableChildren,\n moveArrayItem,\n moveArrayItems,\n parseArrayExpression,\n parseValue,\n removeArrayItems,\n updateArrayItemProperty,\n updateArrayItemValue,\n} from '~/utils/ast';\nimport { moveSelectedIndices } from '~/utils/selection';\n\nimport { useDndEditOptions } from '../edit-options';\nimport {\n type PanelBinding,\n type PanelNodeChange,\n resolvePanelBindings,\n resolveRenderEntry,\n toBindingFields,\n withPanelCommit,\n} from '../panel-binding';\nimport {\n selectionAfter,\n useStructuralSelection,\n} from './use-structural-selection';\n\n// One data-bound element discovered inside a JSX-valued item property.\n// These are the elements the top-level `bindings` array can't reach —\n// `extract()` doesn't walk into an attribute expression, so they're found\n// by re-extracting the property's own JSX here (#308).\nexport interface DndItemsNestedElement {\n // The element's `data-id`, which is what commits address it by.\n id: string;\n tagName: string;\n bindings: PanelBinding[];\n}\n\nexport interface DndItemsNestedGroup {\n // The item property holding this JSX (e.g. `children`, `label`).\n property: string;\n elements: DndItemsNestedElement[];\n // Set instead of `elements` when the JSX parsed but declared no binding\n // at all. Editing the property's raw source is the only thing left to\n // offer, so this is a `jsx`-typed binding over that source (#298).\n fallback?: PanelBinding;\n}\n\nexport interface DndItemsItem {\n // Stable while this hook can prove the same item survived a source edit.\n // Structural actions update this identity alongside the source patch, so\n // React keys follow moved/duplicated/deleted rows instead of their positions.\n id: string;\n // Position among the visible items of this kind, which is what selection\n // indices refer to.\n index: number;\n // Position in the array's elements, which is what every `~/utils/ast`\n // item function addresses. Differs from `index` when the array mixes\n // objects and primitives.\n elementIndex: number;\n // An object item's plain (non-JSX) properties, already resolved through\n // the binding `render` map.\n properties: PanelBinding[];\n // An object item's JSX-valued properties.\n nested: DndItemsNestedGroup[];\n // A primitive item's own value. Absent on object items.\n value?: PanelBinding;\n}\n\nexport interface DndItemsActions {\n // Appends a copy of the first item of the current `kind`. An array\n // binding stays editable only while it holds at least one item: the shape\n // of a new item comes from its siblings, never from a guess. On an empty\n // array this is a no-op that raises the failure toast, so a custom panel\n // should offer it only when `items` is non-empty, the way the built-in\n // panel does (#316).\n add: () => void;\n move: (elementIndex: number, toIndex: number) => void;\n // Refuses the edit that would remove the last item, keeping the array\n // non-empty and therefore editable.\n remove: (elementIndex: number) => void;\n duplicateSelected: () => void;\n moveSelected: (direction: 'up' | 'down') => void;\n removeSelected: () => void;\n}\n\n// Which items show their fields. Keyed by `DndItemsItem.id`, so an item\n// keeps its state when it moves, a sibling changes, or another item is\n// added or removed. Every item starts expanded, including one added later.\n// The hook only holds the state; drawing a collapsed item is the panel's job.\nexport interface DndItemsExpansion {\n // The ids of the current items that are expanded, in item order.\n expandedIds: string[];\n isExpanded: (id: string) => boolean;\n toggle: (id: string) => void;\n // Expands exactly these items and collapses the rest. Pass every id to\n // expand all, or `[]` to collapse all.\n setExpanded: (ids: string[]) => void;\n}\n\nexport interface DndItems {\n // Which kind the array is being edited as. The panel shows one kind at a\n // time; an array holding both is treated as objects, and the primitives\n // stay untouched rather than being dropped.\n kind: 'object' | 'primitive';\n items: DndItemsItem[];\n // `@jbpark/use-hooks`' multi-select state, re-exposed as-is: `selected`,\n // `toggle`, `isSelected`, `clear`, `replace`. Its indices are item\n // `index` values, not `elementIndex` — the actions below translate.\n selection: ReturnType<typeof useMultiSelect>;\n expansion: DndItemsExpansion;\n actions: DndItemsActions;\n // Whether the current source can be moved, copied, removed or appended\n // without losing syntax. Value/property edits can remain available when\n // this is false. Every action revalidates the source before committing.\n canEditStructure: boolean;\n // The source didn't parse as an array expression. `items` is empty; the\n // built-in panel also raises a toast.\n parseError: boolean;\n}\n\nexport interface DndItemsOptions {\n render?: BindingRenderMap;\n // Commits a whole new array source. Every mutation here goes through\n // `~/utils/ast`'s item functions, which re-parse the source and hand back\n // a string, so no AST node is held or edited across renders.\n onChange?: (value: string) => void;\n // Commits an edit to one nested element, addressed by its own `data-id`.\n // A single binding's `onChange` can't express this — see #308.\n onNodeChange?: PanelNodeChange;\n}\n\ninterface RawObjectItem {\n id: string;\n index: number;\n elementIndex: number;\n source: string;\n editableProperties: ReturnType<typeof extractObjectProperties>;\n jsxBindings: Record<string, DataAttrNode[]>;\n jsxFallbacks: Record<string, string>;\n}\n\ninterface RawPrimitiveItem {\n id: string;\n index: number;\n elementIndex: number;\n source: string;\n value: string | number | boolean | null;\n type: ReturnType<typeof extractNodeValue>['type'];\n}\n\n// What an edit reads: this render's array, or the one a same-tick commit\n// left behind (#451), with the item identity and selection that go with it.\ninterface Snapshot {\n value: string;\n items: Array<RawObjectItem | RawPrimitiveItem>;\n ids: string[];\n selected: Set<number>;\n}\n\ninterface PendingCommit {\n // The render `value` the commit was built on.\n from: string;\n value: string;\n ids: string[];\n selected: Set<number>;\n}\n\nconst createPendingCommit = () => {\n let current: PendingCommit | null = null;\n\n return {\n read: () => current,\n write: (next: PendingCommit) => {\n current = next;\n },\n clear: () => {\n current = null;\n },\n };\n};\n\ninterface ItemIdentityState {\n value: string;\n kind: DndItems['kind'];\n ids: string[];\n signatures: string[];\n}\n\n// Pulls the data-bound elements out of one JSX-valued property. A container\n// declaring `children` wins outright: it owns the elements below it, so\n// listing them separately would offer the same edit twice.\nconst bindingsInJSX = (source: string): DataAttrNode[] => {\n const nodes = extract(source);\n const container = nodes.find(n =>\n n.bindings?.some(b => b.property === 'children'),\n );\n\n if (container) {\n return [container];\n }\n\n const bindings: DataAttrNode[] = [];\n\n nodes.forEach(n => {\n if (\n n.bindings &&\n n.bindings.length > 0 &&\n n.dataAttributes.some(a => a.name === 'data-id')\n ) {\n bindings.push(n);\n }\n\n bindings.push(...findEditableChildren(n));\n });\n\n return bindings;\n};\n\n// The parse. Split from the binding construction below so the Babel work is\n// memoized on the source string alone, while the callbacks the bindings\n// close over stay current on every render.\nconst parseSource = (value: string) => {\n const ast = parseArrayExpression(value);\n\n if (!ast) {\n return { objectItems: [], primitiveItems: [], parseError: true };\n }\n\n const objectItems: RawObjectItem[] = [];\n const primitiveItems: RawPrimitiveItem[] = [];\n ast.elements.forEach((element, elementIndex) => {\n if (!t.isExpression(element)) {\n return;\n }\n\n if (!t.isObjectExpression(element)) {\n const extracted = extractNodeValue(element);\n\n primitiveItems.push({\n id: nanoid(6),\n index: primitiveItems.length,\n elementIndex,\n source: value.slice(element.start!, element.end!),\n value: extracted.value,\n type: extracted.type,\n });\n return;\n }\n\n const jsxBindings: Record<string, DataAttrNode[]> = {};\n const jsxFallbacks: Record<string, string> = {};\n\n element.properties.forEach(prop => {\n if (\n !t.isObjectProperty(prop) ||\n !t.isIdentifier(prop.key) ||\n !(t.isJSXElement(prop.value) || t.isJSXFragment(prop.value))\n ) {\n return;\n }\n\n const propertyName = prop.key.name;\n\n try {\n const found = bindingsInJSX(\n value.slice(prop.value.start!, prop.value.end!),\n );\n\n if (found.length > 0) {\n jsxBindings[propertyName] = found;\n } else {\n jsxFallbacks[propertyName] = value.slice(\n prop.value.start!,\n prop.value.end!,\n );\n }\n } catch (error) {\n console.error(\n `Failed to parse JSX in property '${propertyName}':`,\n error,\n );\n }\n });\n\n const editableProperties = extractObjectProperties(element);\n\n for (const property of Object.values(editableProperties)) {\n if (property.type === 'array' || property.type === 'object') {\n property.value = value.slice(\n property.astNode.start!,\n property.astNode.end!,\n );\n }\n }\n\n objectItems.push({\n id: nanoid(6),\n index: objectItems.length,\n elementIndex,\n source: value.slice(element.start!, element.end!),\n editableProperties,\n jsxBindings,\n jsxFallbacks,\n });\n });\n\n return { objectItems, primitiveItems, parseError: false };\n};\n\nconst createIdentityState = (\n value: string,\n kind: DndItems['kind'],\n items: Array<RawObjectItem | RawPrimitiveItem>,\n ids: string[] = items.map(item => item.id),\n): ItemIdentityState => ({\n value,\n kind,\n ids,\n signatures: items.map(item => item.source),\n});\n\nconst reconcileIdentityState = (\n current: ItemIdentityState | null,\n value: string,\n kind: DndItems['kind'],\n items: Array<RawObjectItem | RawPrimitiveItem>,\n): ItemIdentityState => {\n if (\n current &&\n current.value === value &&\n current.kind === kind &&\n current.ids.length === items.length\n ) {\n return current;\n }\n\n if (!current || current.kind !== kind) {\n return createIdentityState(value, kind, items);\n }\n\n const previousCounts = new Map<string, number>();\n const nextCounts = new Map<string, number>();\n\n current.signatures.forEach(signature => {\n previousCounts.set(signature, (previousCounts.get(signature) ?? 0) + 1);\n });\n items.forEach(item => {\n nextCounts.set(item.source, (nextCounts.get(item.source) ?? 0) + 1);\n });\n\n const ids = items.map(item => {\n const previousIndex = current.signatures.indexOf(item.source);\n\n return previousIndex >= 0 &&\n previousCounts.get(item.source) === 1 &&\n nextCounts.get(item.source) === 1\n ? current.ids[previousIndex]!\n : item.id;\n });\n\n return createIdentityState(value, kind, items, ids);\n};\n\nconst moveId = (ids: string[], from: number, to: number) => {\n const next = [...ids];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved!);\n\n return next;\n};\n\nconst removeIds = (ids: string[], indices: Set<number>) => {\n return ids.filter((_, index) => !indices.has(index));\n};\n\n// The array-editing engine behind the built-in Items panel, exposed so a\n// consumer can render their own markup over it (#237/#308 follow-up).\n//\n// What it saves reimplementing: re-parsing each item's JSX to find nested\n// data-bound elements, resolving the binding `render` map, translating\n// visible item positions to array element positions before every edit, and\n// reconciling the selection after a move or delete (#285). Everything comes\n// back as `PanelBinding`s, the same currency `useDndPanel()` and\n// `Live.Dnd.Field` already speak, so nothing here requires touching Babel.\nexport const useDndItems = (\n value: string,\n { render, onChange, onNodeChange }: DndItemsOptions = {},\n): DndItems => {\n const { objectItems, primitiveItems, parseError } = useMemo(\n () => parseSource(value),\n [value],\n );\n const canEditStructure = useMemo(\n () => canStructurallyEditArray(value),\n [value],\n );\n\n const { reportError } = useDndEditOptions();\n\n // Read through a ref so the effect below fires once per parse failure, not\n // again on every render a host passes a fresh inline `onEditError`.\n const reportErrorRef = useRef(reportError);\n\n useEffect(() => {\n reportErrorRef.current = reportError;\n });\n\n useEffect(() => {\n if (parseError) {\n reportErrorRef.current({\n type: 'parse',\n target: 'items',\n title: 'Failed to parse items',\n description: 'Check the console for details.',\n });\n }\n }, [parseError]);\n\n const kind =\n primitiveItems.length > 0 && objectItems.length === 0\n ? 'primitive'\n : 'object';\n const isPrimitive = kind === 'primitive';\n const rawItems = isPrimitive ? primitiveItems : objectItems;\n const [identityState, setIdentityState] = useState(() =>\n createIdentityState(value, kind, rawItems),\n );\n const identity = useMemo(\n () => reconcileIdentityState(identityState, value, kind, rawItems),\n [identityState, kind, rawItems, value],\n );\n\n // Collapsed rather than expanded ids, so an item this hook hasn't seen\n // yet, such as one just added, starts expanded. Ids are never reused, so\n // one left behind by a removed item can't collapse another.\n const [collapsed, setCollapsed] = useState<ReadonlySet<string>>(\n () => new Set(),\n );\n\n const { selection, record } = useStructuralSelection(\n isPrimitive ? primitiveItems.length : objectItems.length,\n value,\n );\n\n // The array the last commit produced, with the identity and selection that\n // go with it, tagged with the render `value` it was built on. Every edit\n // below computes a whole new array from a snapshot, and the host only\n // hands the result back as `value` on the next render, so two edits in the\n // same tick both started from this render's array and the second dropped\n // the first (#451). Edits read `latest()` instead.\n //\n // Dropped after each render, as `useSectionDocument` does for the document\n // (#450): from then on the rendered `value` is the source of truth again,\n // including when the host didn't accept the commit.\n //\n // Held in a `useState` box rather than a ref: the item bindings below are\n // built during render and close over `latest()`, which the compiler reads\n // as a ref access in render even though only their `onChange` calls it —\n // the same reason `useSectionDocument` keeps its preview cache this way.\n const [pending] = useState(createPendingCommit);\n\n useEffect(() => {\n pending.clear();\n });\n\n const latest = (): Snapshot => {\n const last = pending.read();\n\n if (last?.from !== value) {\n return {\n value,\n items: rawItems,\n ids: identity.ids,\n selected: selection.selected,\n };\n }\n\n const parsed = parseSource(last.value);\n\n return {\n value: last.value,\n items: isPrimitive ? parsed.primitiveItems : parsed.objectItems,\n ids: last.ids,\n selected: last.selected,\n };\n };\n\n // Where the item this render showed at `elementIndex` is in `snapshot`,\n // followed by identity so an edit lands on the same item after a\n // same-tick move. `null` when a same-tick edit removed it; `undefined`\n // when this render has no such item, so the caller keeps the position it\n // was given.\n const locate = (snapshot: Snapshot, elementIndex: number) => {\n const shown = rawItems.find(item => item.elementIndex === elementIndex);\n\n if (!shown) {\n return undefined;\n }\n\n const index = snapshot.ids.indexOf(identity.ids[shown.index]!);\n\n return index >= 0 ? snapshot.items[index] : null;\n };\n\n // `null` means the edit could not be applied. `nextSelection` is where the\n // selection stands once it is: applied now, since a non-null `next` means\n // the edit succeeded, and again when this exact source comes back as\n // `value`. Any other new `value` clears it (useStructuralSelection).\n const commit = (\n snapshot: Snapshot,\n next: string | null,\n nextIds: string[] | undefined,\n nextSelection: Set<number>,\n ) => {\n if (next === null) {\n reportError({\n type: 'items',\n title: 'Failed to update this item',\n description:\n 'The source was preserved. Structural edits require a dense array without spreads; use the code editor for unsupported syntax.',\n });\n\n return false;\n }\n\n const parsed = parseSource(next);\n const nextItems =\n kind === 'primitive' ? parsed.primitiveItems : parsed.objectItems;\n const ids = nextIds ?? snapshot.ids;\n\n pending.write({\n from: value,\n value: next,\n ids,\n selected: nextSelection,\n });\n setIdentityState(createIdentityState(next, kind, nextItems, ids));\n record(nextSelection, revision => revision === next, { now: true });\n onChange?.(next);\n\n return true;\n };\n\n // Selection indices are positions among the visible items; every AST\n // function addresses element positions. Keeping the two apart is what\n // stops an edit from dropping the items that aren't on screen.\n const elementIndicesOf = (snapshot: Snapshot, indices: Set<number>) =>\n new Set(\n snapshot.items\n .filter(item => indices.has(item.index))\n .map(item => item.elementIndex),\n );\n\n const updateProperty = (\n elementIndex: number,\n propertyKey: string,\n next: unknown,\n ) => {\n const snapshot = latest();\n const item = locate(snapshot, elementIndex);\n\n if (item === null) {\n return;\n }\n\n // A value edit moves nothing, so the selection stands.\n commit(\n snapshot,\n updateArrayItemProperty(\n snapshot.value,\n item?.elementIndex ?? elementIndex,\n propertyKey,\n next,\n render,\n ),\n undefined,\n new Set(snapshot.selected),\n );\n };\n\n const updateValue = (elementIndex: number, next: unknown) => {\n const snapshot = latest();\n const item = locate(snapshot, elementIndex);\n\n if (item === null) {\n return;\n }\n\n commit(\n snapshot,\n updateArrayItemValue(\n snapshot.value,\n item?.elementIndex ?? elementIndex,\n next,\n ),\n undefined,\n new Set(snapshot.selected),\n );\n };\n\n const actions: DndItemsActions = {\n add: () => {\n const snapshot = latest();\n const next = appendArrayItem(snapshot.value, kind);\n\n commit(\n snapshot,\n next,\n next ? [...snapshot.ids, nanoid(6)] : undefined,\n selectionAfter(\n { type: 'append' },\n snapshot.selected,\n snapshot.items.length,\n ),\n );\n },\n\n move: (elementIndex, toIndex) => {\n const snapshot = latest();\n const from = locate(snapshot, elementIndex);\n const target = snapshot.items.find(item => item.index === toIndex);\n\n if (!from || !target) {\n return;\n }\n\n // Positions shift after a move but the count doesn't, so the\n // selection is cleared rather than left on the wrong items (#285).\n commit(\n snapshot,\n moveArrayItem(snapshot.value, from.elementIndex, target.elementIndex),\n moveId(snapshot.ids, from.index, target.index),\n new Set(),\n );\n },\n\n remove: elementIndex => {\n const snapshot = latest();\n const removed = locate(snapshot, elementIndex);\n\n if (removed === null) {\n return;\n }\n\n // Removing an item shifts every position after it; same reasoning.\n commit(\n snapshot,\n removeArrayItems(\n snapshot.value,\n new Set([removed?.elementIndex ?? elementIndex]),\n kind,\n ),\n removed ? removeIds(snapshot.ids, new Set([removed.index])) : undefined,\n new Set(),\n );\n },\n\n duplicateSelected: () => {\n const snapshot = latest();\n const selected = elementIndicesOf(snapshot, snapshot.selected);\n const next = duplicateArrayItems(snapshot.value, selected);\n const copied = snapshot.items\n .filter(item => selected.has(item.elementIndex))\n .sort((a, b) => a.elementIndex - b.elementIndex)\n .map(() => nanoid(6));\n\n commit(\n snapshot,\n next,\n next ? [...snapshot.ids, ...copied] : undefined,\n selectionAfter(\n { type: 'duplicate', indices: [...snapshot.selected] },\n snapshot.selected,\n snapshot.items.length,\n ),\n );\n },\n\n moveSelected: direction => {\n const snapshot = latest();\n const nextIdentity = moveSelectedIndices(\n snapshot.ids,\n snapshot.selected,\n direction,\n );\n const result = moveArrayItems(\n snapshot.value,\n elementIndicesOf(snapshot, snapshot.selected),\n direction,\n );\n\n if (!result) {\n commit(snapshot, null, undefined, snapshot.selected);\n return;\n }\n\n // Translate the moved source positions back into the visible kind.\n const parsed = parseArrayExpression(result.code);\n const visible =\n parsed?.elements.flatMap((node, index) =>\n t.isExpression(node) && t.isObjectExpression(node) === !isPrimitive\n ? [index]\n : [],\n ) ?? [];\n // The moved block, mapped back from element positions: in a mixed\n // array a step can pass a hidden element, so this is not the same as\n // shifting the visible indices.\n commit(\n snapshot,\n result.code,\n nextIdentity.items,\n new Set(\n visible.flatMap((position, index) =>\n result.indices.has(position) ? [index] : [],\n ),\n ),\n );\n },\n\n removeSelected: () => {\n const snapshot = latest();\n\n commit(\n snapshot,\n removeArrayItems(\n snapshot.value,\n elementIndicesOf(snapshot, snapshot.selected),\n kind,\n ),\n removeIds(snapshot.ids, snapshot.selected),\n new Set(),\n );\n },\n };\n\n // Built fresh each render rather than inside the memo above: these close\n // over `onChange`/`onNodeChange`, and the work is a plain walk of the\n // already-parsed result — no Babel.\n const items: DndItemsItem[] = isPrimitive\n ? primitiveItems.map(item => ({\n id: identity.ids[item.index] ?? item.id,\n index: item.index,\n elementIndex: item.elementIndex,\n properties: [],\n nested: [],\n value: {\n id: `primitive-${item.id}`,\n label: `item-${item.index}`,\n property: item.type,\n value: item.value ?? '',\n rawValue:\n item.type === 'unknown' ? item.source : String(item.value ?? ''),\n canEditValue: canLosslesslyEvaluateSource(item.source),\n onChange: next => updateValue(item.elementIndex, next),\n },\n }))\n : objectItems.map(item => {\n const id = identity.ids[item.index] ?? item.id;\n const properties: PanelBinding[] = Object.entries(\n item.editableProperties,\n ).map(([key, prop]) => {\n const binding = resolveRenderEntry(render, key);\n const propertySource = value.slice(\n prop.astNode.start!,\n prop.astNode.end!,\n );\n\n return {\n ...toBindingFields(binding),\n id: `item-${id}-${key}`,\n // Merged over the leaf's own metadata, never under it: a consumer\n // labels the control with the property's actual kind, as the\n // built-in panel does, so an authored `valueType` can't shadow it.\n meta: { ...binding.meta, valueType: prop.type },\n value: parseValue(String(prop.value)),\n rawValue:\n prop.type === 'unknown' ? propertySource : String(prop.value),\n canEditValue: canLosslesslyEvaluateSource(propertySource),\n onChange: next => updateProperty(item.elementIndex, key, next),\n };\n });\n\n const nested: DndItemsNestedGroup[] = [\n ...Object.entries(item.jsxBindings).map(([property, nodes]) => ({\n property,\n elements: nodes.flatMap(node => {\n const source = resolvePanelBindings(node);\n\n if (!source) {\n return [];\n }\n\n return [\n {\n id: source.id,\n tagName: source.tagName,\n bindings: withPanelCommit(source.bindings, onNodeChange),\n },\n ];\n }),\n })),\n ...Object.entries(item.jsxFallbacks).map(([property, code]) => ({\n property,\n elements: [],\n fallback: {\n id: `item-${id}-${property}-jsx`,\n label: property,\n property,\n type: 'jsx' as const,\n value: code,\n rawValue: code,\n canEditValue: true,\n onChange: (next: unknown) =>\n updateProperty(item.elementIndex, property, next),\n },\n })),\n ];\n\n return {\n id,\n index: item.index,\n elementIndex: item.elementIndex,\n properties,\n nested,\n };\n });\n\n const expansion: DndItemsExpansion = {\n expandedIds: items.flatMap(item =>\n collapsed.has(item.id) ? [] : [item.id],\n ),\n isExpanded: id => !collapsed.has(id),\n toggle: id =>\n setCollapsed(previous => {\n const next = new Set(previous);\n\n if (!next.delete(id)) {\n next.add(id);\n }\n\n return next;\n }),\n setExpanded: ids => {\n const expanded = new Set(ids);\n\n setCollapsed(\n new Set(\n items.flatMap(item => (expanded.has(item.id) ? [] : [item.id])),\n ),\n );\n },\n };\n\n return {\n kind,\n items,\n selection,\n expansion,\n actions,\n canEditStructure,\n parseError,\n };\n};\n","import { Button, Checkbox } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\n\nimport type { BindingRenderMap } from '~/utils/ast';\n\nimport type { PanelNodeChange } from '../dnd';\nimport BulkActionsBar from './bulk-actions-bar';\nimport Field from './field';\nimport { ItemCard, SortableItems } from './sortable-items';\nimport {\n type DndItemsItem,\n type DndItemsNestedGroup,\n useDndItems,\n} from './use-dnd-items';\n\ninterface Props {\n value: string;\n render?: BindingRenderMap;\n onChange?: (value: string) => void;\n onChildChange?: PanelNodeChange;\n}\n\n// The data-bound elements found inside one JSX-valued property, or the\n// raw-source fallback when that property declared no binding at all (#298).\nconst NestedGroup = ({\n group,\n onNodeChange,\n}: {\n group: DndItemsNestedGroup;\n onNodeChange?: PanelNodeChange;\n}) => {\n if (group.fallback) {\n return (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {group.property}\n </div>\n <Field binding={group.fallback} onNodeChange={onNodeChange} />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {group.property} Bindings ({group.elements.length}):\n </div>\n {group.elements.map(element => (\n <div\n key={`${group.property}-${element.id}`}\n data-node-id={element.id}\n className=\"rounded border border-blue-100 bg-blue-50 p-2\n data-[picked]:ring-2 data-[picked]:ring-blue-400\"\n >\n <div className=\"mb-1 text-xs text-blue-600\">\n &lt;{element.tagName}&gt;\n </div>\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {element.bindings.map(binding => (\n <div\n key={`${binding.property}-${binding.label}`}\n className=\"space-y-1\"\n >\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">\n ({binding.property})\n </span>\n </label>\n <Field binding={binding} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n </div>\n </div>\n ))}\n </div>\n );\n};\n\n// Presentation for `useDndItems`. Everything that reads or writes the\n// array source lives in that hook, which is exported so a consumer can put\n// their own markup over the same engine — see its doc comment (#237/#308).\nconst Items = ({ value, render, onChange, onChildChange }: Props) => {\n const {\n kind,\n items,\n selection,\n expansion,\n actions,\n canEditStructure,\n parseError,\n } = useDndItems(value, {\n render,\n onChange,\n onNodeChange: onChildChange,\n });\n\n const header = (\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold\">Items ({items.length})</div>\n {/* Add copies an existing item, so it is offered only once there is\n one to copy — see the empty-list notice below (#316). */}\n {items.length > 0 && canEditStructure && (\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n onClick={actions.add}\n >\n Add Item\n </Button>\n )}\n </div>\n );\n\n if (parseError) {\n return (\n <div className=\"space-y-4\">\n {header}\n <div\n className=\"rounded border border-dashed border-red-200 p-3 text-xs\n text-red-600\"\n >\n This value could not be read as a list. Edit it in the code editor.\n </div>\n </div>\n );\n }\n\n // An array binding is editable only while it holds at least one item: the\n // panel derives an item's shape from its siblings and will not invent one.\n // `removeArrayItems` already refuses to empty a populated array, so this\n // state means the source itself declared `[]` (or only holes/spreads).\n if (items.length === 0) {\n return (\n <div className=\"space-y-4\">\n {header}\n <div\n className=\"rounded border border-dashed border-gray-200 p-3 text-xs\n text-gray-500\"\n >\n No editable items. The panel copies an existing item rather than\n guessing the shape of a new one — add the first item in the code\n editor.\n </div>\n </div>\n );\n }\n\n const bulkBar = (\n <BulkActionsBar\n count={selection.selected.size}\n disabled={!canEditStructure}\n onDuplicate={actions.duplicateSelected}\n onMoveUp={() => actions.moveSelected('up')}\n onMoveDown={() => actions.moveSelected('down')}\n onDelete={actions.removeSelected}\n onClear={selection.clear}\n />\n );\n\n const itemControls = (item: DndItemsItem) => (\n <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={!canEditStructure || item.index === 0}\n onClick={() => actions.move(item.elementIndex, item.index - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={!canEditStructure || item.index === items.length - 1}\n onClick={() => actions.move(item.elementIndex, item.index + 1)}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n disabled={!canEditStructure || items.length <= 1}\n onClick={() => actions.remove(item.elementIndex)}\n />\n </div>\n );\n\n const itemCheckbox = (item: DndItemsItem) => (\n <div\n onClick={e =>\n canEditStructure && selection.toggle(item.index, e.shiftKey)\n }\n className=\"inline-flex\"\n >\n <Checkbox\n checked={selection.isSelected(item.index)}\n disabled={!canEditStructure}\n onChange={() => {}}\n />\n </div>\n );\n\n const objectBody = (item: DndItemsItem) => (\n <>\n <div className=\"space-y-2\">\n {item.properties.map(binding => (\n <div key={`${item.id}-${binding.property}-${binding.label}`}>\n <div className=\"flex flex-col space-y-2\">\n <label className=\"w-20 shrink-0 text-xs font-medium\">\n {binding.label}\n </label>\n <Field binding={binding} onNodeChange={onChildChange} />\n </div>\n <span className=\"text-right text-xs text-gray-500\">\n ({String(binding.meta?.valueType)})\n </span>\n </div>\n ))}\n </div>\n <div className=\"space-y-3 border-t pt-2\">\n {item.nested.length ? (\n item.nested.map(group => (\n <NestedGroup\n key={group.property}\n group={group}\n onNodeChange={onChildChange}\n />\n ))\n ) : (\n <div className=\"text-xs text-gray-500\">✓ No JSX bindings found</div>\n )}\n </div>\n </>\n );\n\n const allExpanded = expansion.expandedIds.length === items.length;\n\n return (\n <div className=\"space-y-4\">\n {header}\n\n {items.length > 1 && (\n <div className=\"flex justify-end\">\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() =>\n expansion.setExpanded(\n allExpanded ? [] : items.map(item => item.id),\n )\n }\n >\n {allExpanded ? 'Collapse all' : 'Expand all'}\n </Button>\n </div>\n )}\n\n {bulkBar}\n\n {!canEditStructure && (\n <div\n className=\"rounded border border-dashed border-amber-200 p-3 text-xs\n text-amber-700\"\n >\n Values remain editable, but moving, copying, adding, and deleting\n require a dense array without spreads or parenthesized top-level\n items. Use the code editor for those structural changes.\n </div>\n )}\n\n <SortableItems\n items={items}\n disabled={!canEditStructure}\n onMove={(item, toIndex) => actions.move(item.elementIndex, toIndex)}\n >\n {item => (\n <ItemCard\n key={item.id}\n id={item.id}\n title={`Item ${item.index + 1}`}\n disabled={!canEditStructure}\n expanded={expansion.isExpanded(item.id)}\n onToggle={() => expansion.toggle(item.id)}\n checkbox={itemCheckbox(item)}\n controls={itemControls(item)}\n className={\n kind === 'primitive'\n ? 'space-y-2 rounded border border-gray-100 bg-gray-50 p-2'\n : 'space-y-3 rounded border bg-gray-50 p-3'\n }\n >\n {kind === 'primitive' ? (\n <Field binding={item.value!} onNodeChange={onChildChange} />\n ) : (\n objectBody(item)\n )}\n </ItemCard>\n )}\n </SortableItems>\n </div>\n );\n};\n\nexport default Items;\n","import {\n type ComponentProps,\n type FocusEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport {\n Checkbox,\n ColorPicker,\n DatePicker,\n Input,\n RichTextEditor,\n Select,\n} from '@jbpark/ui-kit';\nimport { useDebounce } from '@jbpark/use-hooks';\nimport type {\n EditorSelection,\n EditorView,\n ViewUpdate,\n} from '@uiw/react-codemirror';\n\nimport CoreEditor from '~/components/editor/core';\nimport {\n type DataAttrNode,\n parseValue,\n validateBindingValue,\n} from '~/utils/ast';\n\nimport type { PanelBinding, PanelNodeChange } from '../dnd';\nimport { useDndEditOptions } from '../edit-options';\nimport { resolveRenderEntry, toBindingFields } from '../panel-binding';\nimport Children from './children';\nimport { getFieldKind } from './field-kind';\nimport Items from './items';\n\n// Exported as `Live.Dnd.Field` (see index.ts) so a custom panel can\n// hand any single binding back to the built-in control instead of\n// reimplementing it — most usefully for `items`/`children` bindings, whose\n// editors discover nested data-bound elements by re-extracting the value's\n// own JSX (~100 lines of Babel walking a consumer would otherwise have to\n// reproduce). Renders the *control* only; the built-in panel's label comes\n// from `FieldGroup`, so a consumer supplies their own heading and layout.\nexport interface FieldProps {\n binding: PanelBinding;\n // `Items`/`Children` edit a *different* element than `binding` itself —\n // an array item or a sibling child, each with its own id/label/property —\n // which `binding.onChange`'s single-value shape can't express. This is\n // the node-level escape hatch those two need (see #237's documented\n // items/children boundary). Not part of `PanelBinding`, which is\n // per-binding; it reaches a custom panel through `useDndPanel()`\n // instead (#308). Omit it and nested array/children edits won't commit.\n onNodeChange?: PanelNodeChange;\n}\n\nconst normalizeToHex = (value: string): string => {\n const trimmed = value.trim();\n\n if (/^#([0-9A-Fa-f]{3}){1,2}$/.test(trimmed)) {\n return trimmed;\n }\n return '#000000';\n};\n\nconst parseDateValue = (value: string): Date | undefined => {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n\n if (!match) {\n return undefined;\n }\n\n const [, year, month, day] = match;\n const date = new Date(Number(year), Number(month) - 1, Number(day));\n\n return Number.isNaN(date.getTime()) ? undefined : date;\n};\n\nconst formatDateValue = (date: Date): string => {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return `${year}-${month}-${day}`;\n};\n\n// ColorPicker's onChange fires on every drag frame — committing straight\n// to `onChange` (which drives the AST parse/mutate/re-serialize +\n// generateSections + compile pipeline, see #130) makes a single drag cost\n// upward of 15-25ms per frame. Debouncing the *commit* keeps that pipeline\n// to roughly one run per pause instead of one per frame, while a local\n// `liveValue` state keeps the swatch/hex text updating every frame for\n// responsiveness — ColorPicker is fully controlled (`useControllableState`\n// with `value` always set here), so without this it would visually snap\n// back to the last committed color between debounced commits.\nconst COLOR_COMMIT_DELAY = 75;\n\n// A curated subset rather than `toolbar` (every preset): the panel is a\n// small sidebar field, not a full document editor, so this keeps to the\n// formatting controls most binding content actually needs.\nconst RICHTEXT_TOOLBAR: ComponentProps<typeof RichTextEditor>['toolbar'] = [\n 'bold',\n 'italic',\n 'underline',\n 'bulletList',\n 'orderedList',\n 'link',\n];\n\ninterface ColorPickerFieldProps {\n value: string;\n onChange: (value: string) => void;\n}\n\ninterface JSXEditorFieldProps {\n value: string;\n isHTML: boolean;\n onSave: (value: string) => void;\n}\n\n// Moving a keyed item reconnects descendant effects under Strict Effects.\n// `@uiw/react-codemirror` recreates its EditorView during that reconnect,\n// replacing the `.cm-editor` DOM and otherwise losing focus/selection. Keep\n// those user-facing values above the view lifecycle and restore them when the\n// replacement view is created (#359).\nconst JSXEditorField = ({ value, isHTML, onSave }: JSXEditorFieldProps) => {\n const selectionRef = useRef<EditorSelection | null>(null);\n const focusedRef = useRef(false);\n\n const handleUpdate = useCallback((update: ViewUpdate) => {\n selectionRef.current = update.state.selection;\n }, []);\n\n const handleCreateEditor = useCallback((view: EditorView) => {\n if (selectionRef.current) {\n view.dispatch({ selection: selectionRef.current });\n }\n\n if (focusedRef.current) {\n view.focus();\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n focusedRef.current = true;\n }, []);\n\n const handleBlur = useCallback((event: FocusEvent<HTMLDivElement>) => {\n if (\n event.relatedTarget &&\n !event.currentTarget.contains(event.relatedTarget as Node)\n ) {\n focusedRef.current = false;\n }\n }, []);\n\n return (\n <div onFocusCapture={handleFocus} onBlurCapture={handleBlur}>\n <CoreEditor\n value={value}\n height=\"150px\"\n fragment={!isHTML}\n raw={isHTML}\n onSave={onSave}\n onUpdate={handleUpdate}\n onCreateEditor={handleCreateEditor}\n />\n </div>\n );\n};\n\nconst ColorPickerField = ({ value, onChange }: ColorPickerFieldProps) => {\n const [liveValue, setLiveValue] = useState(value);\n // Tracks `value` purely to detect an external change during render (see\n // below) — refs can't be read/written during render, so this has to be\n // state even though nothing here reads `prevValue` itself afterward.\n const [prevValue, setPrevValue] = useState(value);\n const lastCommittedRef = useRef(value);\n\n // The committed `value` can also change from outside (undo/redo, another\n // field touching the same binding) — stay in sync with it rather than\n // only ever tracking our own commits. Adjusted during render (React's\n // recommended \"reset state when a prop changes\" pattern) rather than in\n // an effect, so the mismatched frame never actually paints.\n if (value !== prevValue) {\n setPrevValue(value);\n setLiveValue(value);\n }\n\n // `lastCommittedRef` only needs to be current by the time `commit` next\n // runs (always from an event handler / debounce timer, never render), so\n // syncing it in an effect — instead of alongside the state adjustment\n // above — keeps the ref access out of the render phase entirely.\n useEffect(() => {\n lastCommittedRef.current = value;\n }, [value]);\n\n const commit = (next: string) => {\n if (next === lastCommittedRef.current) {\n return;\n }\n lastCommittedRef.current = next;\n onChange(next);\n };\n\n const debouncedCommit = useDebounce(() => commit(liveValue), {\n delay: COLOR_COMMIT_DELAY,\n autoInvoke: false,\n });\n\n return (\n <ColorPicker\n showText\n value={liveValue}\n onChange={next => {\n setLiveValue(next);\n debouncedCommit();\n }}\n onOpenChange={open => {\n // Flush immediately on close (picker dismissed / selection\n // finished) instead of waiting out the debounce window, so the\n // last color is never at risk of being dropped by an unmount\n // racing the pending timeout.\n if (!open) {\n commit(liveValue);\n }\n }}\n />\n );\n};\n\n// `mb-0` is deliberate: `dist/style.css` ships without a preflight, so a bare\n// `<p>` keeps the UA's `margin-block: 1em` in a consumer that doesn't reset\n// it. That bottom margin collapses out of the field's wrapper and overrides\n// `FieldGroup`'s `space-y-1`, shifting every field below as the error toggles\n// (#409). `mt-1` already declares the top; this declares the bottom.\nconst FieldError = ({ message }: { message: string | null }) =>\n message ? <p className=\"mt-1 mb-0 text-xs text-red-500\">{message}</p> : null;\n\nconst BuiltinField = ({ binding, onNodeChange }: FieldProps) => {\n // `value` is already structured (its real JS type); `rawValue` is the exact\n // source text used for the raw editors (Items/code/textarea) and as the\n // <input> defaultValue. See #238.\n const { id, value, rawValue, onChange } = binding;\n\n const [validationError, setValidationError] = useState<string | null>(null);\n\n // The text-like inputs below (url/number/textarea) commit on blur, so\n // they need local live state to hold what the user is typing. Left\n // uncontrolled (`defaultValue`), they ignored later changes to the canonical\n // value — an undo/redo or another field touching the same binding — because\n // `Field` reconciles rather than remounts (a stable key, now\n // `property`+`label` — see #318).\n // The stale text then got re-committed on blur, clobbering the undo. Track\n // the canonical `rawValue` with a render-phase reset, the same pattern\n // `ColorPickerField` uses above. See #284. (The date picker commits on\n // change, not blur, so it can bind the prop directly with no local state.)\n const [text, setText] = useState(rawValue);\n const [prevRawValue, setPrevRawValue] = useState(rawValue);\n\n if (rawValue !== prevRawValue) {\n setPrevRawValue(rawValue);\n setText(rawValue);\n }\n\n const kind = getFieldKind(binding);\n\n if (kind === 'readonly') {\n return (\n <div\n className=\"space-y-1 rounded border border-dashed border-amber-200 p-3\n text-xs text-amber-700\"\n >\n <div>This expression is preserved but is not editable here.</div>\n <code className=\"block overflow-x-auto text-amber-800\">{rawValue}</code>\n <div>Use the code editor to change it.</div>\n </div>\n );\n }\n\n // Guard against the canonical value with the same shape as the commit:\n // raw source text for string-in/string-out controls, structured values\n // for typed controls. Comparing across those shapes lets no-op edits\n // through when, for example, `'42'` and `42` describe the same field.\n const commitIfChanged = (next: unknown) => {\n const current = typeof next === 'string' ? rawValue : value;\n\n if (next !== current) {\n onChange(next);\n }\n };\n\n if (kind === 'items') {\n return (\n <Items\n value={rawValue}\n render={binding.render}\n onChange={onChange}\n onChildChange={onNodeChange}\n />\n );\n }\n\n if (kind === 'richtext') {\n return (\n <RichTextEditor\n value={rawValue}\n toolbar={RICHTEXT_TOOLBAR}\n onChange={commitIfChanged}\n />\n );\n }\n\n if (kind === 'html' || kind === 'jsx') {\n return (\n <JSXEditorField\n value={rawValue}\n isHTML={kind === 'html'}\n onSave={commitIfChanged}\n />\n );\n }\n\n if (kind === 'children') {\n return (\n <Children\n value={value as DataAttrNode[]}\n onChange={onChange}\n onNodeChange={onNodeChange}\n />\n );\n }\n\n if (kind === 'object') {\n const objectValue = value as Record<string, unknown>;\n\n return (\n <div className=\"space-y-2 rounded border border-gray-200 bg-gray-50 p-2\">\n {Object.entries(objectValue).map(([key, val]) => {\n const nested = resolveRenderEntry(binding.render, key);\n\n return (\n <div key={key} className=\"space-y-1\">\n <label className=\"block text-xs font-medium text-gray-600\">\n {nested.label}\n </label>\n <Field\n binding={{\n ...toBindingFields(nested),\n id,\n value: val,\n rawValue:\n typeof val === 'object' && val !== null\n ? JSON.stringify(val)\n : String(val),\n onChange: next => {\n onChange({ ...objectValue, [key]: next });\n },\n }}\n onNodeChange={onNodeChange}\n />\n </div>\n );\n })}\n </div>\n );\n }\n\n if (kind === 'boolean') {\n return (\n <Checkbox\n checked={value === true || value === 'true'}\n onChange={checked => {\n onChange(checked);\n }}\n />\n );\n }\n\n const stringValue = rawValue;\n\n if (kind === 'select') {\n return (\n <Select\n value={stringValue}\n options={binding.options ?? []}\n onChange={commitIfChanged}\n />\n );\n }\n\n if (kind === 'color') {\n return (\n <ColorPickerField\n value={normalizeToHex(stringValue)}\n onChange={commitIfChanged}\n />\n );\n }\n\n if (kind === 'date') {\n return (\n <div>\n <DatePicker\n value={parseDateValue(stringValue)}\n onChange={date => {\n const next = date ? formatDateValue(date) : '';\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n }\n\n if (kind === 'url') {\n return (\n <div>\n <Input\n type=\"url\"\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"https://example.com\"\n onBlur={e => {\n const next = e.target.value.trim();\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n }\n\n if (kind === 'number') {\n return (\n <div>\n <Input\n type=\"number\"\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"Enter a numeric value\"\n onBlur={e => {\n const raw = e.target.value.trim();\n // Commit a real number, not a numeric string — the AST boundary\n // and `validateBindingValue` (its `min`/`max`) both expect the\n // value as its declared type now. An unparseable entry falls\n // back to the raw text so a genuine mistake still round-trips\n // rather than becoming `NaN`.\n const next: unknown =\n raw !== '' && !Number.isNaN(Number(raw)) ? Number(raw) : raw;\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n }\n\n return (\n <div>\n <Input.TextArea\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"Enter a value\"\n onBlur={e => {\n const raw = e.target.value.trim();\n // Untyped field: infer the value's type from the text the user\n // entered (so `42` commits as a number), the way the old boundary\n // did — but here, in the presentation layer, not by re-guessing in\n // the AST pipeline. A declared string-family type keeps the text\n // verbatim, so `\"{x}\"` stays a string.\n const next: unknown = binding.type ? raw : parseValue(raw);\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n};\n\n// The public control: a consumer's `renderField` gets the first say, with the\n// built-in control as its fallback. Every field goes through here — nested\n// object keys and item properties render `Field` too — so an override\n// reaches them without any per-editor wiring.\nconst Field = (props: FieldProps) => {\n const { renderField } = useDndEditOptions();\n const builtin = <BuiltinField {...props} />;\n\n if (!renderField) {\n return builtin;\n }\n\n const custom = renderField(props, builtin);\n\n return custom === undefined ? builtin : <>{custom}</>;\n};\n\nexport default Field;\n","import type { PanelBinding, PanelNodeChange } from '../dnd';\nimport Field from './field';\n\ninterface Props {\n bindings: PanelBinding[];\n onNodeChange?: PanelNodeChange;\n}\n\n// One bordered group per element `id` — the same visual grouping `Node`\n// (panel/node.tsx) renders, but for the top-level panel list, where\n// `bindings` are already resolved PanelBindings (see dnd.tsx's `bindings`\n// useMemo). `Node` stays a separate component: it still parses a raw\n// DataAttrNode itself, which `Items` needs for elements it discovers\n// dynamically inside an array item's `children` (not present in the\n// top-level `bindings` array at all) — see #237's items/children boundary.\nconst FieldGroup = ({ bindings, onNodeChange }: Props) => (\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {bindings.map(binding => (\n <div key={`${binding.property}-${binding.label}`} className=\"space-y-1\">\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">({binding.property})</span>\n </label>\n <Field binding={binding} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n </div>\n);\n\nexport default FieldGroup;\n","import { useContext, useEffect, useRef } from 'react';\n\nimport { Button, Typography } from '@jbpark/ui-kit';\nimport { ChevronDown, ChevronUp, Trash } from 'lucide-react';\n\nimport type { Section } from '~/types';\nimport { cn } from '~/utils/cn';\n\nimport type { PanelBinding, PanelNodeChange } from '../dnd';\nimport { DndInspectorContext } from '../inspector';\nimport FieldGroup from './field-group';\n\n// The built-in property panel. Reached publicly as `Live.Dnd.Panel`, which\n// is this in the container the desktop pane wants, driven from\n// `useDndPanel()` — every field here lines up with what that hook returns\n// (drop `onChange`, which this panel never needed), so the built-in panel and\n// a custom one run on the same data and the public surface can't drift into a\n// subset of it (#237).\n//\n// `onNodeChange` is the node-level escape hatch `Items`/`Children` use to\n// commit a *different* element's edit than any single\n// `PanelBinding.onChange` can express (see field.tsx's items/children\n// boundary note from step 1). Optional here only so this can be rendered\n// read-only for nested edits; leave it out with real data and nested\n// array/children edits silently don't commit (#308).\nexport interface PanelProps {\n item?: Section;\n onDelete?: (id: string) => void;\n // Reordering by dragging a section on the canvas doesn't work from\n // inside this panel on mobile — the canvas sits behind the Drawer this\n // panel renders in, so there's nothing visible to drag onto. These give\n // an explicit alternative that works regardless of layout.\n onMoveUp?: () => void;\n onMoveDown?: () => void;\n canMoveUp?: boolean;\n canMoveDown?: boolean;\n // `item`'s editable fields, already resolved to PanelBindings by Dnd —\n // the same data a custom panel receives, so this panel doesn't re-derive\n // it from DataAttrNode a second time (#237).\n bindings: PanelBinding[];\n onNodeChange?: PanelNodeChange;\n // The document doesn't parse, so these fields are from the last version\n // that did and edits are refused (#433).\n readOnly?: boolean;\n}\n\n// `bindings` is flat (one entry per bound property, across every editable\n// element in the section) — regroup by `id` to render the same \"one\n// bordered box per element\" layout as before. `bindings` is already\n// ordered element-by-element, property-by-property (dnd.tsx builds it by\n// flat-mapping the extracted fields), so a Map preserves both the element\n// order and each element's own property order with no extra sorting.\n//\n// Not memoized: Dnd rebinds `bindings` every render so its commit callbacks\n// can't go stale against the document (#336), which means a dependency on\n// it would miss every time. This is a single pass over an already-parsed\n// list, so the miss costs more than the walk.\nconst groupBindingsById = (bindings: PanelBinding[]): PanelBinding[][] => {\n const groups = new Map<string, PanelBinding[]>();\n\n for (const binding of bindings) {\n const group = groups.get(binding.id);\n\n if (group) {\n group.push(binding);\n } else {\n groups.set(binding.id, [binding]);\n }\n }\n\n return [...groups.values()];\n};\n\nconst Panel = ({\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp = false,\n canMoveDown = false,\n bindings,\n onNodeChange,\n readOnly = false,\n}: PanelProps) => {\n const groups = groupBindingsById(bindings);\n const rootRef = useRef<HTMLDivElement>(null);\n // Read without the throwing hook: this panel also renders outside\n // `Live.Dnd`, read-only, where there's no picker.\n const picked = useContext(DndInspectorContext)?.picked ?? null;\n const pickedId = picked?.id;\n\n // Brings the fields of an element picked in the preview into view and\n // marks them, whether they're a top-level group or nested in an Items or\n // Children editor (#432). A collapsed array item hides its nested fields,\n // so there's nothing to scroll to then.\n useEffect(() => {\n const root = rootRef.current;\n\n if (!root || !pickedId) {\n return;\n }\n\n const target = root.querySelector(\n `[data-node-id=\"${CSS.escape(pickedId)}\"]`,\n );\n\n if (!target) {\n return;\n }\n\n target.setAttribute('data-picked', '');\n\n // Fields above the target can still grow for a moment after it renders\n // (a rich-text editor mounting, for one), pushing it back out of view.\n // So keep it in view for the first few hundred milliseconds.\n const until = performance.now() + 600;\n let frame = 0;\n\n const keepInView = () => {\n const box = target.getBoundingClientRect();\n const view = root.getBoundingClientRect();\n\n if (box.top < view.top || box.bottom > view.bottom) {\n target.scrollIntoView?.({ block: 'nearest' });\n }\n\n if (performance.now() < until) {\n frame = requestAnimationFrame(keepInView);\n }\n };\n\n keepInView();\n\n return () => {\n cancelAnimationFrame(frame);\n target.removeAttribute('data-picked');\n };\n }, [pickedId, groups.length]);\n\n if (!item) {\n return (\n <Typography.Paragraph\n className={cn(\n 'p-4 text-sm text-gray-500',\n //\n )}\n >\n Please select a section.\n </Typography.Paragraph>\n );\n }\n\n return (\n <div\n ref={rootRef}\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 {readOnly && (\n <Typography.Text role=\"status\" className=\"block text-xs text-amber-700\">\n The document has a syntax error. These fields are from the last\n version that parsed, and can&apos;t be edited until it parses again.\n </Typography.Text>\n )}\n {!groups.length && (\n <Typography.Text className=\"text-xs text-gray-400\">\n No editable elements.\n </Typography.Text>\n )}\n {groups.map(group => (\n <div\n key={group[0]!.id}\n data-node-id={group[0]!.id}\n className=\"rounded data-[picked]:ring-2 data-[picked]:ring-blue-400\n data-[picked]:ring-offset-2\"\n >\n <FieldGroup bindings={group} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n );\n};\n\nexport default Panel;\n","import { Button, Drawer, Space, Splitter } from '@jbpark/ui-kit';\nimport { Crosshair, LayoutGrid } from 'lucide-react';\n\nimport { cn } from '~/utils/cn';\n\nimport { DefaultDraggableItem } from './draggable';\nimport { useDndInspector } from './inspector';\nimport { useDndRegions } from './layout-context';\nimport PropertyPanel from './panel';\n\n// The regions take their content from context, so `children` is never a\n// consumer's to pass — everything else about the wrapper div is (className\n// is tailwind-merged over the defaults, so overriding one of them wins\n// rather than fighting).\nexport type DndRegionProps = Omit<\n React.ComponentPropsWithRef<'div'>,\n 'children'\n>;\n\n// The built-in palette and panel without their region wrapper. Both exist\n// because `Layout` renders them twice on mobile — once in a pane, once in a\n// Drawer that's already the scroll container and shouldn't inherit the\n// pane's background.\nconst PaletteItems = ({ subject }: { subject: string }) => {\n const {\n palette: { items, onAdd },\n isMobile,\n } = useDndRegions(subject);\n\n return (\n <Space orientation=\"vertical\" align=\"start\">\n {items.map(item => (\n <DefaultDraggableItem\n key={item.id}\n item={item}\n onAdd={onAdd}\n tapToAdd={isMobile}\n />\n ))}\n </Space>\n );\n};\n\nconst PanelFields = ({ subject }: { subject: string }) => {\n const {\n panel: {\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp,\n canMoveDown,\n bindings,\n onNodeChange,\n readOnly,\n },\n } = useDndRegions(subject);\n\n return (\n <PropertyPanel\n item={item}\n onDelete={onDelete}\n onMoveUp={onMoveUp}\n onMoveDown={onMoveDown}\n canMoveUp={canMoveUp}\n canMoveDown={canMoveDown}\n bindings={bindings}\n onNodeChange={onNodeChange}\n readOnly={readOnly}\n />\n );\n};\n\n// The built-in palette, in the scroll container the desktop pane wants.\n// Replace it by putting your own component in `Layout`'s `palette` slot, or\n// anywhere in `Live.Dnd`'s children — `useDndPalette()` hands over the same\n// items and `onAdd` this reads.\nexport const Palette = ({ className, ...restProps }: DndRegionProps) => (\n <div\n className={cn(\n 'h-full overflow-y-auto bg-gray-50 p-4',\n className,\n //\n )}\n {...restProps}\n >\n <PaletteItems subject=\"<Live.Dnd.Palette>\" />\n </div>\n);\n\n// Owns the scroll container each section's iframe resolves by\n// `closest('[data-frame-container]')` to size itself against (see\n// frame/iframe.tsx), plus the containment/isolation styles that keep a\n// section's compiled CSS out of the editor chrome — hence a region rather\n// than a plain slot: a custom layout can move it, not lose it. Needs a\n// height-constrained parent, since it fills one (`h-full`). Render it\n// exactly once — the droppable and the sortable list inside use fixed ids,\n// and a second instance would duplicate both.\nexport const Canvas = ({ className, style, ...restProps }: DndRegionProps) => {\n const { canvas, documentError } = useDndRegions('<Live.Dnd.Canvas>');\n const inspector = useDndInspector();\n\n return (\n <div\n className={cn(\n 'relative h-full w-full overflow-y-auto',\n className,\n //\n )}\n data-frame-container\n style={{\n isolation: 'isolate',\n contain: 'layout style',\n transform: 'translateZ(0)',\n ...style,\n }}\n {...restProps}\n >\n {canvas}\n {/* The element picker's switch (#432). Pinned to the bottom-left of\n the scroll area, clear of the selected section's own buttons at its\n top-right and of the mobile palette button at the bottom-right. */}\n {!documentError && (\n <div className=\"pointer-events-none sticky bottom-0 z-70 h-0\">\n <div className=\"pointer-events-auto absolute bottom-3 left-3\">\n <Button\n icon={<Crosshair />}\n color=\"primary\"\n variant={inspector.active ? 'solid' : 'outlined'}\n aria-pressed={inspector.active}\n aria-label=\"Pick an element\"\n title={\n inspector.active\n ? 'Click an element to edit it. Esc to cancel.'\n : 'Pick an element'\n }\n onClick={inspector.toggle}\n />\n </div>\n </div>\n )}\n </div>\n );\n};\n\n// The built-in property panel. Same deal as `Palette`: replace it via\n// `Layout`'s `panel` slot or by placing your own component in `Live.Dnd`'s\n// children, driving it from `useDndPanel()`.\nexport const Panel = ({ className, ...restProps }: DndRegionProps) => (\n <div\n className={cn(\n 'h-full',\n className,\n //\n )}\n {...restProps}\n >\n <PanelFields subject=\"<Live.Dnd.Panel>\" />\n </div>\n);\n\nexport interface DndLayoutProps {\n // Replacements for the palette/panel regions, kept as slots so swapping\n // one out doesn't mean rebuilding the 3-pane Splitter and the mobile\n // Drawers around it. A slot is placed raw — it owns its own container,\n // unlike the built-in regions, which bring theirs. Drive it from\n // `useDndPalette()` / `useDndPanel()`.\n palette?: React.ReactNode;\n panel?: React.ReactNode;\n}\n\n// What `Live.Dnd` renders when given no children — the 3-pane desktop\n// Splitter, the stacked mobile canvas, and the mobile FAB/Drawers. Exported\n// so children can keep the built-in arrangement while wrapping it (a toolbar\n// above it, say) or while replacing just one region — and because\n// `@jbpark/ui-kit` is a dependency rather than a peer, so `Splitter` isn't\n// necessarily importable on the consumer's side.\nexport const Layout = ({ palette, panel }: DndLayoutProps) => {\n const { isMobile, selectedId, clearSelection, paletteOpen, setPaletteOpen } =\n useDndRegions('<Live.Dnd.Layout>');\n\n return (\n <>\n {isMobile ? (\n <Canvas />\n ) : (\n <Splitter withHandle orientation=\"horizontal\">\n <Splitter.Panel\n defaultSize=\"20%\"\n minSize=\"15%\"\n maxSize=\"35%\"\n collapsible\n >\n {palette ?? <Palette />}\n </Splitter.Panel>\n <Splitter.Panel defaultSize=\"60%\">\n <Canvas />\n </Splitter.Panel>\n <Splitter.Panel\n defaultSize=\"20%\"\n minSize=\"15%\"\n maxSize=\"35%\"\n collapsible\n >\n {panel ?? <Panel />}\n </Splitter.Panel>\n </Splitter>\n )}\n <Button\n type=\"primary\"\n shape=\"circle\"\n icon={<LayoutGrid />}\n aria-label=\"Components\"\n className=\"fixed right-4 bottom-4 z-20 md:hidden\"\n onClick={() => setPaletteOpen(true)}\n />\n {/* A slot goes in as-is; the built-ins go in without their region\n wrapper, since the Drawer is already the scroll container and the\n palette's gray background belongs to the desktop pane. */}\n <Drawer\n open={isMobile && paletteOpen}\n onClose={() => setPaletteOpen(false)}\n direction=\"bottom\"\n size=\"large\"\n title=\"Components\"\n >\n {palette ?? <PaletteItems subject=\"<Live.Dnd.Layout>\" />}\n </Drawer>\n <Drawer\n open={isMobile && Boolean(selectedId)}\n onClose={clearSelection}\n direction=\"bottom\"\n size=\"large\"\n title=\"Properties\"\n >\n {panel ?? <PanelFields subject=\"<Live.Dnd.Layout>\" />}\n </Drawer>\n </>\n );\n};\n\nexport default Layout;\n","import { createContext } from 'react';\n\nimport type { Section } from '~/types';\n\nexport interface DndSectionFallbackArgs {\n section: Section;\n // `compile`: the section's code failed to compile. `runtime`: it threw\n // while rendering. `forced`: `shouldForceSectionFallback` returned true, so\n // it was never compiled.\n reason: 'compile' | 'runtime' | 'forced';\n // The compiler or runtime message. `undefined` for `forced`.\n message?: string;\n}\n\n// Return a node to show in the section's place, or `undefined` for the\n// built-in error box.\nexport type DndRenderSectionFallback = (\n args: DndSectionFallbackArgs,\n) => React.ReactNode | undefined;\n\n// Only `SectionFallback` reads this, and it renders only for a failed\n// section, so a host passing a fresh inline function each render re-renders\n// those fallbacks alone, never a healthy memoized section (#97).\nexport const SectionFallbackContext = createContext<\n DndRenderSectionFallback | undefined\n>(undefined);\n","import { useContext } from 'react';\n\nimport ErrorBoundary from '~/components/error/boundary';\n\nimport {\n type DndRenderSectionFallback,\n type DndSectionFallbackArgs,\n SectionFallbackContext,\n} from './section-fallback-context';\n\ninterface ConsumerFallbackProps {\n render: DndRenderSectionFallback;\n args: DndSectionFallbackArgs;\n builtin: React.ReactElement;\n}\n\n// Its own component so the consumer's function runs inside the guard below:\n// a throw from the call itself, not only from what it returns, is caught.\nconst ConsumerFallback = ({ render, args, builtin }: ConsumerFallbackProps) => {\n const node = render(args);\n\n return node === undefined ? builtin : <>{node}</>;\n};\n\ninterface Props {\n args: DndSectionFallbackArgs;\n // What renders when no consumer fallback is set, when it returns\n // `undefined`, or when it throws.\n builtin: React.ReactElement;\n}\n\nconst SectionFallback = ({ args, builtin }: Props) => {\n const render = useContext(SectionFallbackContext);\n\n if (!render) {\n return builtin;\n }\n\n // A broken fallback must not break the canvas: revert to the built-in\n // error for this section only.\n return (\n <ErrorBoundary fallback={() => builtin}>\n <ConsumerFallback render={render} args={args} builtin={builtin} />\n </ErrorBoundary>\n );\n};\n\nexport default SectionFallback;\n","import { memo } from 'react';\n\nimport ErrorBoundary from '~/components/error/boundary';\nimport LiveError from '~/components/error/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { useCompiledModule } from '~/components/preview/use-compiled-module';\nimport { useDynamicTailwind } from '~/components/preview/use-dynamic-tailwind';\n\nimport SectionFallback from './section-fallback';\n\ninterface Props {\n preview: string;\n // The section's identity for `renderSectionFallback`, as primitives rather\n // than the `Section` object: sections are re-extracted on every document\n // change, so an object prop would defeat the memo below.\n sectionId?: string;\n sectionName?: string;\n sectionCode?: string;\n // Skip compiling and render the fallback (`shouldForceSectionFallback`).\n forceFallback?: boolean;\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 sectionId = '',\n sectionName = '',\n sectionCode = preview,\n forceFallback = false,\n headers,\n modules,\n frame,\n dynamicTailwind = false,\n provider,\n}: Props) => {\n // Empty code compiles to nothing, so a forced section never reaches the\n // compiler or runs any of its top-level code.\n const module = useCompiledModule(forceFallback ? '' : preview, modules);\n const section = { id: sectionId, name: sectionName, code: sectionCode };\n\n // In `shadow` mode there's no separate document to load a stylesheet into\n // — the shadow root only gets whatever CSS naturally inherits across the\n // boundary (see `frame/shadow.tsx`), not utility classes. So this section's\n // own Tailwind classes are compiled and portalled in as a `<style>` tag\n // alongside the rendered content, which crosses the shadow boundary fine\n // since it lives inside the same portal target.\n const { ref: wrapperRef, css: dynamicCSS } = useDynamicTailwind(\n preview,\n dynamicTailwind && !forceFallback,\n );\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\n };\n\n // Rendered in place of the frame rather than inside it: there is nothing to\n // portal into an iframe for code that never produced a component, and a\n // silent blank slot (the previous behaviour) gives the author no clue why\n // their section vanished. Mirrors preview/client.tsx's compile-error branch.\n if (forceFallback) {\n return (\n <SectionFallback\n args={{ section, reason: 'forced' }}\n builtin={\n <LiveError\n message=\"This section is not rendered in this editor.\"\n title=\"Section Unavailable\"\n />\n }\n />\n );\n }\n\n if (module?.error) {\n return (\n <SectionFallback\n args={{ section, reason: 'compile', message: module.error }}\n builtin={<LiveError message={module.error} title=\"Compile Error\" />}\n />\n );\n }\n\n const Component = module?.exports?.default;\n\n if (!Component) {\n return null;\n }\n\n return (\n <Frame {...frame} autoHeight>\n {container => (\n <div\n ref={wrapperRef}\n className=\"w-full overflow-x-hidden\"\n data-editor-mode\n >\n {/*\n Without this, a render error in any single canvas section\n propagated past Dnd and unmounted the whole editor — palette,\n canvas and panel — while the same error in <Preview> was caught\n and displayed (see #246). Kept inside the frame so the failure is\n reported in the slot the broken section occupies, and so a\n transient error while the author is mid-edit doesn't tear down and\n rebuild the iframe (script loading, style sync, resize observers)\n on every keystroke. `Error` is inline-styled, so it stays readable\n even in a frame that never received the host's CSS.\n\n resetKeys={[preview]} makes the fix itself the recovery signal: the\n next edit to this section produces a new preview string, which\n clears the caught error without needing a remount.\n\n No `Error.Guard` here, unlike client.tsx: it listens on `window`,\n not on its subtree, so one per section would mean N global\n listeners all tripping on any single error — every section would\n show a runtime error regardless of which one actually threw.\n\n Errors also stay local rather than going to ErrorContext, whose\n `error` is a single string shared by the whole tree: N sections\n reporting into it would overwrite each other with no way to tell\n which section failed.\n */}\n <ErrorBoundary\n resetKeys={[preview]}\n fallback={(message, reset) => (\n <SectionFallback\n args={{ section, reason: 'runtime', message }}\n builtin={\n <LiveError\n message={message}\n onReset={reset}\n title=\"Rendering Error\"\n />\n }\n />\n )}\n >\n {renderProvider(\n <>\n <Component\n headers={headers}\n container={container}\n //\n />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </>,\n )}\n </ErrorBoundary>\n </div>\n )}\n </Frame>\n );\n};\n\n// `frame` is configuration — strings, flags, string arrays, a style object —\n// and callers usually write it inline (`frame={{ mode: 'iframe' }}`), so it is\n// a new object on every render. Compared by identity, that alone re-rendered\n// every section on every edit (#348). Compare it by value instead: arrays by\n// their entries, objects (`style`) shallowly, anything else — a callback\n// included — by identity, so a changed `onLoaded` still re-renders.\nconst sameValue = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) {\n return true;\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((item, i) => Object.is(item, b[i]));\n }\n\n if (\n a &&\n b &&\n typeof a === 'object' &&\n typeof b === 'object' &&\n Object.getPrototypeOf(a) === Object.prototype &&\n Object.getPrototypeOf(b) === Object.prototype\n ) {\n const aKeys = Object.keys(a);\n\n return (\n aKeys.length === Object.keys(b).length &&\n aKeys.every(key =>\n Object.is(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n ),\n )\n );\n }\n\n return false;\n};\n\nconst sameFrame = (a?: FrameProps, b?: FrameProps): boolean => {\n if (a === b) {\n return true;\n }\n\n if (!a || !b) {\n return false;\n }\n\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n\n return [...keys].every(key =>\n sameValue(a[key as keyof FrameProps], b[key as keyof FrameProps]),\n );\n};\n\n// Every other prop is compared by identity, as `memo` does by default.\nconst arePropsEqual = (prev: Props, next: Props): boolean => {\n const keys = new Set([...Object.keys(prev), ...Object.keys(next)]);\n\n return [...keys].every(key =>\n key === 'frame'\n ? sameFrame(prev.frame, next.frame)\n : Object.is(prev[key as keyof Props], next[key as keyof Props]),\n );\n};\n\nexport default memo(Renderer, arePropsEqual);\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/cn';\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 // Registers the focusable wrapper, so the canvas can move focus to it.\n nodeRef?: (node: HTMLElement | null) => void;\n // Arrow keys and Home/End on a focused section, outside a drag (#435).\n onNavigate?: (to: SectionNavigation) => void;\n // Delete or Backspace on a focused section (#435).\n onDeleteKey?: () => void;\n // The element picker is on (#432): the section can't be dragged, and the\n // pointer over it reports positions instead of selecting it.\n inspecting?: boolean;\n onInspectMove?: (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => void;\n onInspectPick?: (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => void;\n onInspectLeave?: () => void;\n}\n\nexport type SectionNavigation = 'previous' | 'next' | 'first' | 'last';\n\nconst NAVIGATION_KEYS: Record<string, SectionNavigation> = {\n ArrowUp: 'previous',\n ArrowDown: 'next',\n Home: 'first',\n End: 'last',\n};\n\nconst Sortable = ({\n id,\n children,\n selected,\n onClick,\n onDelete: _onDelete,\n onCopy: _onCopy,\n nodeRef,\n onNavigate,\n onDeleteKey,\n inspecting = false,\n onInspectMove,\n onInspectPick,\n onInspectLeave,\n}: Props) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n setActivatorNodeRef,\n transform,\n transition,\n isDragging,\n isOver,\n active,\n } = useSortable({ id, disabled: inspecting });\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n opacity: isDragging ? 0.5 : 1,\n cursor: inspecting ? 'crosshair' : 'grab',\n };\n\n const isNewItemOver = isOver && active?.data.current?.type === 'new-item';\n\n // The wrapper is a `role=\"button\"`, so Enter selects it the way a click\n // does. Only when the key lands on the wrapper itself, not on its copy and\n // delete buttons, and not while a drag is on (Enter drops one then) (#435).\n //\n // The same rule covers the other keys handled here. Keys pressed inside a\n // section's own inputs never count: those sit in the section's frame, or\n // retarget to its shadow host, so the event target isn't the wrapper.\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n listeners?.onKeyDown?.(e);\n\n if (e.target !== e.currentTarget || active || e.defaultPrevented) {\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault();\n onClick?.();\n\n return;\n }\n\n const to = NAVIGATION_KEYS[e.key];\n\n if (to && onNavigate) {\n // Otherwise the arrow keys also scroll the canvas.\n e.preventDefault();\n onNavigate(to);\n\n return;\n }\n\n if ((e.key === 'Delete' || e.key === 'Backspace') && onDeleteKey) {\n e.preventDefault();\n onDeleteKey();\n }\n };\n\n // The same element is the activator, so Space on the copy or delete button\n // presses that button instead of picking the section up.\n const setRefs = (node: HTMLDivElement | null) => {\n setNodeRef(node);\n setActivatorNodeRef(node);\n nodeRef?.(node);\n };\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={setRefs}\n style={style}\n {...attributes}\n {...listeners}\n onKeyDown={onKeyDown}\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 onPointerMove={\n inspecting\n ? e =>\n onInspectMove?.(\n e.currentTarget.parentElement!,\n e.currentTarget,\n e.clientX,\n e.clientY,\n )\n : undefined\n }\n onPointerLeave={inspecting ? onInspectLeave : undefined}\n onClick={\n inspecting\n ? e => {\n // The pick selects the section itself.\n e.stopPropagation();\n onInspectPick?.(\n e.currentTarget.parentElement!,\n e.currentTarget,\n e.clientX,\n e.clientY,\n );\n }\n : undefined\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/sections';\n\nimport { DefaultDraggableItem } from './draggable';\nimport Renderer from './renderer';\nimport Sortable from './sortable';\n\ninterface Props {\n sections: Section[];\n isForced?: (section: Section) => boolean;\n renderProps: {\n fullCode: string;\n containerId?: string;\n modules: Record<string, unknown>;\n frame?: FrameProps;\n dynamicTailwind?: boolean;\n };\n}\n\nconst Overlay = ({ sections, isForced, 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 containerId: renderProps.containerId,\n });\n\n return (\n <Sortable id={section.id} name={section.name}>\n <Renderer\n preview={preview}\n sectionId={section.id}\n sectionName={section.name}\n sectionCode={section.code}\n forceFallback={isForced?.(section) ?? false}\n modules={renderProps.modules}\n frame={renderProps.frame}\n dynamicTailwind={renderProps.dynamicTailwind}\n />\n </Sortable>\n );\n }\n\n return null;\n};\n\nexport default Overlay;\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { arrayMove } from '@dnd-kit/sortable';\n\nimport type { Section } from '~/types';\nimport {\n type DocumentProblem,\n type SectionOptions,\n fillSectionIds,\n inspectDocument,\n replaceIds,\n} from '~/utils/ast';\nimport {\n createSectionPreviewCache,\n extractSections,\n replaceSections,\n} from '~/utils/sections';\n\nimport { usePreview } from '../context/states';\n\nexport interface SectionDocument {\n sections: Section[];\n previews: string[];\n selectedId: string | null;\n selectedItem?: Section;\n selectedIndex: number;\n select: (id: string) => void;\n // Selects `id` outright, where `select` toggles. For keyboard navigation,\n // which lands on a section and must not deselect it (#435).\n selectOnly: (id: string) => void;\n clearSelection: () => void;\n add: (item: Pick<Section, 'name' | 'code'>, atIndex?: number) => void;\n remove: (id: string) => void;\n copy: (id: string) => void;\n move: (id: string | null, direction: 'up' | 'down') => void;\n reorder: (activeId: string, overId: string) => void;\n patch: (next: Partial<Section> & { id: string }) => void;\n // The section as the latest commit left it, when a commit has landed since\n // this render; `undefined` when nothing has, or when that commit removed\n // it. Lets a caller that edits inside a section build on a same-tick\n // commit instead of this render's `sections` (#450).\n getCommittedSection: (id: string) => Section | undefined;\n // Why `value` isn't a usable document, or `null` when it is (#433, #449).\n problem: DocumentProblem | null;\n // True while `value` doesn't parse and `sections`/`previews` are the last\n // ones that did. Every mutation is refused then, through `onBlockedEdit`:\n // the only ranges to edit are from a different source (#433).\n stale: boolean;\n}\n\nexport interface SectionDocumentOptions extends SectionOptions {\n // Called instead of committing when a mutation is refused because the\n // document doesn't parse. Pass a stable function.\n onBlockedEdit?: (problem: DocumentProblem) => void;\n}\n\n// The last document that parsed, per container id. A box held in `useState`\n// and written from the derivation below, like `createSectionPreviewCache`:\n// it only remembers a value, it never decides what renders on its own.\nconst createLastParsed = () => {\n let last: { containerId?: string; document: string } | null = null;\n\n return {\n read: (containerId?: string) =>\n last && last.containerId === containerId ? last.document : undefined,\n write: (containerId: string | undefined, document: string) => {\n last = { containerId, document };\n },\n };\n};\n\n// Owns the document side of the DnD canvas: deriving sections from the code\n// string, tracking which one is selected, and committing every mutation.\n//\n// Extracted from Dnd (#245), where the commit sequence\n// `replaceSections -> onChange -> setCode` was spelled out seven separate\n// times. Naming it once means no mutation can perform half of it, and it\n// puts the section logic somewhere reachable without rendering dnd-kit.\nexport const useSectionDocument = (\n value: string,\n onChange?: (value: string) => void,\n {\n containerId,\n sectionNameFallback,\n onBlockedEdit,\n }: SectionDocumentOptions = {},\n): SectionDocument => {\n const { setCode } = usePreview();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n // Every read of a document into sections goes through here, so a section\n // without `data-name` is named the same way wherever it's read (#448).\n const readSections = useCallback(\n (code: string) =>\n extractSections(code, { containerId, sectionNameFallback }),\n [containerId, sectionNameFallback],\n );\n\n // Sections identify themselves by `data-id`; `getSections` falls back to a\n // positional id for documents predating that (see #245). Filling the gap\n // here makes the ids below real identities rather than positions, so a\n // held `selectedId` survives an insert, copy, move or delete.\n //\n // Deliberately not committed on its own — like dnd.tsx's existing use of\n // fillIds for field ids, the filled document only reaches\n // `onChange`/`setCode` when a real mutation commits, so merely opening a\n // document never rewrites the author's code.\n const document = useMemo(\n () => fillSectionIds(value, undefined, { containerId }),\n [containerId, value],\n );\n\n // What the canvas and panel show. Normally `document` itself. While the\n // source doesn't parse, which is usually the moment an author is typing in\n // the code editor, it's the last version that did, so the canvas and panel\n // keep their content instead of emptying on every keystroke (#433). A\n // missing container isn't covered: that isn't a passing state, and the\n // canvas says what's wrong instead (#449).\n //\n // Not a regex scan of the broken source: section ranges are where every\n // commit writes back, and a guessed range could put an edit in the wrong\n // place. The last parsed version is shown read-only instead.\n const [lastParsed] = useState(createLastParsed);\n const view = useMemo(() => {\n const inspection = inspectDocument(document, { containerId });\n\n if (inspection.ok) {\n lastParsed.write(containerId, document);\n\n return { document, problem: null, stale: false };\n }\n\n const { ok: _ok, ...problem } = inspection;\n const last =\n problem.reason === 'parse-error'\n ? lastParsed.read(containerId)\n : undefined;\n\n return { document: last ?? document, problem, stale: last !== undefined };\n }, [containerId, document, lastParsed]);\n\n const sections = useMemo(\n () => readSections(view.document),\n [readSections, view.document],\n );\n\n // One cache per hook instance (lazy `useState` initializer, never\n // replaced) — see createSectionPreviewCache (#131). It's stateful by\n // design (remembers the previous render's previews to reuse the ones that\n // didn't change), which a `useMemo`/`useRef` can't do without touching a\n // ref during render; a cache object stored via `useState` and only ever\n // mutated through its own method isn't subject to that restriction the way\n // `ref.current` is.\n const [previewCache] = useState(() => createSectionPreviewCache());\n const previews = useMemo(\n () => previewCache.compute(view.document, sections, { containerId }),\n [containerId, previewCache, sections, view.document],\n );\n\n const selectedIndex = sections.findIndex(s => s.id === selectedId);\n const selectedItem = selectedIndex >= 0 ? sections[selectedIndex] : undefined;\n\n // The document the last commit produced, tagged with the render document\n // it was built on. A commit's own `document`/`sections` are this render's\n // snapshot, and the host only hands the new value back on the next render,\n // so two commits in the same tick both started from the snapshot and the\n // second wrote the first one's section back as it was (#450). Every\n // mutation below reads through `latestDocument()` instead.\n //\n // Dropped after each render: from then on the render's own `value` is the\n // source of truth, including when the host chose not to accept a commit.\n // The `from` check covers the window between that render and this effect.\n const pendingRef = useRef<{ from: string; code: string } | null>(null);\n\n useEffect(() => {\n pendingRef.current = null;\n });\n\n const latestDocument = useCallback(() => {\n const pending = pendingRef.current;\n\n return pending?.from === document ? pending.code : document;\n }, [document]);\n\n // `extractSections` goes through the document parse cache, so re-reading\n // an unchanged document here costs a cache hit, not a parse.\n const latestSections = useCallback(\n () => readSections(latestDocument()),\n [latestDocument, readSections],\n );\n\n // The single place a set of sections becomes a new document. Takes only\n // `code` because that is genuinely all a commit reads — ids and names are\n // re-derived from the result, never carried across.\n //\n // Runs `fillSectionIds` on the way out so a section that arrived without\n // one still lands with an id: a palette template is a bare `<section>`\n // snippet with no `#app-container`, so it cannot be filled until after\n // it's spliced in. Returns the resulting sections so a caller that needs\n // to select what it just created can read the real id back rather than\n // inventing one.\n const commit = useCallback(\n (nextSections: { code: string }[]): Section[] => {\n const nextCode = fillSectionIds(\n replaceSections(\n latestDocument(),\n nextSections.map(s => s.code),\n { containerId },\n ),\n undefined,\n { containerId },\n );\n\n pendingRef.current = { from: document, code: nextCode };\n onChange?.(nextCode);\n setCode(nextCode);\n\n return readSections(nextCode);\n },\n [containerId, document, latestDocument, onChange, readSections, setCode],\n );\n\n const getCommittedSection = useCallback(\n (id: string) => {\n const pending = pendingRef.current;\n\n if (pending?.from !== document) {\n return undefined;\n }\n\n return readSections(pending.code).find(s => s.id === id);\n },\n [document, readSections],\n );\n\n // Every mutation starts here. Refusing up front, rather than letting the\n // edit reach `replaceSections`, matters: on a source that doesn't parse\n // that returns the source unchanged, so the edit used to \"commit\" nothing\n // and say nothing.\n const { problem, stale } = view;\n const refuse = useCallback(() => {\n if (!stale || !problem) {\n return false;\n }\n\n onBlockedEdit?.(problem);\n\n return true;\n }, [onBlockedEdit, problem, stale]);\n\n const select = useCallback((id: string) => {\n setSelectedId(prev => (prev === id ? null : id));\n }, []);\n\n const selectOnly = useCallback((id: string) => setSelectedId(id), []);\n\n const clearSelection = useCallback(() => setSelectedId(null), []);\n\n const add = useCallback(\n (item: Pick<Section, 'name' | 'code'>, atIndex?: number) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n const next = { code: item.code };\n\n commit(\n atIndex === undefined || atIndex < 0\n ? [...current, next]\n : [...current.slice(0, atIndex), next, ...current.slice(atIndex)],\n );\n },\n [commit, refuse, latestSections],\n );\n\n const remove = useCallback(\n (id: string) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n // Removes by position, not by predicate: `fillSectionIds` keeps ids\n // unique, but a filter would delete every match if that invariant ever\n // slipped — and this is the one destructive operation here, so it\n // shouldn't be the one relying on it.\n const index = current.findIndex(s => s.id === id);\n\n if (index < 0) {\n return;\n }\n\n // Only the deleted section loses the selection. The previous\n // implementation cleared it unconditionally, so deleting any section\n // closed the panel for whichever one was open.\n if (id === selectedId) {\n setSelectedId(null);\n }\n\n commit(current.filter((_, i) => i !== index));\n },\n [commit, refuse, latestSections, selectedId],\n );\n\n const copy = useCallback(\n (id: string) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n const index = current.findIndex(s => s.id === id);\n const source = current[index];\n\n if (!source) {\n return;\n }\n\n // replaceIds refreshes every data-id in the snippet, the section's own\n // included, so the copy carries a distinct identity into the document.\n const committed = commit([\n ...current.slice(0, index + 1),\n { code: replaceIds(source.code) },\n ...current.slice(index + 1),\n ]);\n\n // Read the new id back from the committed document. This used to\n // select a `uuidv4()` that was never written into the code and so\n // didn't exist after the next parse, leaving the panel empty right\n // after a copy (#245).\n setSelectedId(committed[index + 1]?.id ?? null);\n },\n [commit, refuse, latestSections],\n );\n\n const move = useCallback(\n (id: string | null, direction: 'up' | 'down') => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n const index = current.findIndex(s => s.id === id);\n const targetIndex = direction === 'up' ? index - 1 : index + 1;\n\n if (index < 0 || targetIndex < 0 || targetIndex >= current.length) {\n return;\n }\n\n // No `setSelectedId` compensation needed any more: the id travels with\n // the section's own markup, so the selection follows it across a move.\n commit(arrayMove(current, index, targetIndex));\n },\n [commit, refuse, latestSections],\n );\n\n const reorder = useCallback(\n (activeId: string, overId: string) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n const prevIndex = current.findIndex(s => s.id === activeId);\n const nextIndex = current.findIndex(s => s.id === overId);\n\n if (prevIndex < 0 || nextIndex < 0 || prevIndex === nextIndex) {\n return;\n }\n\n commit(arrayMove(current, prevIndex, nextIndex));\n },\n [commit, refuse, latestSections],\n );\n\n const patch = useCallback(\n (next: Partial<Section> & { id: string }) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n commit(current.map(s => (s.id === next.id ? { ...s, ...next } : s)));\n },\n [commit, refuse, latestSections],\n );\n\n return {\n sections,\n previews,\n selectedId,\n selectedItem,\n selectedIndex,\n select,\n selectOnly,\n clearSelection,\n add,\n remove,\n copy,\n move,\n reorder,\n patch,\n getCommittedSection,\n problem,\n stale,\n };\n};\n","import {\n Children,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport {\n type Announcements,\n DndContext,\n type DragEndEvent,\n type DragOverEvent,\n DragOverlay,\n type DragStartEvent,\n KeyboardSensor,\n type Modifier,\n PointerSensor,\n type ScreenReaderInstructions,\n closestCenter,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport { restrictToVerticalAxis } from '@dnd-kit/modifiers';\nimport {\n SortableContext,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { Space, Typography } from '@jbpark/ui-kit';\nimport { useResponsiveSize } from '@jbpark/use-hooks';\n\nimport { DATA_ATTR, DRAGGABLE_ITEMS } from '~/constants';\nimport type { Section } from '~/types';\nimport {\n type DataAttrNode,\n type DocumentProblem,\n extract,\n updateAll,\n} from '~/utils/ast';\nimport type { UpdateFailure } from '~/utils/ast';\nimport { fillIdsFrom } from '~/utils/ast/tree';\n\nimport { cn } from '../../utils/cn';\nimport { preloadScripts } from '../../utils/scripts';\nimport { usePreview } from '../context/states';\nimport { type FrameProps } from '../frame';\nimport { useStableModules } from '../preview/use-stable-modules';\nimport Droppable from './droppable';\nimport {\n type DndEditError,\n DndEditOptionsContext,\n type DndRenderField,\n toastEditError,\n} from './edit-options';\nimport {\n type DndInspector,\n DndInspectorContext,\n type DndNodePick,\n pickElement,\n viewportRect,\n} from './inspector';\nimport InspectorHighlight from './inspector-highlight';\nimport Layout from './layout';\nimport { DndRegionContext } from './layout-context';\nimport Overlay from './overlay';\nimport {\n type PanelBinding,\n type PanelNodeChange,\n type PanelNodesChange,\n resolvePanelBindings,\n withPanelCommit,\n} from './panel-binding';\nimport Renderer from './renderer';\nimport {\n type DndRenderSectionFallback,\n SectionFallbackContext,\n} from './section-fallback-context';\nimport Sortable, { type SectionNavigation } from './sortable';\nimport { useSectionDocument } from './use-section-document';\n\n// Turn a structured `update` failure into a toast that names the actual\n// fault. Before #270 every failure showed \"Failed to update this field /\n// Check the console for details\" — but nothing was logged, so the console\n// was empty. Most of these are a wrong `property`/`label` in the element's\n// `data-binding`, not the value the author just typed, so the message points\n// there. `description` is only set for paths that genuinely log (parse\n// errors), so \"check the console\" is never a dead end again.\nconst describeUpdateFailure = (\n failure: UpdateFailure | undefined,\n label: string,\n): { title: string; description?: string } => {\n switch (failure?.reason) {\n case 'attribute-not-found':\n return {\n title: `Failed to update \"${label}\"`,\n description: `This element has no \"${failure.property}\" attribute — check the property in its data-binding.`,\n };\n case 'binding-not-declared':\n return {\n title: `Failed to update \"${label}\"`,\n description: `No binding for ${\n failure.property\n ? `property \"${failure.property}\"`\n : `label \"${label}\"`\n } is declared on this element's data-binding.`,\n };\n case 'duplicate-binding':\n return {\n title: `Failed to update \"${label}\"`,\n description: `${failure.count} bindings share ${\n failure.property\n ? `property \"${failure.property}\"`\n : `label \"${label}\"`\n } on this element — remove the duplicate in its data-binding.`,\n };\n case 'reserved-property':\n return {\n title: `Cannot edit \"${label}\" in the panel`,\n description: `\"${failure.property}\" is managed by the editor, so a binding can't change it.`,\n };\n case 'required-property':\n return {\n title: `Cannot remove \"${label}\"`,\n description: `\"${failure.property}\" is marked required in its data-binding, so it can't be removed.`,\n };\n case 'no-binding':\n return {\n title: `Failed to update \"${label}\"`,\n description: 'This element has no data-binding declaration.',\n };\n case 'element-not-found':\n return {\n title: `Failed to update \"${label}\"`,\n description: 'The target element could not be found in this section.',\n };\n case 'unsupported-syntax':\n return {\n title: `Cannot edit \"${label}\" in the panel`,\n description: `The \"${failure.property}\" expression was preserved. Change it in the code editor instead.`,\n };\n case 'parse-error':\n return {\n title: `Failed to update \"${label}\"`,\n description:\n failure.error instanceof Error\n ? failure.error.message\n : 'Check the console for details.',\n };\n default:\n return { title: `Failed to update \"${label}\"` };\n }\n};\n\n// Enter is left out of `start` so it can select the focused section (#435).\nconst KEYBOARD_CODES = {\n start: ['Space'],\n cancel: ['Escape'],\n end: ['Space', 'Enter'],\n};\n\nconst SCREEN_READER_INSTRUCTIONS: ScreenReaderInstructions = {\n draggable:\n 'On a palette item, press Enter to add it to the canvas. On a canvas section, press Enter to select it, the up and down arrow keys to go to the previous or next section, and Delete to remove it. Press Space to pick a section up, the arrow keys to move it, and Space or Enter to drop it. Press Escape to cancel.',\n};\n\n// Section wrappers by id, with one stable ref callback per id so React\n// doesn't detach and reattach every wrapper on each render. Held in a\n// `useState` box and only read from handlers and effects.\nconst createNodeRegistry = () => {\n const nodes = new Map<string, HTMLElement>();\n const callbacks = new Map<string, (node: HTMLElement | null) => void>();\n\n return {\n get: (id: string) => nodes.get(id),\n register: (id: string) => {\n let callback = callbacks.get(id);\n\n if (!callback) {\n callback = node => {\n if (node) {\n nodes.set(id, node);\n } else {\n // A wrapper only detaches when its section leaves the canvas\n // (sections are keyed by id), so its callback can go too.\n nodes.delete(id);\n callbacks.delete(id);\n }\n };\n callbacks.set(id, callback);\n }\n\n return callback;\n },\n };\n};\n\n// An edit refused because the document doesn't parse (#433).\nconst blockedEditError = (error: unknown): DndEditError => ({\n type: 'parse',\n target: 'document',\n reason: 'parse-error',\n error,\n title: 'The document has a syntax error',\n description:\n 'The canvas shows the last version that parsed. Fix the error in the code, then edit here again.',\n});\n\n// What `useDndPalette()` returns. Deliberately just data: the drag wiring is\n// a component (`Live.Dnd.DraggableItem`) and the breakpoint belongs to\n// `useDndLayout()`, so a custom palette takes each from where it lives\n// rather than having all three funnelled through one object.\nexport interface DndPalette {\n items: Section[];\n // Appends the item to the canvas. Closes the mobile palette Drawer too,\n // which is a no-op wherever it isn't open.\n onAdd: (item: Section) => void;\n}\n\n// `PanelNodeChange`/`PanelBinding` live in `./panel-binding` alongside the\n// DataAttrNode -> PanelBinding conversion they describe, and are re-exported\n// here so `Live.Dnd`'s public types keep their original import path (#340).\nexport type {\n PanelBinding,\n PanelNodeChange,\n PanelNodesChange,\n} from './panel-binding';\n\n// What `useDndPanel()` returns — everything the built-in property panel runs\n// on, so a custom panel starts from the same place rather than re-deriving\n// any of it.\nexport interface DndPanel {\n item?: Section;\n onChange: (next: Partial<Section>) => void;\n onDelete: (id: string) => void;\n // Alternative to dragging a section to reorder it — needed since the\n // canvas sits behind the mobile Drawer the panel renders in, so\n // there's nothing visible to drag onto there.\n onMoveUp: () => void;\n onMoveDown: () => void;\n canMoveUp: boolean;\n canMoveDown: boolean;\n // `item`'s editable data-binding fields, already flattened to one entry\n // per bound property (across every non-<section> descendant carrying a\n // `data-binding` attribute). Each entry carries the binding's `type` and\n // current `value` plus an `onChange` wired straight into the same\n // AST-update pipeline the built-in panel uses — including the error Toast\n // on a bad edit. Switch on `type` to render your own control (an\n // `<input>`, `<textarea>`, `<select>`, ...) instead of the built-in one.\n bindings: PanelBinding[];\n // Node-level commit for elements that aren't in `bindings` — the nested\n // data-bound JSX held inside an `items`/`children` value, which the\n // built-in Items/Children editors discover by re-extracting that value's\n // own JSX. Those `data-id`s never reach `bindings` (the top-level\n // `extract()` doesn't walk into an attribute expression), and no single\n // `PanelBinding.onChange` can address them since each one closes over a\n // fixed `id` — hence this `(id, label, property, value)` channel. Hand it\n // to `Live.Dnd.Field` along with the binding, otherwise nested\n // array/children edits inside it silently don't commit (#308).\n onNodeChange: PanelNodeChange;\n // Several node-level edits as one commit: applied in array order, all or\n // none. Reach for it when one interaction writes more than one binding (an\n // image picker setting `src` and `alt`, say), so the host sees a single\n // `onChange` and a failure can't leave half of it behind (#425).\n onNodesChange: PanelNodesChange;\n // True while the document doesn't parse: `item` and `bindings` are from the\n // last version that did, and every commit is refused (and reported through\n // `onEditError`) until the source parses again. Disable your controls, or\n // say why edits aren't landing (#433).\n readOnly: boolean;\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 // Replaces the built-in control for any field, wherever it renders — the\n // built-in panel, `Live.Dnd.Field` in a custom panel, nested object keys\n // and array item properties. Return `undefined` to keep the built-in one.\n // See `DndRenderField`.\n renderField?: DndRenderField;\n // Receives every edit the editor could not apply. When set, the built-in\n // error toast is not shown; the payload carries the same title and\n // description so a host can show them its own way.\n onEditError?: (error: DndEditError) => void;\n // Renders in place of a canvas section that failed to compile, threw while\n // rendering, or was skipped by `shouldForceSectionFallback`. Return\n // `undefined` for the built-in error box. See `DndSectionFallbackArgs`.\n renderSectionFallback?: DndRenderSectionFallback;\n // Checked for every section before it is compiled. Return `true` to skip\n // compiling it (so none of its top-level code runs) and render the\n // fallback with reason `forced`.\n shouldForceSectionFallback?: (section: Section) => boolean;\n // Asked before a section is deleted, from the canvas, the panel, or a\n // custom panel's `onDelete`. Return `false` (or a promise of it) to keep the\n // section; use it to show your own confirmation. Deleting is immediate and\n // has no undo inside `Live.Dnd`, so this is the host's chance to ask (#435).\n onBeforeDelete?: (section: Section) => boolean | Promise<boolean>;\n // Names a section whose `<section>` has no `data-name`, from its 0-based\n // position on the canvas. The name shows on the canvas, in the panel and\n // in `renderSectionFallback`'s `section`. Defaults to \"Section 1\",\n // \"Section 2\", ...\n sectionNameFallback?: (index: number) => string;\n // The `id` of the element whose `<section>` children are the document's\n // sections. Defaults to `app-container`. A document without that element\n // has no sections, and `onEditError` (or the toast) says so. Start a new\n // document with `createDocument({ containerId })` from\n // `@jbpark/live-editor/utils`. Without a `value`, `Live.Dnd` starts from\n // the default template, which uses `app-container`, so pass a `value`\n // when you change this.\n containerId?: string;\n // Called when an element is picked in the canvas preview with the element\n // picker (`useDndInspector()`, or the canvas's picker button). Receives the\n // element's `data-id`, the key its fields carry in `useDndPanel()`, and its\n // section's id. The section is selected as well (#432).\n onNodePick?: (pick: DndNodePick) => void;\n // The single customization slot. Omit it for the built-in editor. Supply\n // it and you own the arrangement: compose `Live.Dnd.Palette` /\n // `Live.Dnd.Canvas` / `Live.Dnd.Panel` (each the built-in region, in the\n // container it needs) and your own components in any structure you like.\n // The drag context wraps all of it, so drag-and-drop and field editing\n // keep working wherever a region lands. Your components read the same data\n // the built-ins do through `useDndPalette()` / `useDndPanel()` /\n // `useDndLayout()`.\n //\n // Note this replaces the mobile chrome too — the FAB and both Drawers live\n // in `Live.Dnd.Layout`, which is what runs when children are omitted.\n // Render it yourself (`<Live.Dnd.Layout panel={<MyPanel />} />`) to keep\n // the built-in arrangement while swapping one region. Render `Canvas` at\n // most once either way.\n children?: React.ReactNode;\n}\n\nconst conditionalModifiers: Modifier = args => {\n const { active } = args;\n\n if (active?.data.current?.type === 'new-item') {\n return args.transform;\n }\n\n return restrictToVerticalAxis(args);\n};\n\n// Shared, not `= {}` in the parameter list: a fresh object on every render\n// is a new `modules` prop for every section, which defeats `Renderer`'s memo\n// (#97) and re-runs `compile()` for every section on every edit. Past the\n// compilation cache's limit that meant recompiling most sections with Babel\n// per keystroke-commit — 1.4 s per edit at 90 sections (#348).\nconst NO_MODULES: Record<string, unknown> = {};\n\nconst Dnd = ({\n value: _value,\n props,\n modules: _modules = NO_MODULES,\n onChange: _onChange,\n className,\n items = [],\n frame,\n dynamicTailwind = false,\n provider,\n renderField,\n onEditError,\n renderSectionFallback,\n shouldForceSectionFallback,\n onBeforeDelete,\n sectionNameFallback,\n containerId,\n onNodePick,\n children,\n ...restProps\n}: Props) => {\n const modules = useStableModules(_modules);\n const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);\n\n const { breakpoint } = useResponsiveSize();\n const isMobile = breakpoint.current === 'xs' || breakpoint.current === 'sm';\n\n // Read-only here — `useSectionDocument` below owns `setCode` (the commit\n // side). `code` is still needed locally: it feeds `value`'s fallback\n // chain just below, and `value` itself is read again further down for\n // the drag overlay's `fullCode` — not something `useSectionDocument`\n // exposes back out.\n const { code } = usePreview();\n\n // A throwing predicate is treated as \"not forced\" rather than taking the\n // whole editor down with it.\n const isForced = (section: Section) => {\n try {\n return shouldForceSectionFallback?.(section) === true;\n } catch (error) {\n console.error('shouldForceSectionFallback threw', error);\n\n return false;\n }\n };\n\n // Space picks a focused section up, the arrow keys move it, and Space or\n // Enter drops it (Escape cancels). Enter doesn't pick up, unlike dnd-kit's\n // default: a focused section is a `role=\"button\"`, and Enter selects it\n // like a click does (see Sortable). Before, sections could be reached with\n // Tab but neither selected nor moved from the keyboard (#435).\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 10,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n keyboardCodes: KEYBOARD_CODES,\n }),\n );\n\n // dnd-kit announces drags by id, which here is a generated `data-id`.\n const nameOf = (id: string | number, data?: { current?: unknown }) => {\n const current = data?.current as { item?: Section } | undefined;\n\n return (\n current?.item?.name ??\n sections.find(section => section.id === id)?.name ??\n 'section'\n );\n };\n\n const positionOf = (id: string | number) =>\n sections.findIndex(section => section.id === id) + 1;\n\n const announcements: Announcements = {\n onDragStart: ({ active }) => `Picked up ${nameOf(active.id, active.data)}.`,\n onDragOver: ({ active, over }) =>\n over && positionOf(over.id) > 0\n ? `${nameOf(active.id, active.data)} moved to position ${positionOf(over.id)} of ${sections.length}.`\n : `${nameOf(active.id, active.data)} is no longer over a position.`,\n onDragEnd: ({ active, over }) =>\n over && positionOf(over.id) > 0\n ? `${nameOf(active.id, active.data)} dropped at position ${positionOf(over.id)} of ${sections.length}.`\n : `${nameOf(active.id, active.data)} dropped.`,\n onDragCancel: ({ active }) =>\n `Moving ${nameOf(active.id, active.data)} was cancelled.`,\n };\n\n // Uncontrolled usage (`<Live.Dnd />` with no `value`) used to read\n // nothing but DEFAULT_TEMPLATE forever: every edit committed through\n // useSectionDocument writes into PreviewContext, but this component\n // never read `code` back — so the section a reader just dragged in\n // vanished on the very next render. `Client` (preview/client.tsx)\n // resolves the same dual-source situation by distinguishing an omitted\n // prop from an explicitly empty string; mirror that contract here. The\n // ContextProvider supplies DEFAULT_TEMPLATE for a fresh document.\n const value = _value === undefined ? code : _value;\n\n const reportError = onEditError ?? toastEditError;\n\n // Read through a ref so the effects below fire once per failure, not again\n // on every render a host passes a fresh inline `onEditError`.\n const reportErrorRef = useRef(reportError);\n\n useEffect(() => {\n reportErrorRef.current = reportError;\n });\n\n // Reported only when an author tries to edit, not whenever the source\n // stops parsing: that happens on most keystrokes in the code editor, and\n // the canvas already says it's showing the last valid version (#433).\n const onBlockedEdit = useCallback((problem: DocumentProblem) => {\n if (problem.reason === 'parse-error') {\n reportErrorRef.current(blockedEditError(problem.error));\n }\n }, []);\n\n const {\n sections,\n previews,\n selectedId,\n selectedItem,\n selectedIndex,\n select,\n selectOnly,\n clearSelection,\n add: addItem,\n remove,\n copy: onCopy,\n move: moveSection,\n reorder,\n patch,\n getCommittedSection,\n problem,\n stale,\n } = useSectionDocument(value, _onChange, {\n containerId,\n sectionNameFallback,\n onBlockedEdit,\n });\n\n // The container id the document is missing, or `null`.\n const missingContainer =\n problem?.reason === 'container-not-found' ? problem.containerId : null;\n\n const onDragStart = (_: DragStartEvent) => {};\n\n const onDragOver = (_e: DragOverEvent) => {};\n\n const onDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n\n if (!over) {\n return;\n }\n\n if (active.data.current?.type === 'new-item') {\n const item = active.data.current.item as Section;\n const atBottom =\n over.id === 'sortable-area' || over.id === 'sortable-area-bottom';\n\n addItem(\n item,\n atBottom ? undefined : sections.findIndex(s => s.id === over.id),\n );\n return;\n }\n\n if (active.id !== over.id && sections.some(s => s.id === active.id)) {\n reorder(String(active.id), String(over.id));\n }\n };\n\n const onSelect = (id: string) => select(id);\n\n // The element picker (#432). `picked` follows the selection: picking\n // selects the element's section, and selecting another section clears it.\n const [inspecting, setInspecting] = useState(false);\n const [picked, setPicked] = useState<DndNodePick | null>(null);\n const [highlight, setHighlight] = useState<DOMRect | null>(null);\n\n if (picked && picked.sectionId !== selectedId) {\n setPicked(null);\n }\n\n const stopInspecting = useCallback(() => {\n setInspecting(false);\n setHighlight(null);\n }, []);\n\n useEffect(() => {\n if (!inspecting) {\n return;\n }\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n stopInspecting();\n }\n };\n\n window.addEventListener('keydown', onKeyDown);\n\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [inspecting, stopInspecting]);\n\n const inspector: DndInspector = {\n active: inspecting,\n activate: () => setInspecting(true),\n deactivate: stopInspecting,\n toggle: () => (inspecting ? stopInspecting() : setInspecting(true)),\n picked,\n };\n\n const onInspectMove = (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => {\n const element = pickElement(section, overlay, x, y);\n\n setHighlight(element ? viewportRect(element) : null);\n };\n\n const onInspectPick = (\n sectionId: string,\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => {\n const id = pickElement(section, overlay, x, y)?.getAttribute(DATA_ATTR.ID);\n\n if (!id) {\n return;\n }\n\n const pick = { id, sectionId };\n\n selectOnly(sectionId);\n setPicked(pick);\n stopInspecting();\n onNodePick?.(pick);\n };\n\n // Read through a ref after an async `onBeforeDelete`: while a confirmation\n // is open the document can change, and the `remove` from the render that\n // asked would commit against the document as it was then.\n const removeRef = useRef(remove);\n\n useEffect(() => {\n removeRef.current = remove;\n });\n\n // Asks `onBeforeDelete` first when there is one, then removes the section.\n // `onDeleted` runs only once it's actually gone.\n const requestDelete = (id: string, onDeleted?: () => void) => {\n const section = sections.find(candidate => candidate.id === id);\n\n if (!onBeforeDelete || !section) {\n remove(id);\n onDeleted?.();\n\n return;\n }\n\n const decide = (allowed: boolean) => {\n if (allowed) {\n removeRef.current(id);\n onDeleted?.();\n }\n };\n\n try {\n const answer = onBeforeDelete(section);\n\n if (typeof answer === 'boolean') {\n decide(answer);\n\n return;\n }\n\n answer.then(decide, error => {\n console.error('onBeforeDelete rejected; the section was kept', error);\n });\n } catch (error) {\n console.error('onBeforeDelete threw; the section was kept', error);\n }\n };\n\n const onDelete = (id: string) => requestDelete(id);\n\n // The focusable wrapper of each section, so the keyboard can move focus\n // between them (#435).\n const [sectionNodes] = useState(createNodeRegistry);\n\n // `focus()` also scrolls the section into view.\n const focusSection = (id: string) => sectionNodes.get(id)?.focus();\n\n // Arrow keys and Home/End move focus to another section and select it, so\n // the panel follows. Outside a drag only: during one, dnd-kit owns them.\n const onNavigate = (fromId: string, to: SectionNavigation) => {\n const from = sections.findIndex(section => section.id === fromId);\n const index =\n to === 'first'\n ? 0\n : to === 'last'\n ? sections.length - 1\n : from + (to === 'next' ? 1 : -1);\n const target = sections[index];\n\n if (from < 0 || !target || target.id === fromId) {\n return;\n }\n\n selectOnly(target.id);\n focusSection(target.id);\n };\n\n // Delete on a focused section. Focus goes to the section that takes its\n // place (or the one before it, for the last), so it isn't dropped on the\n // page body.\n const onDeleteKey = (id: string) => {\n const index = sections.findIndex(section => section.id === id);\n const neighbor = sections[index + 1] ?? sections[index - 1];\n\n requestDelete(id, () => {\n if (neighbor) {\n focusSection(neighbor.id);\n }\n });\n };\n\n // Keeps the selected section on screen when it moves out of view without\n // the keyboard taking it there: a move from the panel, or a copy that lands\n // below the fold. After the next frame, once the new order is laid out.\n useEffect(() => {\n if (selectedId === null) {\n return;\n }\n\n const frame = requestAnimationFrame(() => {\n sectionNodes.get(selectedId)?.scrollIntoView?.({ block: 'nearest' });\n });\n\n return () => cancelAnimationFrame(frame);\n }, [sectionNodes, selectedId, selectedIndex]);\n\n const onChange = (next: Partial<Section>) => {\n if (!next.id) {\n return;\n }\n\n patch(next as Partial<Section> & { id: string });\n };\n\n // Reads only the extracted `code` local, not `selectedItem`, so the\n // compiler can verify this dependency array actually matches what the\n // body reads — matches Panel's own former version of this same logic,\n // now shared here so both the built-in Panel and a custom one built on\n // `useDndPanel()` get the same extraction/update pipeline instead of each\n // needing it.\n const selectedCode = selectedItem?.code;\n const selectedSectionId = selectedItem?.id;\n const { fields, updatedCode, parseError } = useMemo(() => {\n if (!selectedCode) {\n return {\n fields: [] as DataAttrNode[],\n updatedCode: '',\n parseError: null,\n };\n }\n\n try {\n // The same ids the canvas preview fills this section with, so an\n // element's `data-id` there matches its fields here (#432).\n const updated = fillIdsFrom(selectedCode, selectedSectionId ?? '');\n // Every element, the section's own root included: a `<section>` with a\n // `data-binding` is editable like any other element, and one without\n // resolves to no bindings below. It used to be dropped here, so a\n // binding written on the section itself was silently ignored (#429).\n const allNodes = extract(updated);\n\n return {\n fields: allNodes,\n updatedCode: updated !== selectedCode ? updated : selectedCode,\n parseError: null,\n };\n } catch (e) {\n console.warn('⚠️ Parsing error', e);\n return {\n fields: [] as DataAttrNode[],\n updatedCode: '',\n parseError: { error: e },\n };\n }\n }, [selectedCode, selectedSectionId]);\n\n // Keyed on the missing id alone, so it fires when a document reaches this\n // state and not again for every edit that leaves it there.\n useEffect(() => {\n if (missingContainer !== null) {\n reportErrorRef.current({\n type: 'parse',\n target: 'document',\n reason: 'container-not-found',\n containerId: missingContainer,\n title: `No #${missingContainer} element in the document`,\n description: `Sections are the <section> elements inside the element with id=\"${missingContainer}\". Start from createDocument(), or set containerId to match your document.`,\n });\n }\n }, [missingContainer]);\n\n useEffect(() => {\n if (parseError) {\n reportErrorRef.current({\n type: 'parse',\n target: 'section',\n error: parseError.error,\n title: 'Failed to parse this section',\n description: 'Check the console for details.',\n });\n }\n }, [parseError]);\n\n // The one commit path for panel edits, whether one node or several. A single\n // `PanelNodeChange` is a batch of one, so the guards and the base document\n // below can't drift between the two (#425).\n const commitChanges = (changes: Parameters<PanelNodeChange>[0][]) => {\n if (changes.length === 0) {\n return;\n }\n\n // The fields show the last version that parsed while the source doesn't,\n // and their ids point into that version, not the current source (#433).\n if (stale && problem?.reason === 'parse-error') {\n reportError(blockedEditError(problem.error));\n return;\n }\n\n // Builds on an earlier commit from this same tick when that commit\n // changed this section: `updatedCode` is this render's snapshot, so a\n // second commit made from it would write the first one's edit back out\n // (#450). A section the earlier commit left alone (a sibling was added,\n // say) still reads as `selectedCode`, whose empty `data-id`s haven't been\n // filled yet — `updatedCode` holds the ids the bindings point at.\n const committed =\n selectedItem && getCommittedSection(selectedItem.id)?.code;\n const base =\n committed && committed !== selectedCode ? committed : updatedCode;\n const result = updateAll(\n base,\n changes.map(({ id, label, property, value: changeValue }) => ({\n dataId: id,\n label,\n property,\n value: changeValue,\n })),\n );\n\n if (!result.success) {\n const { id, label, property } = changes[result.index]!;\n\n reportError({\n type: 'update',\n id,\n label,\n property,\n failure: result.failure,\n ...describeUpdateFailure(result.failure, label),\n });\n return;\n }\n\n if (selectedItem) {\n onChange({ ...selectedItem, code: result.code });\n }\n };\n\n const onFieldChange: PanelNodeChange = change => commitChanges([change]);\n\n // Flattens the extracted `fields` (one DataAttrNode per element) down to\n // one descriptor per bound property — the same walk the built-in\n // FieldEditor/Node does internally (data-id + parsed data-binding +\n // current value). Everything here is derived from `fields` alone, so the\n // memo key is honest and the parse/read work still happens once per\n // parsed section.\n //\n // Deliberately no `onChange`: a callback belongs to the render that made\n // it, not to the parse. Keeping the two in one memo is what caused #336 —\n // editing another section leaves `selectedCode` (and therefore `fields`)\n // identical, so the memo was reused and handed back callbacks still bound\n // to the previous document, whose commit wrote the sibling's old source\n // back over the newer one.\n const bindingFields = useMemo(\n () => fields.flatMap(node => resolvePanelBindings(node)?.bindings ?? []),\n [fields],\n );\n\n // Bound fresh each render on top of the memo above — the same split\n // `useDndItems` uses for its `items`. This is a plain walk of an\n // already-parsed result with no Babel in it, and it's what guarantees a\n // commit reads the current `updatedCode`/`selectedItem`/`onChange`.\n //\n // The identity churn the previous memo was guarding against was never\n // real: the `DndRegionContext` value and the `panel` object holding this\n // array are both fresh object literals every render, so every\n // `useDndPanel()` consumer already re-rendered regardless.\n const bindings: PanelBinding[] = withPanelCommit(\n bindingFields,\n onFieldChange,\n );\n\n useEffect(() => {\n if (frame?.scripts?.length) {\n preloadScripts(frame.scripts);\n }\n }, [frame?.scripts]);\n\n // Data, not nodes: the built-in palette and panel read these back through\n // `useDndPalette()`/`useDndPanel()` exactly as a custom one does, so\n // there's a single path and no way for the public surface to drift into a\n // subset of what the built-ins use — the point of #237.\n const palette: DndPalette = {\n items: items?.length ? items : DRAGGABLE_ITEMS,\n onAdd: (item: Section) => {\n addItem(item);\n setMobilePaletteOpen(false);\n },\n };\n\n const panel: DndPanel = {\n item: selectedItem,\n onChange,\n onDelete,\n onMoveUp: () => moveSection(selectedId, 'up'),\n onMoveDown: () => moveSection(selectedId, 'down'),\n canMoveUp: selectedIndex > 0,\n canMoveDown: selectedIndex >= 0 && selectedIndex < sections.length - 1,\n bindings,\n onNodeChange: onFieldChange,\n onNodesChange: commitChanges,\n readOnly: stale,\n };\n\n // Content only — the frame container that wraps this (`data-frame-container`\n // plus the containment styles) belongs to `Live.Dnd.Canvas`, so a custom\n // layout can't accidentally drop it while still placing the canvas.\n const canvas = (\n <>\n {stale && (\n <div\n role=\"status\"\n className={cn(\n 'sticky top-0 z-70',\n 'border-b border-amber-200 bg-amber-50 px-3 py-2',\n 'text-sm text-amber-900',\n )}\n >\n Showing the last version that parsed. Fix the syntax error in the code\n to edit here again.\n </div>\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 {problem?.reason === 'parse-error' ? (\n <Space orientation=\"vertical\" align=\"center\">\n <Typography.Paragraph>\n The document has a syntax error\n </Typography.Paragraph>\n <Typography.Text>\n Fix it in the code to see its sections\n </Typography.Text>\n </Space>\n ) : missingContainer !== null ? (\n <Space orientation=\"vertical\" align=\"center\">\n <Typography.Paragraph>\n No #{missingContainer} element in the document\n </Typography.Paragraph>\n <Typography.Text>\n Sections go inside the element with id=&quot;\n {missingContainer}&quot;\n </Typography.Text>\n </Space>\n ) : (\n <Space orientation=\"vertical\" align=\"center\">\n <Typography.Paragraph>\n No sections available\n </Typography.Paragraph>\n <Typography.Text>\n {isMobile\n ? 'Tap a component to add it'\n : 'Drag a component from the left to add it'}\n </Typography.Text>\n </Space>\n )}\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 nodeRef={sectionNodes.register(section.id)}\n onNavigate={to => onNavigate(section.id, to)}\n onDeleteKey={() => onDeleteKey(section.id)}\n inspecting={inspecting}\n onInspectMove={onInspectMove}\n onInspectPick={(...args) => onInspectPick(section.id, ...args)}\n onInspectLeave={() => setHighlight(null)}\n >\n <Renderer\n preview={previews[index]!}\n sectionId={section.id}\n sectionName={section.name}\n sectionCode={section.code}\n forceFallback={isForced(section)}\n modules={modules}\n frame={frame}\n dynamicTailwind={dynamicTailwind}\n provider={provider}\n {...props}\n />\n </Sortable>\n ))}\n </SortableContext>\n )}\n </Droppable>\n </>\n );\n\n return (\n <SectionFallbackContext.Provider value={renderSectionFallback}>\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n accessibility={{\n announcements,\n screenReaderInstructions: SCREEN_READER_INSTRUCTIONS,\n }}\n modifiers={[\n conditionalModifiers,\n //\n ]}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n >\n <div\n className={cn(\n 'relative flex h-full w-full',\n className,\n //\n )}\n {...restProps}\n >\n {/* Not memoized: `palette`, `panel` and `canvas` are all rebuilt\n each render anyway, so a memo would only add a dependency list\n to keep in sync. */}\n <DndEditOptionsContext.Provider value={{ renderField, reportError }}>\n <DndRegionContext.Provider\n value={{\n palette,\n panel,\n canvas,\n isMobile,\n selectedId,\n clearSelection,\n paletteOpen: mobilePaletteOpen,\n setPaletteOpen: setMobilePaletteOpen,\n documentError: problem?.reason ?? null,\n }}\n >\n {/* `Children.toArray` rather than a plain `children ??`: a JSX\n comment, or a `{cond && <MyLayout />}` that fell through,\n leaves `children` set but empty — and honouring that\n literally renders an editor with no regions at all, which\n looks like a broken build rather than a mistake in the\n layout. Falling back keeps the failure legible. */}\n <DndInspectorContext.Provider value={inspector}>\n {Children.toArray(children).length ? children : <Layout />}\n </DndInspectorContext.Provider>\n </DndRegionContext.Provider>\n <InspectorHighlight rect={inspecting ? highlight : null} />\n </DndEditOptionsContext.Provider>\n </div>\n <DragOverlay>\n <Overlay\n sections={sections}\n isForced={isForced}\n renderProps={{\n fullCode: value,\n modules,\n frame,\n dynamicTailwind,\n ...props,\n // After the spread, so a preview prop with the same name can't\n // point the overlay at a different container.\n containerId,\n }}\n />\n </DragOverlay>\n </DndContext>\n </SectionFallbackContext.Provider>\n );\n};\n\nexport default Dnd;\n","import DndImpl, {\n type DndPalette,\n type DndPanel,\n type PanelBinding,\n type PanelNodeChange,\n type PanelNodesChange,\n type Props,\n} from './dnd';\nimport DraggableItem, {\n type DraggableItemDragState,\n type DraggableItemProps,\n} from './draggable';\nimport type { DndEditError, DndRenderField } from './edit-options';\nimport {\n type DndInspector,\n type DndNodePick,\n useDndInspector,\n} from './inspector';\nimport {\n Canvas,\n type DndLayoutProps,\n type DndRegionProps,\n Layout,\n Palette,\n Panel,\n} from './layout';\nimport {\n type DndLayout,\n useDndLayout,\n useDndPalette,\n useDndPanel,\n} from './layout-context';\nimport Field, { type FieldProps } from './panel/field';\nimport {\n type DndChildren,\n type DndChildrenOptions,\n useDndChildren,\n} from './panel/use-dnd-children';\nimport {\n type DndItems,\n type DndItemsActions,\n type DndItemsExpansion,\n type DndItemsItem,\n type DndItemsNestedElement,\n type DndItemsNestedGroup,\n type DndItemsOptions,\n useDndItems,\n} from './panel/use-dnd-items';\nimport type {\n DndRenderSectionFallback,\n DndSectionFallbackArgs,\n} from './section-fallback-context';\n\ntype DndComponent = typeof DndImpl & {\n // Owns the dnd-kit wiring for a palette item and hands back `ref` /\n // `dragProps` / `isDragging`, so a custom palette decides how an item\n // *looks* without reimplementing how dragging works.\n DraggableItem: typeof DraggableItem;\n // The built-in control for one binding, exported so a custom panel can mix\n // its own controls with the built-in one per binding rather than choosing\n // all-or-nothing. Takes a `PanelBinding` straight out of `bindings` plus\n // `onNodeChange` — both `useDndPanel()` fields, so nothing internal is\n // needed to drive it. Most useful for `items`/`children` bindings, whose\n // editors find nested data-bound elements a consumer can't reach through\n // `bindings`. Renders the control only — supply your own label.\n Field: typeof Field;\n // The three built-in regions, each in the container it needs. Pass them as\n // `children` of `Live.Dnd` in any arrangement to own the layout, mixing in\n // your own components where you want to replace one. `Canvas` is the one\n // that can't be replaced — the droppable, the sortable list and each\n // section's compiled iframe are Dnd's own machinery — so render it exactly\n // once wherever the canvas belongs.\n Palette: typeof Palette;\n Canvas: typeof Canvas;\n Panel: typeof Panel;\n // The built-in arrangement: the 3-pane desktop Splitter, the stacked\n // mobile canvas, and the mobile FAB/Drawers. What `Live.Dnd` renders when\n // given no children, exported so children can wrap it (a toolbar above it,\n // say) or replace one region through its `palette`/`panel` slots without\n // rebuilding the rest. Also the only way to reach the built-in Splitter\n // layout without importing `@jbpark/ui-kit` directly, which a consumer may\n // not have as a direct dependency.\n Layout: typeof Layout;\n};\n\nconst Dnd = DndImpl as DndComponent;\n\nDnd.DraggableItem = DraggableItem;\nDnd.Field = Field;\nDnd.Palette = Palette;\nDnd.Canvas = Canvas;\nDnd.Panel = Panel;\nDnd.Layout = Layout;\n\nexport { DraggableItem, Field };\nexport { Palette, Canvas, Panel, Layout };\n// The data behind each region, so a component placed in `Live.Dnd`'s children\n// can replace one without losing what drives it: the palette's items and\n// `onAdd`, the panel's selected section/bindings/commit callbacks, and the\n// layout state the built-in mobile chrome runs on (`isMobile`, `selectedId` /\n// `clearSelection`, the palette Drawer's open state) — needed because\n// supplying children replaces that chrome along with the Splitter.\nexport { useDndPalette, useDndPanel, useDndLayout };\n// The element picker: turn it on, and clicking an element in the canvas\n// preview selects its section and reports the element's `data-id` (#432).\nexport { useDndInspector };\n// The array-editing engine behind the built-in Items panel, exposed for a\n// consumer who wants their own markup rather than the built-in control\n// (`Field` covers the latter). Everything it returns is `PanelBinding`s, so\n// the two compose: render the hook's own layout and hand individual\n// bindings to `Field` where the built-in control is good enough.\nexport { useDndChildren };\nexport type { DndChildren, DndChildrenOptions };\nexport { useDndItems };\n// The two steps behind `useDndPanel().bindings`, for an element the panel\n// doesn't hand over itself — most often a child's fields under\n// `useDndChildren`, which returns raw `DataAttrNode`s. `resolvePanelBindings`\n// reads a node into bindings without a commit; `withPanelCommit` attaches\n// `onNodeChange`. Together they produce `PanelBinding`s ready for `Field`.\nexport { resolvePanelBindings, withPanelCommit } from './panel-binding';\nexport type { PanelBindingData, PanelBindingSource } from './panel-binding';\n// The rule `Field` uses to pick its built-in control, so a custom panel that\n// routes some bindings to `Field` or a hook (most often the structural\n// `items`/`children` ones) asks the library instead of copying the checks.\nexport { getFieldKind, isStructuralFieldKind } from './panel/field-kind';\nexport type { FieldKind, FieldKindBinding } from './panel/field-kind';\n\n// The names these hooks and types shipped under before they joined the\n// `useDnd*` family. Kept as aliases so existing imports keep compiling; drop\n// them in the next major. Each maps mechanically: `useItemsEditor` →\n// `useDndItems`, `useChildrenEditor` → `useDndChildren`, `ItemsEditor*` →\n// `DndItems*`, `ChildrenEditor*` → `DndChildren*`.\n/** @deprecated Renamed to `useDndItems`. */\nexport const useItemsEditor = useDndItems;\n/** @deprecated Renamed to `useDndChildren`. */\nexport const useChildrenEditor = useDndChildren;\n/** @deprecated Renamed to `DndItems`. */\nexport type ItemsEditor = DndItems;\n/** @deprecated Renamed to `DndItemsActions`. */\nexport type ItemsEditorActions = DndItemsActions;\n/** @deprecated Renamed to `DndItemsItem`. */\nexport type ItemsEditorItem = DndItemsItem;\n/** @deprecated Renamed to `DndItemsNestedElement`. */\nexport type ItemsEditorNestedElement = DndItemsNestedElement;\n/** @deprecated Renamed to `DndItemsNestedGroup`. */\nexport type ItemsEditorNestedGroup = DndItemsNestedGroup;\n/** @deprecated Renamed to `DndItemsOptions`. */\nexport type ItemsEditorOptions = DndItemsOptions;\n/** @deprecated Renamed to `DndChildren`. */\nexport type ChildrenEditor = DndChildren;\n/** @deprecated Renamed to `DndChildrenOptions`. */\nexport type ChildrenEditorOptions = DndChildrenOptions;\nexport type {\n Props,\n DndPalette,\n DndPanel,\n DndLayout,\n DndInspector,\n DndNodePick,\n DndLayoutProps,\n DndRegionProps,\n PanelBinding,\n PanelNodeChange,\n PanelNodesChange,\n FieldProps,\n DndEditError,\n DndRenderField,\n DndRenderSectionFallback,\n DndSectionFallbackArgs,\n DndItems,\n DndItemsActions,\n DndItemsExpansion,\n DndItemsItem,\n DndItemsNestedElement,\n DndItemsNestedGroup,\n DndItemsOptions,\n DraggableItemProps,\n DraggableItemDragState,\n};\nexport default Dnd;\n"],"mappings":"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"}
1
+ {"version":3,"file":"dnd-x8Mvj--6.js","names":["Children","CSS","t","CoreEditor","Children","Panel","PropertyPanel","LiveError","CSS","Renderer","Dnd","Renderer","DndImpl"],"sources":["../src/components/dnd/droppable.tsx","../src/components/dnd/edit-options.ts","../src/components/dnd/inspector.ts","../src/components/dnd/inspector-highlight.tsx","../src/components/dnd/draggable.tsx","../src/components/dnd/layout-context.ts","../src/components/dnd/panel-binding.ts","../src/components/dnd/panel/bulk-actions-bar.tsx","../src/components/dnd/panel/node.tsx","../src/components/dnd/panel/use-structural-selection.ts","../src/components/dnd/panel/use-dnd-children.ts","../src/components/dnd/panel/children.tsx","../src/components/dnd/panel/field-kind.ts","../src/components/dnd/panel/sortable-items.tsx","../src/components/dnd/panel/use-dnd-items.ts","../src/components/dnd/panel/items.tsx","../src/components/dnd/panel/field.tsx","../src/components/dnd/panel/field-group.tsx","../src/components/dnd/panel/panel.tsx","../src/components/dnd/layout.tsx","../src/components/dnd/section-fallback-context.ts","../src/components/dnd/section-fallback.tsx","../src/components/dnd/renderer.tsx","../src/components/dnd/sortable.tsx","../src/components/dnd/overlay.tsx","../src/components/dnd/use-section-document.ts","../src/components/dnd/dnd.tsx","../src/components/dnd/index.ts"],"sourcesContent":["import { useDroppable } from '@dnd-kit/core';\nimport { Typography } from '@jbpark/ui-kit';\n\nimport { cn } from '~/utils/cn';\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 { createContext, useContext } from 'react';\n\nimport { Toast } from '@jbpark/ui-kit';\n\nimport type { UpdateFailure } from '~/utils/ast';\n\nimport type { FieldProps } from './panel/field';\n\n// Everything the editor reports instead of applying an edit. `title` and\n// `description` are the messages the built-in toast shows, so a host that\n// routes these elsewhere can reuse them rather than rewording every case.\nexport type DndEditError =\n | {\n // `update()` rejected a field edit. `failure.reason` says why — most\n // often a `property`/`label` in the element's data-binding that doesn't\n // match its markup.\n type: 'update';\n id: string;\n label: string;\n property: string;\n failure: UpdateFailure | undefined;\n title: string;\n description?: string;\n }\n | {\n // The selected section's source, or an `items` value inside it, did\n // not parse. Nothing in it can be edited from the panel until it does.\n type: 'parse';\n target: 'section' | 'items';\n error?: unknown;\n title: string;\n description?: string;\n }\n | {\n // An edit was refused because the document doesn't parse. The canvas\n // and panel show the last version that did, and nothing can be\n // committed against it (#433). Reported when an edit is attempted, not\n // whenever the source stops parsing.\n type: 'parse';\n target: 'document';\n reason: 'parse-error';\n error: unknown;\n title: string;\n description?: string;\n }\n | {\n // The document has no element with the container id, so it has no\n // sections and nothing added from the palette can land. Reported once\n // each time a document reaches this state, not on every edit (#449).\n type: 'parse';\n target: 'document';\n reason: 'container-not-found';\n containerId: string;\n title: string;\n description?: string;\n }\n | {\n // An array edit could not be applied without losing source (a spread,\n // a hole, unsupported syntax). The source was left unchanged.\n type: 'items';\n title: string;\n description?: string;\n };\n\n// Called before the built-in control for every field — top-level, nested\n// object keys and array item properties alike. Return a node to render it\n// instead, `null` to render nothing, or `undefined` to keep `builtin`.\n// `builtin` is the control that would have rendered, so a renderer can wrap\n// it rather than replace it; don't render `<Live.Dnd.Field>` from here, since\n// that calls this function again.\nexport type DndRenderField = (\n props: FieldProps,\n builtin: React.ReactElement,\n) => React.ReactNode | undefined;\n\ninterface DndEditOptions {\n renderField?: DndRenderField;\n reportError: (error: DndEditError) => void;\n}\n\nexport const toastEditError = (error: DndEditError) => {\n Toast.error(\n error.title,\n error.description ? { description: error.description } : undefined,\n );\n};\n\n// A context rather than props threaded through every editor: `Field` renders\n// itself recursively and inside `Items`/`Children`, and a custom panel\n// renders it directly, so this is the one way every field sees the same\n// options. The default keeps `Field`/`useDndItems` working outside\n// `Live.Dnd`, reporting through the toast as before.\nexport const DndEditOptionsContext = createContext<DndEditOptions>({\n reportError: toastEditError,\n});\n\nexport const useDndEditOptions = () => useContext(DndEditOptionsContext);\n","import { createContext, useContext } from 'react';\n\nimport { DATA_ATTR } from '~/constants';\n\n// What `Live.Dnd` reports when an element is picked in the canvas preview:\n// the element's `data-id`, the key its fields carry in `useDndPanel()`, and\n// the section it belongs to (#432).\nexport interface DndNodePick {\n id: string;\n sectionId: string;\n}\n\n// The element picker. While `active`, pointing at a section in the canvas\n// outlines the element under the pointer, and clicking selects that section\n// and reports the element. Section dragging is off for as long as it's on.\nexport interface DndInspector {\n active: boolean;\n activate: () => void;\n deactivate: () => void;\n toggle: () => void;\n // The last element picked, or `null`. Cleared when the selection moves to\n // another section.\n picked: DndNodePick | null;\n}\n\nexport const DndInspectorContext = createContext<DndInspector | null>(null);\n\nexport const useDndInspector = (): DndInspector => {\n const inspector = useContext(DndInspectorContext);\n\n if (!inspector) {\n throw new Error('useDndInspector() must be used inside <Live.Dnd>.');\n }\n\n return inspector;\n};\n\n// A shadow root's `elementsFromPoint` lists the host page's elements under\n// the point too, the canvas overlay among them, so a nested lookup keeps only\n// its own tree's.\nconst outside = (root: Document | ShadowRoot) => (element: Element) =>\n element.getRootNode() !== root;\n\n// The deepest element at a point, looking into iframes and shadow roots on\n// the way down. Every canvas section sits under a transparent overlay that\n// takes the pointer, so the hit test has to skip it and go through to the\n// preview: in the host document for a section rendered in place, then inside\n// the iframe document or shadow root for the other frame modes.\nconst deepestAt = (\n root: Document | ShadowRoot,\n x: number,\n y: number,\n skip: (element: Element) => boolean,\n): Element | null => {\n const element = root\n .elementsFromPoint(x, y)\n .find(candidate => !skip(candidate));\n\n if (!element) {\n return null;\n }\n\n if (element instanceof HTMLIFrameElement) {\n const document = element.contentDocument;\n\n if (!document) {\n return element;\n }\n\n const rect = element.getBoundingClientRect();\n\n return (\n deepestAt(document, x - rect.left, y - rect.top, outside(document)) ??\n element\n );\n }\n\n if (element.shadowRoot && element.shadowRoot !== root) {\n return (\n deepestAt(element.shadowRoot, x, y, outside(element.shadowRoot)) ??\n element\n );\n }\n\n return element;\n};\n\nconst hasId = (element: Element) => Boolean(element.getAttribute(DATA_ATTR.ID));\n\n// The picked element inside `section`, as the nearest element at or above the\n// point that carries a non-empty `data-id`. `null` outside the section, or\n// when nothing there carries an id.\nexport const pickElement = (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n): Element | null => {\n let element = deepestAt(\n section.ownerDocument,\n x,\n y,\n candidate =>\n candidate === overlay ||\n candidate === section ||\n !section.contains(candidate),\n );\n\n // Stops at the section's wrapper, so an id on the host page around the\n // canvas is never picked.\n while (element && element !== section && !hasId(element)) {\n element =\n element.parentElement ??\n // Past a shadow root, carry on from its host.\n (element.parentNode as ShadowRoot | null)?.host ??\n null;\n }\n\n return element === section ? null : element;\n};\n\n// The picked element's box in the host viewport, adding the offset of each\n// iframe it's nested in.\nexport const viewportRect = (element: Element): DOMRect => {\n const rect = element.getBoundingClientRect();\n let x = rect.left;\n let y = rect.top;\n let frame = element.ownerDocument.defaultView?.frameElement ?? null;\n\n while (frame) {\n const frameRect = frame.getBoundingClientRect();\n\n x += frameRect.left;\n y += frameRect.top;\n frame = frame.ownerDocument.defaultView?.frameElement ?? null;\n }\n\n return new DOMRect(x, y, rect.width, rect.height);\n};\n","import { createPortal } from 'react-dom';\n\n// The outline drawn over the element under the pointer. Portaled to the host\n// body with fixed coordinates: the canvas sets `transform`, which would make\n// a fixed box inside it relative to the canvas instead of the viewport.\nconst InspectorHighlight = ({ rect }: { rect: DOMRect | null }) =>\n rect\n ? createPortal(\n <div\n aria-hidden\n data-dnd-inspector-highlight\n style={{\n position: 'fixed',\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height,\n pointerEvents: 'none',\n outline: '2px solid #3b82f6',\n outlineOffset: -1,\n background: 'rgba(59, 130, 246, 0.12)',\n zIndex: 2147483647,\n }}\n />,\n document.body,\n )\n : null;\n\nexport default InspectorHighlight;\n","import { useDraggable } from '@dnd-kit/core';\nimport { Card } from '@jbpark/ui-kit';\n\nimport type { Section } from '~/types';\nimport { cn } from '~/utils/cn';\n\nexport interface DraggableItemDragState {\n ref: (node: HTMLElement | null) => void;\n dragProps: React.HTMLAttributes<HTMLElement>;\n isDragging: boolean;\n}\n\nexport interface DraggableItemProps {\n item: Section;\n children: (drag: DraggableItemDragState) => React.ReactNode;\n}\n\n// Owns the dnd-kit wiring (useDraggable + the `type: 'new-item'` data shape\n// Dnd's onDragEnd expects) so a custom palette only has to decide how\n// an item *looks*, not how dragging itself works. Exported as\n// Dnd.DraggableItem for that purpose; also used internally for the default\n// palette rendering, so both paths share the exact same drag wiring.\nconst DraggableItem = ({ item, children }: DraggableItemProps) => {\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({\n id: item.id,\n data: { type: 'new-item', item },\n });\n\n return children({\n ref: setNodeRef,\n dragProps: { ...listeners, ...attributes },\n isDragging,\n });\n};\n\n// The built-in card look, shared by the default (non-custom) palette\n// rendering and the drag overlay's floating preview — both rendered a plain\n// `<Draggable>` before this became a children-render-prop component.\nexport interface DefaultDraggableItemProps {\n item: Section;\n onAdd?: (item: Section) => void;\n // Double-click is the desktop convenience shortcut alongside drag — a\n // single click there would fire on every aborted/failed drag attempt.\n // On mobile there's nowhere to drag *to* (the palette lives in a Drawer\n // stacked over the canvas), so a tap can't be a failed drag, and\n // double-tap-to-dblclick synthesis from touch is unreliable anyway\n // (iOS Safari inconsistently fires it, and it can compete with the\n // browser's native double-tap-to-zoom gesture). Tapping just adds there.\n tapToAdd?: boolean;\n}\n\nexport const DefaultDraggableItem = ({\n item,\n onAdd,\n tapToAdd = false,\n}: DefaultDraggableItemProps) => (\n <DraggableItem item={item}>\n {({ ref, dragProps, isDragging }) => (\n <Card\n ref={ref}\n style={{ opacity: isDragging ? 0.5 : 1 }}\n {...dragProps}\n className={cn(\n 'cursor-grab',\n // A visible ring for keyboard focus only, instead of no outline at\n // all: the card is reachable with Tab (#435).\n 'outline-none focus-visible:ring-2 focus-visible:ring-blue-500',\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 // The card is a `role=\"button\"`: Enter adds it, the keyboard\n // counterpart of the double-click above. Space stays with dnd-kit,\n // which picks the card up (#435).\n onKeyDown={event => {\n dragProps.onKeyDown?.(event);\n\n if (\n onAdd &&\n event.key === 'Enter' &&\n event.target === event.currentTarget &&\n !event.defaultPrevented\n ) {\n event.preventDefault();\n onAdd(item);\n }\n }}\n >\n {item.name}\n </Card>\n )}\n </DraggableItem>\n);\n\nexport default DraggableItem;\n","import { createContext, useContext } from 'react';\n\nimport type { DndPalette, DndPanel } from './dnd';\n\n// The layout state a custom arrangement needs. Separate from the palette and\n// panel data because a layout decides *where* things go, not what they\n// contain — the built-in layout reads only this slice.\nexport interface DndLayout {\n // From `useResponsiveSize` — the same value that picks the stacked mobile\n // arrangement, so a custom layout can branch on it without repeating the\n // breakpoint check. Also what the built-in palette reads to decide\n // tap-to-add: at a mobile breakpoint a tap can't be a failed drag attempt\n // (there's nothing visible to drag onto behind the Drawer) and dblclick\n // synthesis from double-tap is unreliable, so a single tap adds.\n isMobile: boolean;\n // `null` when nothing is selected. The built-in layout uses it to open the\n // properties Drawer on mobile, where the panel has nowhere else to go.\n selectedId: string | null;\n clearSelection: () => void;\n // The palette Drawer's open state. Dnd owns it because adding an item\n // closes the Drawer; a layout only opens it.\n paletteOpen: boolean;\n setPaletteOpen: (open: boolean) => void;\n // Why the document can't be edited right now, or `null`. `'parse-error'`\n // while the source doesn't parse: the canvas shows the last version that\n // did, read-only (#433). `'container-not-found'` when it has no container\n // element, so it has no sections (#449).\n documentError: 'parse-error' | 'container-not-found' | null;\n}\n\n// Everything `Live.Dnd` publishes to its children, read back through the\n// three hooks below rather than as one object — a custom panel has no\n// business seeing the palette's items, and narrow hooks say which part of\n// Dnd a component actually depends on.\n//\n// `canvas` is the one node here rather than data: the droppable, the\n// sortable list and each section's compiled iframe are Dnd's own machinery,\n// so `Live.Dnd.Canvas` places it but nobody reproduces it.\ninterface DndRegions extends DndLayout {\n palette: DndPalette;\n panel: DndPanel;\n canvas: React.ReactNode;\n}\n\nexport const DndRegionContext = createContext<DndRegions | null>(null);\n\n// Internal, and takes a `subject` the public hooks don't: the caller as it\n// appears in source — a hook call, or the region element that wraps one — so\n// rendering `<Live.Dnd.Palette />` outside `Live.Dnd` reports the element the\n// reader actually wrote rather than the hook behind it.\nexport const useDndRegions = (subject: string): DndRegions => {\n const regions = useContext(DndRegionContext);\n\n if (!regions) {\n throw new Error(`${subject} must be used inside <Live.Dnd>.`);\n }\n\n return regions;\n};\n\n// The palette's items and the callback that adds one to the canvas. Pair it\n// with `Live.Dnd.DraggableItem` for the drag wiring and you have the whole\n// built-in palette's input.\nexport const useDndPalette = (): DndPalette =>\n useDndRegions('useDndPalette()').palette;\n\n// The selected section, its editable bindings, and the callbacks that commit\n// through Dnd's AST-update pipeline — everything the built-in property panel\n// runs on.\nexport const useDndPanel = (): DndPanel => useDndRegions('useDndPanel()').panel;\n\n// Returns the context object itself, narrowed: identity is stable across\n// renders, so this is safe in a dependency array.\nexport const useDndLayout = (): DndLayout => useDndRegions('useDndLayout()');\n","import { RESERVED_BINDING_PROPERTIES } from '~/constants';\nimport {\n type BindingItem,\n type BindingOption,\n type BindingRenderLeaf,\n type BindingRenderMap,\n type BindingType,\n type BindingWidget,\n type DataAttrNode,\n canLosslesslyEvaluateSource,\n getCurrentValue,\n getStructuredValue,\n parseBinding,\n} from '~/utils/ast';\n\n// The node-level commit callback's shape, named because it's part of the\n// public surface in two places (`DndPanel`, `Field`) and was previously\n// spelled out inline in each — see #308.\nexport interface PanelNodeChange {\n (params: {\n id: string;\n label: string;\n property: string;\n value: unknown;\n }): void;\n}\n\n// Several `PanelNodeChange`s committed as one edit (#425). They apply in array\n// order, all or none: if any is refused nothing is committed and the error\n// names the one that failed. That is what makes it worth using over calling\n// `PanelNodeChange` in a row, which lands as one document change per call and\n// leaves the earlier ones applied when a later one fails. An empty array does\n// nothing.\nexport interface PanelNodesChange {\n (changes: Parameters<PanelNodeChange>[0][]): void;\n}\n\n// One editable data-binding, flattened out of the selected section for a\n// custom panel. Exposes just what a consumer needs to render its own\n// control — the declared `type`, the current `value`, and an `onChange`\n// that commits through Dnd's AST-update pipeline — so it never has to touch\n// DataAttrNode/parseBinding/getCurrentValue itself.\nexport interface PanelBinding {\n // `data-id` of the owning element — stable across edits.\n id: string;\n // Human-readable label from the binding definition.\n label: string;\n // The bound prop/attribute name (e.g. `children`, `src`, `color`).\n property: string;\n // The declared data-binding type — switch on this to pick a control\n // (`string`/`url` -> <input>, `jsx`/`richtext` -> <textarea>, `boolean`\n // -> checkbox, ...). `undefined` means a plain string binding.\n type?: BindingType;\n // Presentation, as opposed to `type`'s data kind — switch on `widget.type`,\n // an open string rather than a closed enum, since a custom panel can\n // declare any control it wants (e.g. `'slider'`) along with that control's\n // own config (`step`, `unit`, ...). Always the object form even when\n // authored as a bare string. Passed through untouched: the built-in panel\n // ignores it and renders the `type`-appropriate default control.\n //\n // Value constraints are *not* in here — `min`/`max`/`pattern`/`required`\n // below apply with or without a widget.\n widget?: BindingWidget;\n // Present when the binding defines a fixed option set (render a <select>).\n options?: BindingOption[];\n // Present for `object`/`array` bindings whose nested keys/items declare\n // their own types — the same map the built-in panel uses to type each\n // nested field instead of falling back to a plain string input.\n render?: BindingRenderMap;\n // Constraints declared on the binding. `min`/`max` compare against the\n // real number `value` delivers for `type: 'number'` bindings (see\n // `validateBindingValue`).\n min?: number;\n max?: number;\n pattern?: string;\n required?: boolean;\n // Consumer-defined keys carried straight through from the authored\n // data-binding — namespaced instead of spread onto PanelBinding so they\n // can't collide with a future first-class field. Absent when nothing\n // extra was authored. See #234.\n meta?: Record<string, unknown>;\n // Current value as its real JS type — a number for `type: 'number'`, a\n // boolean for `type: 'boolean'`, an object/array for `object`/`array`,\n // a string otherwise. Switch on this without re-parsing. See #238.\n value: unknown;\n // The exact source text behind `value`, for cases that can't round-trip\n // through a JS value — `jsx`/`richtext` bindings, or an attribute whose\n // source is an expression you want to edit as text.\n rawValue: string;\n // False when the built-in control would have to reconstruct a partial\n // literal and could discard an expression, spread, hole or reference.\n // Raw array/JSX editors retain their own narrower source-safe contracts.\n canEditValue?: boolean;\n // `false` when the binding names an attribute the element doesn't carry.\n // Absent otherwise, including for content (`innerText`, `innerHTML`,\n // `children`), which is always there. `onChange(undefined)` removes an\n // attribute and `onChange(value)` adds one back, so this is what a panel\n // reads to draw an on/off control. `prop=\"\"` counts as present (#426).\n present?: boolean;\n // Commit a new value through the same AST-update pipeline the built-in\n // panel uses (including the error Toast on a bad edit). Pass the value as\n // its real type; it's serialized once, at the AST boundary, where the\n // declared `type` is known — so no string quoting/guessing on your side.\n onChange: (value: unknown) => void;\n}\n\n// A `PanelBinding` before a commit callback is attached. The split is the\n// point of this module: reading a node is pure and cacheable, while\n// `onChange` belongs to the render that made it. Binding the two together\n// too early is what caused #336 — a memo keyed on the parsed section handed\n// back callbacks still closed over a previous document.\nexport type PanelBindingData = Omit<PanelBinding, 'onChange'>;\n\n// One data-bound element resolved into panel currency.\nexport interface PanelBindingSource {\n // `data-id` of the element every binding below belongs to.\n id: string;\n // Falls back to `'element'` so a caller rendering a heading never has to\n // repeat that default.\n tagName: string;\n bindings: PanelBindingData[];\n}\n\nconst readAttribute = (node: DataAttrNode, name: string) =>\n node.dataAttributes.find(attribute => attribute.name === name)?.value;\n\nconst canEditBindingValue = (node: DataAttrNode, binding: BindingItem) => {\n // The editor owns these attributes; `update()` refuses them too (#429).\n if (RESERVED_BINDING_PROPERTIES.includes(binding.property)) {\n return false;\n }\n\n if (\n binding.property === 'children' ||\n binding.property === 'innerText' ||\n binding.property === 'innerHTML' ||\n binding.property === 'items' ||\n binding.property === 'data' ||\n binding.type === 'array' ||\n binding.type === 'jsx' ||\n binding.type === 'richtext'\n ) {\n return true;\n }\n\n const attribute = node.attributes.find(\n candidate => candidate.name === binding.property,\n );\n\n // Not in the source yet: nothing to lose, and a value adds it (#426).\n if (!attribute) {\n return true;\n }\n\n return (\n attribute.isStringLiteral === true ||\n canLosslesslyEvaluateSource(attribute?.value ?? '')\n );\n};\n\n// Every field a binding declares, listed exactly once. The mapped return type\n// makes leaving one out a type error, so a field added to `BindingItem`\n// reaches the built-in panel, a custom panel, nested item editors and\n// render-map leaves together instead of whichever path the author happened\n// to edit (#340, #383).\nexport const toBindingFields = (\n binding: BindingItem,\n): { [K in keyof Required<BindingItem>]: BindingItem[K] } => ({\n label: binding.label,\n property: binding.property,\n type: binding.type,\n widget: binding.widget,\n options: binding.options,\n render: binding.render,\n min: binding.min,\n max: binding.max,\n pattern: binding.pattern,\n required: binding.required,\n meta: binding.meta,\n});\n\n// The binding a nested key of an `object`/`array` value would have if it were\n// declared at the top level. A render-map leaf carries its own field spec;\n// `label` and `property` fall back to the key, which is what the property is\n// actually called. A nested map (or nothing) yields an untyped field that\n// still hands its sub-map down.\nexport const resolveRenderEntry = (\n render: BindingRenderMap | undefined,\n key: string,\n): BindingItem => {\n const entry = render?.[key];\n\n if (entry && 'type' in entry) {\n const leaf = entry as BindingRenderLeaf;\n\n return {\n ...leaf,\n label: leaf.label ?? key,\n property: leaf.property ?? key,\n };\n }\n\n return { label: key, property: key, render: entry as BindingRenderMap };\n};\n\n// Properties that are the element's content rather than one of its\n// attributes, so there's nothing to be absent.\nconst CONTENT_PROPERTIES = new Set(['innerText', 'innerHTML', 'children']);\n\nconst isAttributeAbsent = (node: DataAttrNode, binding: BindingItem) =>\n !CONTENT_PROPERTIES.has(binding.property) &&\n !node.attributes.some(candidate => candidate.name === binding.property);\n\nconst toPanelBindingData = (\n node: DataAttrNode,\n id: string,\n binding: BindingItem,\n): PanelBindingData => ({\n ...toBindingFields(binding),\n id,\n value: getStructuredValue(node, binding.property, binding.type),\n rawValue: getCurrentValue(node, binding.property),\n ...(!canEditBindingValue(node, binding) && { canEditValue: false }),\n ...(isAttributeAbsent(node, binding) && { present: false }),\n});\n\n// Read one extracted element's `data-id`/`data-binding` into panel bindings.\n// Returns `null` for anything not editable — a node missing either\n// attribute, or one whose `data-binding` parses to nothing — so callers keep\n// a single \"skip this node\" branch instead of re-deriving the rule.\n//\n// Reuses `node.bindings` when `extract()` already parsed the attribute and\n// only falls back to `parseBinding` otherwise, which is what keeps this\n// cheap enough to run on every node of a section.\nexport const resolvePanelBindings = (\n node: DataAttrNode,\n): PanelBindingSource | null => {\n const id = readAttribute(node, 'data-id');\n const bindingAttr = readAttribute(node, 'data-binding');\n\n if (!id || !bindingAttr) {\n return null;\n }\n\n const parsed = node.bindings ?? parseBinding(bindingAttr);\n\n if (!parsed.length) {\n return null;\n }\n\n return {\n id,\n tagName: node.tagName || 'element',\n bindings: parsed.map(binding => toPanelBindingData(node, id, binding)),\n };\n};\n\n// Attach the node-level commit to already-read bindings. Call this during\n// render, not inside a memo keyed on the parsed source: `commit` closes over\n// the current document, and reusing a stale one writes an older source back\n// over a newer one (#336).\nexport const withPanelCommit = (\n bindings: PanelBindingData[],\n commit: PanelNodeChange | undefined,\n): PanelBinding[] =>\n bindings.map(binding => ({\n ...binding,\n onChange: (value: unknown) =>\n commit?.({\n id: binding.id,\n label: binding.label,\n property: binding.property,\n value,\n }),\n }));\n","import { Button } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Copy, X } from 'lucide-react';\n\ninterface BulkActionsBarProps {\n count: number;\n disabled?: boolean;\n onDuplicate: () => void;\n onMoveUp: () => void;\n onMoveDown: () => void;\n onDelete: () => void;\n onClear: () => void;\n}\n\nconst BulkActionsBar = ({\n count,\n disabled = false,\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 disabled={disabled}\n onClick={onDuplicate}\n />\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n title=\"Move selected up\"\n disabled={disabled}\n onClick={onMoveUp}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n title=\"Move selected down\"\n disabled={disabled}\n onClick={onMoveDown}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n title=\"Delete selected\"\n disabled={disabled}\n onClick={onDelete}\n />\n <Button size=\"small\" onClick={onClear}>\n Clear\n </Button>\n </div>\n </div>\n );\n};\n\nexport default BulkActionsBar;\n","import type { DataAttrNode } from '~/utils/ast';\n\nimport {\n type PanelNodeChange,\n resolvePanelBindings,\n withPanelCommit,\n} from '../panel-binding';\nimport Field from './field';\n\nexport interface FieldEditorProps {\n data: DataAttrNode;\n onChange?: PanelNodeChange;\n}\n\nconst Node = ({ data, onChange }: FieldEditorProps) => {\n const source = resolvePanelBindings(data);\n\n if (!source) {\n return null;\n }\n\n // Keyed by `property`, never `label`: two bindings on one element may\n // share a label, and using it as identity is what #318 fixed elsewhere.\n return (\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {withPanelCommit(source.bindings, onChange).map(binding => (\n <div key={`${binding.id}-${binding.property}`} className=\"space-y-1\">\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">({binding.property})</span>\n </label>\n <Field binding={binding} onNodeChange={onChange} />\n </div>\n ))}\n </div>\n </div>\n );\n};\n\nexport default Node;\n","import { useState } from 'react';\n\nimport { useMultiSelect } from '@jbpark/use-hooks';\n\nimport type { ChildrenAction } from '~/utils/ast';\nimport { moveSelectedIndices } from '~/utils/selection';\n\n// The structural commands both list editors issue (#342). Children sends them\n// to the AST layer as-is; Items translates them to array element positions.\nexport type StructuralCommand = ChildrenAction;\n\n// Where the selection stands after a command succeeds. Commands that leave\n// every existing position in place keep it; a bulk move carries the block to\n// its new positions; anything else shifts positions under the selection, so\n// it is cleared rather than left pointing at different items (#285).\nexport const selectionAfter = (\n command: StructuralCommand,\n selected: ReadonlySet<number>,\n count: number,\n): Set<number> => {\n switch (command.type) {\n case 'append':\n case 'duplicate':\n // Both add at the end, so no existing item moves.\n return new Set(selected);\n case 'move-selected':\n return moveSelectedIndices(\n Array.from({ length: count }, (_, index) => index),\n new Set(command.indices),\n command.direction,\n ).indices;\n default:\n return new Set();\n }\n};\n\ninterface Pending {\n // Recognizes the source this command produced, as opposed to one that\n // came from somewhere else (another field, undo, an external edit).\n matches: (revision: string) => boolean;\n selection: Set<number>;\n}\n\nexport interface RecordOptions {\n // Apply the selection now as well, for a caller that already knows the\n // command succeeded. Otherwise it applies when the source arrives.\n now?: boolean;\n}\n\n// Positional multi-selection for a list whose source can change under it.\n// `revision` identifies the current source. When it changes to the source a\n// recorded command produced, that command's selection applies; when it\n// changes for any other reason, the selection is cleared, since positions in\n// an unrelated source no longer name the same items. A refused command\n// produces no new source, so it changes nothing.\nexport const useStructuralSelection = (count: number, revision: string) => {\n const selection = useMultiSelect(count);\n const [seen, setSeen] = useState(revision);\n const [pending, setPending] = useState<Pending | null>(null);\n\n // Adjusted during render rather than in an effect, so a frame with the\n // previous source's selection never paints.\n if (revision !== seen) {\n setSeen(revision);\n setPending(null);\n\n if (pending?.matches(revision) && pending.selection.size > 0) {\n selection.replace(pending.selection);\n } else {\n selection.clear();\n }\n }\n\n const record = (\n next: Set<number>,\n matches: Pending['matches'],\n { now = false }: RecordOptions = {},\n ) => {\n setPending({ matches, selection: next });\n\n if (!now) {\n return;\n }\n\n // `clear` also drops the shift-range anchor, which `replace` keeps.\n if (next.size > 0) {\n selection.replace(next);\n } else {\n selection.clear();\n }\n };\n\n return { selection, record };\n};\n","import { useMemo } from 'react';\n\nimport {\n type ChildrenAction,\n type ChildrenEdit,\n type DataAttrNode,\n getChildrenSignatures,\n} from '~/utils/ast';\nimport { moveSelectedIndices } from '~/utils/selection';\n\nimport {\n selectionAfter,\n useStructuralSelection,\n} from './use-structural-selection';\n\nexport interface DndChildrenOptions {\n onChange?: (value: string) => void;\n}\n\n// The signature list a successful command produces, as far as it can be\n// known up front: a reorder is a permutation of the current signatures, and\n// an append or duplicate leaves them all in place as a prefix. Lets the\n// selection tell this command's result apart from an unrelated edit.\nconst producedBy = (\n expected: string[],\n action: ChildrenAction,\n): ((revision: string) => boolean) => {\n if (action.type === 'move-selected') {\n const moved = JSON.stringify(\n moveSelectedIndices(expected, new Set(action.indices), action.direction)\n .items,\n );\n\n return revision => revision === moved;\n }\n\n const added =\n action.type === 'append'\n ? 1\n : action.type === 'duplicate'\n ? action.indices.length\n : 0;\n\n return revision => {\n const next = JSON.parse(revision) as string[];\n\n return (\n next.length === expected.length + added &&\n expected.every((signature, index) => next[index] === signature)\n );\n };\n};\n\n// Domain adapter: serializes a structural command for the existing binding\n// onChange/update path. The AST layer owns source validation and mutation;\n// selection follows the shared rule in useStructuralSelection.\nexport const useDndChildren = (\n items: DataAttrNode[],\n { onChange }: DndChildrenOptions = {},\n) => {\n const expected = useMemo(() => getChildrenSignatures(items), [items]);\n const revision = JSON.stringify(expected);\n const { selection, record } = useStructuralSelection(items.length, revision);\n\n // The outcome is only known when new source arrives, so the selection is\n // recorded here and applied then. A rejected edit produces no new source\n // and leaves the selection as it was.\n const commit = (action: ChildrenAction) => {\n const edit: ChildrenEdit = { kind: 'children-edit', expected, action };\n const next = selectionAfter(action, selection.selected, items.length);\n\n if (next.size > 0) {\n record(next, producedBy(expected, action));\n }\n\n onChange?.(JSON.stringify(edit));\n };\n\n return {\n items,\n selection,\n actions: {\n move: (from: number, to: number) => commit({ type: 'move', from, to }),\n remove: (index: number) => commit({ type: 'remove', indices: [index] }),\n add: () => commit({ type: 'append' }),\n duplicateSelected: () =>\n commit({ type: 'duplicate', indices: [...selection.selected] }),\n moveSelected: (direction: 'up' | 'down') =>\n commit({\n type: 'move-selected',\n indices: [...selection.selected],\n direction,\n }),\n removeSelected: () =>\n commit({ type: 'remove', indices: [...selection.selected] }),\n },\n };\n};\n\nexport type DndChildren = ReturnType<typeof useDndChildren>;\n","import { useMemo } from 'react';\n\nimport { Button, Checkbox } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\n\nimport { type DataAttrNode, findEditableChildren } from '~/utils/ast';\n\nimport type { PanelNodeChange } from '../dnd';\nimport BulkActionsBar from './bulk-actions-bar';\nimport Node from './node';\nimport { useDndChildren } from './use-dnd-children';\n\ninterface Props {\n value: DataAttrNode[];\n onChange?: (value: string) => void;\n onNodeChange?: PanelNodeChange;\n}\n\nconst Children = ({ value, onChange, onNodeChange }: Props) => {\n const items = useMemo(() => (Array.isArray(value) ? value : []), [value]);\n\n const { selection, actions } = useDndChildren(items, { onChange });\n\n const editableChildrenMap = useMemo(() => {\n const map = new Map<number, DataAttrNode[]>();\n items.forEach((item, index) => {\n const editableNodes = findEditableChildren(item);\n if (editableNodes.length > 0) {\n map.set(index, editableNodes);\n }\n });\n return map;\n }, [items]);\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold text-green-700\">\n Children Items ({items.length})\n </div>\n <Button\n size=\"small\"\n color=\"green\"\n icon={<Plus />}\n onClick={actions.add}\n >\n Add Child\n </Button>\n </div>\n\n <BulkActionsBar\n count={selection.selected.size}\n onDuplicate={actions.duplicateSelected}\n onMoveUp={() => actions.moveSelected('up')}\n onMoveDown={() => actions.moveSelected('down')}\n onDelete={actions.removeSelected}\n onClear={selection.clear}\n />\n\n {items.map((item, itemIndex) => (\n <div\n key={item.id || itemIndex}\n className=\"space-y-2 rounded border border-green-200 bg-green-50 p-3\"\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-2\">\n <div\n onClick={e => selection.toggle(itemIndex, e.shiftKey)}\n className=\"inline-flex\"\n >\n <Checkbox\n checked={selection.isSelected(itemIndex)}\n onChange={() => {}}\n />\n </div>\n <div className=\"text-xs font-medium text-green-800\">\n Child {itemIndex + 1} ({item.tagName || 'fragment'})\n </div>\n </div>\n\n <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={itemIndex === 0}\n onClick={() => actions.move(itemIndex, itemIndex - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={itemIndex === items.length - 1}\n onClick={() => actions.move(itemIndex, itemIndex + 1)}\n />\n <Button\n title=\"Delete item\"\n danger\n size=\"small\"\n icon={<X />}\n onClick={() => actions.remove(itemIndex)}\n />\n </div>\n </div>\n\n {editableChildrenMap.has(itemIndex) && (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-green-700\">\n Editable Bindings:\n </div>\n {editableChildrenMap.get(itemIndex)!.map((editableNode, idx) => {\n const nodeId = editableNode.dataAttributes.find(\n a => a.name === 'data-id',\n )?.value;\n\n return (\n <div\n key={`editable-${nodeId || idx}`}\n data-node-id={nodeId}\n className=\"rounded border border-green-100 bg-white p-2\n data-[picked]:ring-2 data-[picked]:ring-blue-400\"\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 { BINDING_PROP } from '~/constants';\n\nimport type { PanelBinding } from '../panel-binding';\n\n// Which built-in control `Field` renders for a binding. `BuiltinField`\n// dispatches on this, so a custom panel that asks the same question (most\n// often \"does this binding need a structural editor?\") gets the library's\n// answer rather than a copy of it that can drift.\nexport type FieldKind =\n // `canEditValue: false` — shown as preserved source, not editable.\n | 'readonly'\n // An array literal (`items`/`data` or `type: 'array'`) — the Items editor,\n // or `useDndItems` for your own markup.\n | 'items'\n // Element children given as extracted nodes — the Children editor, or\n // `useDndChildren` for your own markup.\n | 'children'\n | 'richtext'\n | 'jsx'\n | 'html'\n // A plain object value — one nested field per key.\n | 'object'\n | 'boolean'\n | 'select'\n | 'color'\n | 'date'\n | 'url'\n | 'number'\n | 'text';\n\nexport type FieldKindBinding = Pick<\n PanelBinding,\n 'property' | 'type' | 'value' | 'options' | 'canEditValue'\n>;\n\nconst isColorProperty = (property: string): boolean =>\n property.toLowerCase().includes('color');\n\n// Order matters: the first match wins, exactly as the built-in control\n// chooses. `renderField` runs before any of this and can replace the result,\n// so this describes the built-in control, not what a `renderField` override\n// draws.\nexport const getFieldKind = (binding: FieldKindBinding): FieldKind => {\n const { property, type, value } = binding;\n\n if (binding.canEditValue === false) {\n return 'readonly';\n }\n\n if (property === 'items' || property === 'data' || type === 'array') {\n return 'items';\n }\n\n if (type === 'richtext') {\n return 'richtext';\n }\n\n if (property === BINDING_PROP.INNER_HTML) {\n return 'html';\n }\n\n if (type === 'jsx') {\n return 'jsx';\n }\n\n if (property === 'children' && Array.isArray(value)) {\n return 'children';\n }\n\n if (typeof value === 'object' && value !== null && !Array.isArray(value)) {\n return 'object';\n }\n\n if (type === 'boolean' || typeof value === 'boolean') {\n return 'boolean';\n }\n\n if (binding.options && Array.isArray(binding.options)) {\n return 'select';\n }\n\n if (type === 'color' || isColorProperty(property)) {\n return 'color';\n }\n\n if (type === 'date') {\n return 'date';\n }\n\n if (type === 'url') {\n return 'url';\n }\n\n if (type === 'number' || typeof value === 'number') {\n return 'number';\n }\n\n return 'text';\n};\n\n// True for the two kinds whose value holds further data-bound elements, so a\n// flat input can't edit them: route these to `Field` or to the matching hook.\nexport const isStructuralFieldKind = (\n kind: FieldKind,\n): kind is 'items' | 'children' => kind === 'items' || kind === 'children';\n","import {\n type Announcements,\n DndContext,\n type DragEndEvent,\n KeyboardSensor,\n MouseSensor,\n TouchSensor,\n closestCenter,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport {\n restrictToParentElement,\n restrictToVerticalAxis,\n} from '@dnd-kit/modifiers';\nimport {\n SortableContext,\n sortableKeyboardCoordinates,\n useSortable,\n verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { CSS } from '@dnd-kit/utilities';\nimport { ChevronDown, ChevronRight, GripVertical } from 'lucide-react';\n\nimport { cn } from '~/utils/cn';\n\nimport type { DndItemsItem } from './use-dnd-items';\n\nconst label = (items: DndItemsItem[], id: string | number) => {\n const index = items.findIndex(item => item.id === id);\n\n return index >= 0 ? `Item ${index + 1}` : 'Item';\n};\n\n// Drag sorting for the built-in Items editor (#436). It has a context of its\n// own, so a drag here never reaches the canvas's section sorting. Moves go\n// through `actions.move`, the same edit the up/down buttons make.\n//\n// A mouse drag starts after a few pixels of movement. A touch drag starts\n// after a long press, so a short tap still scrolls the panel. The handle is\n// a button, so the keyboard can pick an item up with Space or Enter and move\n// it with the arrow keys.\nexport const SortableItems = ({\n items,\n disabled,\n onMove,\n children,\n}: {\n items: DndItemsItem[];\n disabled?: boolean;\n onMove: (item: DndItemsItem, toIndex: number) => void;\n children: (item: DndItemsItem) => React.ReactNode;\n}) => {\n const sensors = useSensors(\n useSensor(MouseSensor, { activationConstraint: { distance: 4 } }),\n useSensor(TouchSensor, {\n activationConstraint: { delay: 250, tolerance: 5 },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n }),\n );\n\n const onDragEnd = ({ active, over }: DragEndEvent) => {\n const from = items.find(item => item.id === active.id);\n const to = items.find(item => item.id === over?.id);\n\n if (from && to && from !== to) {\n onMove(from, to.index);\n }\n };\n\n // The default announcements read out the items' generated ids.\n const announcements: Announcements = {\n onDragStart: ({ active }) => `Picked up ${label(items, active.id)}.`,\n onDragOver: ({ active, over }) =>\n over\n ? `${label(items, active.id)} is over ${label(items, over.id)}.`\n : undefined,\n onDragEnd: ({ active, over }) =>\n over\n ? `${label(items, active.id)} was moved to the place of ${label(items, over.id)}.`\n : `${label(items, active.id)} was dropped.`,\n onDragCancel: ({ active }) =>\n `Moving ${label(items, active.id)} was cancelled.`,\n };\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n modifiers={[restrictToVerticalAxis, restrictToParentElement]}\n accessibility={{ announcements }}\n onDragEnd={onDragEnd}\n >\n <SortableContext\n items={items.map(item => item.id)}\n strategy={verticalListSortingStrategy}\n disabled={disabled}\n >\n <div className=\"space-y-4\">{items.map(children)}</div>\n </SortableContext>\n </DndContext>\n );\n};\n\n// One item in the Items editor: a header with a drag handle, the selection\n// checkbox and a toggle that shows or hides the item's fields.\nexport const ItemCard = ({\n id,\n title,\n disabled,\n expanded,\n onToggle,\n checkbox,\n controls,\n className,\n children,\n}: {\n id: string;\n title: string;\n disabled?: boolean;\n expanded: boolean;\n onToggle: () => void;\n checkbox: React.ReactNode;\n controls: React.ReactNode;\n className?: string;\n children: React.ReactNode;\n}) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n setActivatorNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id, disabled });\n\n return (\n <div\n ref={setNodeRef}\n style={{ transform: CSS.Translate.toString(transform), transition }}\n className={cn(className, isDragging && 'relative z-10 shadow-md')}\n >\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center space-x-1\">\n <button\n type=\"button\"\n ref={setActivatorNodeRef}\n {...attributes}\n {...listeners}\n aria-label={`Reorder ${title}`}\n disabled={disabled}\n className=\"cursor-grab rounded p-0.5 text-gray-400\n hover:text-gray-700 disabled:cursor-not-allowed\n disabled:opacity-40\"\n >\n <GripVertical size={14} />\n </button>\n {checkbox}\n <button\n type=\"button\"\n aria-expanded={expanded}\n onClick={onToggle}\n className=\"inline-flex items-center space-x-1 rounded px-1 text-xs\n font-medium\"\n >\n {expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}\n <span>{title}</span>\n </button>\n </div>\n {controls}\n </div>\n {expanded && children}\n </div>\n );\n};\n","import { useEffect, useMemo, useRef, useState } from 'react';\n\nimport * as t from '@babel/types';\nimport type { useMultiSelect } from '@jbpark/use-hooks';\nimport { nanoid } from 'nanoid';\n\nimport {\n type BindingRenderMap,\n type DataAttrNode,\n appendArrayItem,\n canLosslesslyEvaluateSource,\n canStructurallyEditArray,\n duplicateArrayItems,\n extract,\n extractNodeValue,\n extractObjectProperties,\n findEditableChildren,\n moveArrayItem,\n moveArrayItems,\n parseArrayExpression,\n parseValue,\n removeArrayItems,\n updateArrayItemProperty,\n updateArrayItemValue,\n} from '~/utils/ast';\nimport { moveSelectedIndices } from '~/utils/selection';\n\nimport { useDndEditOptions } from '../edit-options';\nimport {\n type PanelBinding,\n type PanelNodeChange,\n resolvePanelBindings,\n resolveRenderEntry,\n toBindingFields,\n withPanelCommit,\n} from '../panel-binding';\nimport {\n selectionAfter,\n useStructuralSelection,\n} from './use-structural-selection';\n\n// One data-bound element discovered inside a JSX-valued item property.\n// These are the elements the top-level `bindings` array can't reach —\n// `extract()` doesn't walk into an attribute expression, so they're found\n// by re-extracting the property's own JSX here (#308).\nexport interface DndItemsNestedElement {\n // The element's `data-id`, which is what commits address it by.\n id: string;\n tagName: string;\n bindings: PanelBinding[];\n}\n\nexport interface DndItemsNestedGroup {\n // The item property holding this JSX (e.g. `children`, `label`).\n property: string;\n elements: DndItemsNestedElement[];\n // Set instead of `elements` when the JSX parsed but declared no binding\n // at all. Editing the property's raw source is the only thing left to\n // offer, so this is a `jsx`-typed binding over that source (#298).\n fallback?: PanelBinding;\n}\n\nexport interface DndItemsItem {\n // Stable while this hook can prove the same item survived a source edit.\n // Structural actions update this identity alongside the source patch, so\n // React keys follow moved/duplicated/deleted rows instead of their positions.\n id: string;\n // Position among the visible items of this kind, which is what selection\n // indices refer to.\n index: number;\n // Position in the array's elements, which is what every `~/utils/ast`\n // item function addresses. Differs from `index` when the array mixes\n // objects and primitives.\n elementIndex: number;\n // An object item's plain (non-JSX) properties, already resolved through\n // the binding `render` map.\n properties: PanelBinding[];\n // An object item's JSX-valued properties.\n nested: DndItemsNestedGroup[];\n // A primitive item's own value. Absent on object items.\n value?: PanelBinding;\n}\n\nexport interface DndItemsActions {\n // Appends a copy of the first item of the current `kind`. An array\n // binding stays editable only while it holds at least one item: the shape\n // of a new item comes from its siblings, never from a guess. On an empty\n // array this is a no-op that raises the failure toast, so a custom panel\n // should offer it only when `items` is non-empty, the way the built-in\n // panel does (#316).\n add: () => void;\n move: (elementIndex: number, toIndex: number) => void;\n // Refuses the edit that would remove the last item, keeping the array\n // non-empty and therefore editable.\n remove: (elementIndex: number) => void;\n duplicateSelected: () => void;\n moveSelected: (direction: 'up' | 'down') => void;\n removeSelected: () => void;\n}\n\n// Which items show their fields. Keyed by `DndItemsItem.id`, so an item\n// keeps its state when it moves, a sibling changes, or another item is\n// added or removed. Every item starts expanded, including one added later.\n// The hook only holds the state; drawing a collapsed item is the panel's job.\nexport interface DndItemsExpansion {\n // The ids of the current items that are expanded, in item order.\n expandedIds: string[];\n isExpanded: (id: string) => boolean;\n toggle: (id: string) => void;\n // Expands exactly these items and collapses the rest. Pass every id to\n // expand all, or `[]` to collapse all.\n setExpanded: (ids: string[]) => void;\n}\n\nexport interface DndItems {\n // Which kind the array is being edited as. The panel shows one kind at a\n // time; an array holding both is treated as objects, and the primitives\n // stay untouched rather than being dropped.\n kind: 'object' | 'primitive';\n items: DndItemsItem[];\n // `@jbpark/use-hooks`' multi-select state, re-exposed as-is: `selected`,\n // `toggle`, `isSelected`, `clear`, `replace`. Its indices are item\n // `index` values, not `elementIndex` — the actions below translate.\n selection: ReturnType<typeof useMultiSelect>;\n expansion: DndItemsExpansion;\n actions: DndItemsActions;\n // Whether the current source can be moved, copied, removed or appended\n // without losing syntax. Value/property edits can remain available when\n // this is false. Every action revalidates the source before committing.\n canEditStructure: boolean;\n // The source didn't parse as an array expression. `items` is empty; the\n // built-in panel also raises a toast.\n parseError: boolean;\n}\n\nexport interface DndItemsOptions {\n render?: BindingRenderMap;\n // Commits a whole new array source. Every mutation here goes through\n // `~/utils/ast`'s item functions, which re-parse the source and hand back\n // a string, so no AST node is held or edited across renders.\n onChange?: (value: string) => void;\n // Commits an edit to one nested element, addressed by its own `data-id`.\n // A single binding's `onChange` can't express this — see #308.\n onNodeChange?: PanelNodeChange;\n}\n\ninterface RawObjectItem {\n id: string;\n index: number;\n elementIndex: number;\n source: string;\n editableProperties: ReturnType<typeof extractObjectProperties>;\n jsxBindings: Record<string, DataAttrNode[]>;\n jsxFallbacks: Record<string, string>;\n}\n\ninterface RawPrimitiveItem {\n id: string;\n index: number;\n elementIndex: number;\n source: string;\n value: string | number | boolean | null;\n type: ReturnType<typeof extractNodeValue>['type'];\n}\n\n// What an edit reads: this render's array, or the one a same-tick commit\n// left behind (#451), with the item identity and selection that go with it.\ninterface Snapshot {\n value: string;\n items: Array<RawObjectItem | RawPrimitiveItem>;\n ids: string[];\n selected: Set<number>;\n}\n\ninterface PendingCommit {\n // The render `value` the commit was built on.\n from: string;\n value: string;\n ids: string[];\n selected: Set<number>;\n}\n\nconst createPendingCommit = () => {\n let current: PendingCommit | null = null;\n\n return {\n read: () => current,\n write: (next: PendingCommit) => {\n current = next;\n },\n clear: () => {\n current = null;\n },\n };\n};\n\ninterface ItemIdentityState {\n value: string;\n kind: DndItems['kind'];\n ids: string[];\n signatures: string[];\n}\n\n// Pulls the data-bound elements out of one JSX-valued property. A container\n// declaring `children` wins outright: it owns the elements below it, so\n// listing them separately would offer the same edit twice.\nconst bindingsInJSX = (source: string): DataAttrNode[] => {\n const nodes = extract(source);\n const container = nodes.find(n =>\n n.bindings?.some(b => b.property === 'children'),\n );\n\n if (container) {\n return [container];\n }\n\n const bindings: DataAttrNode[] = [];\n\n nodes.forEach(n => {\n if (\n n.bindings &&\n n.bindings.length > 0 &&\n n.dataAttributes.some(a => a.name === 'data-id')\n ) {\n bindings.push(n);\n }\n\n bindings.push(...findEditableChildren(n));\n });\n\n return bindings;\n};\n\n// The parse. Split from the binding construction below so the Babel work is\n// memoized on the source string alone, while the callbacks the bindings\n// close over stay current on every render.\nconst parseSource = (value: string) => {\n const ast = parseArrayExpression(value);\n\n if (!ast) {\n return { objectItems: [], primitiveItems: [], parseError: true };\n }\n\n const objectItems: RawObjectItem[] = [];\n const primitiveItems: RawPrimitiveItem[] = [];\n ast.elements.forEach((element, elementIndex) => {\n if (!t.isExpression(element)) {\n return;\n }\n\n if (!t.isObjectExpression(element)) {\n const extracted = extractNodeValue(element);\n\n primitiveItems.push({\n id: nanoid(6),\n index: primitiveItems.length,\n elementIndex,\n source: value.slice(element.start!, element.end!),\n value: extracted.value,\n type: extracted.type,\n });\n return;\n }\n\n const jsxBindings: Record<string, DataAttrNode[]> = {};\n const jsxFallbacks: Record<string, string> = {};\n\n element.properties.forEach(prop => {\n if (\n !t.isObjectProperty(prop) ||\n !t.isIdentifier(prop.key) ||\n !(t.isJSXElement(prop.value) || t.isJSXFragment(prop.value))\n ) {\n return;\n }\n\n const propertyName = prop.key.name;\n\n try {\n const found = bindingsInJSX(\n value.slice(prop.value.start!, prop.value.end!),\n );\n\n if (found.length > 0) {\n jsxBindings[propertyName] = found;\n } else {\n jsxFallbacks[propertyName] = value.slice(\n prop.value.start!,\n prop.value.end!,\n );\n }\n } catch (error) {\n console.error(\n `Failed to parse JSX in property '${propertyName}':`,\n error,\n );\n }\n });\n\n const editableProperties = extractObjectProperties(element);\n\n for (const property of Object.values(editableProperties)) {\n if (property.type === 'array' || property.type === 'object') {\n property.value = value.slice(\n property.astNode.start!,\n property.astNode.end!,\n );\n }\n }\n\n objectItems.push({\n id: nanoid(6),\n index: objectItems.length,\n elementIndex,\n source: value.slice(element.start!, element.end!),\n editableProperties,\n jsxBindings,\n jsxFallbacks,\n });\n });\n\n return { objectItems, primitiveItems, parseError: false };\n};\n\nconst createIdentityState = (\n value: string,\n kind: DndItems['kind'],\n items: Array<RawObjectItem | RawPrimitiveItem>,\n ids: string[] = items.map(item => item.id),\n): ItemIdentityState => ({\n value,\n kind,\n ids,\n signatures: items.map(item => item.source),\n});\n\nconst reconcileIdentityState = (\n current: ItemIdentityState | null,\n value: string,\n kind: DndItems['kind'],\n items: Array<RawObjectItem | RawPrimitiveItem>,\n): ItemIdentityState => {\n if (\n current &&\n current.value === value &&\n current.kind === kind &&\n current.ids.length === items.length\n ) {\n return current;\n }\n\n if (!current || current.kind !== kind) {\n return createIdentityState(value, kind, items);\n }\n\n const previousCounts = new Map<string, number>();\n const nextCounts = new Map<string, number>();\n\n current.signatures.forEach(signature => {\n previousCounts.set(signature, (previousCounts.get(signature) ?? 0) + 1);\n });\n items.forEach(item => {\n nextCounts.set(item.source, (nextCounts.get(item.source) ?? 0) + 1);\n });\n\n const ids = items.map(item => {\n const previousIndex = current.signatures.indexOf(item.source);\n\n return previousIndex >= 0 &&\n previousCounts.get(item.source) === 1 &&\n nextCounts.get(item.source) === 1\n ? current.ids[previousIndex]!\n : item.id;\n });\n\n return createIdentityState(value, kind, items, ids);\n};\n\nconst moveId = (ids: string[], from: number, to: number) => {\n const next = [...ids];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved!);\n\n return next;\n};\n\nconst removeIds = (ids: string[], indices: Set<number>) => {\n return ids.filter((_, index) => !indices.has(index));\n};\n\n// The array-editing engine behind the built-in Items panel, exposed so a\n// consumer can render their own markup over it (#237/#308 follow-up).\n//\n// What it saves reimplementing: re-parsing each item's JSX to find nested\n// data-bound elements, resolving the binding `render` map, translating\n// visible item positions to array element positions before every edit, and\n// reconciling the selection after a move or delete (#285). Everything comes\n// back as `PanelBinding`s, the same currency `useDndPanel()` and\n// `Live.Dnd.Field` already speak, so nothing here requires touching Babel.\nexport const useDndItems = (\n value: string,\n { render, onChange, onNodeChange }: DndItemsOptions = {},\n): DndItems => {\n const { objectItems, primitiveItems, parseError } = useMemo(\n () => parseSource(value),\n [value],\n );\n const canEditStructure = useMemo(\n () => canStructurallyEditArray(value),\n [value],\n );\n\n const { reportError } = useDndEditOptions();\n\n // Read through a ref so the effect below fires once per parse failure, not\n // again on every render a host passes a fresh inline `onEditError`.\n const reportErrorRef = useRef(reportError);\n\n useEffect(() => {\n reportErrorRef.current = reportError;\n });\n\n useEffect(() => {\n if (parseError) {\n reportErrorRef.current({\n type: 'parse',\n target: 'items',\n title: 'Failed to parse items',\n description: 'Check the console for details.',\n });\n }\n }, [parseError]);\n\n const kind =\n primitiveItems.length > 0 && objectItems.length === 0\n ? 'primitive'\n : 'object';\n const isPrimitive = kind === 'primitive';\n const rawItems = isPrimitive ? primitiveItems : objectItems;\n const [identityState, setIdentityState] = useState(() =>\n createIdentityState(value, kind, rawItems),\n );\n const identity = useMemo(\n () => reconcileIdentityState(identityState, value, kind, rawItems),\n [identityState, kind, rawItems, value],\n );\n\n // Collapsed rather than expanded ids, so an item this hook hasn't seen\n // yet, such as one just added, starts expanded. Ids are never reused, so\n // one left behind by a removed item can't collapse another.\n const [collapsed, setCollapsed] = useState<ReadonlySet<string>>(\n () => new Set(),\n );\n\n const { selection, record } = useStructuralSelection(\n isPrimitive ? primitiveItems.length : objectItems.length,\n value,\n );\n\n // The array the last commit produced, with the identity and selection that\n // go with it, tagged with the render `value` it was built on. Every edit\n // below computes a whole new array from a snapshot, and the host only\n // hands the result back as `value` on the next render, so two edits in the\n // same tick both started from this render's array and the second dropped\n // the first (#451). Edits read `latest()` instead.\n //\n // Dropped after each render, as `useSectionDocument` does for the document\n // (#450): from then on the rendered `value` is the source of truth again,\n // including when the host didn't accept the commit.\n //\n // Held in a `useState` box rather than a ref: the item bindings below are\n // built during render and close over `latest()`, which the compiler reads\n // as a ref access in render even though only their `onChange` calls it —\n // the same reason `useSectionDocument` keeps its preview cache this way.\n const [pending] = useState(createPendingCommit);\n\n useEffect(() => {\n pending.clear();\n });\n\n const latest = (): Snapshot => {\n const last = pending.read();\n\n if (last?.from !== value) {\n return {\n value,\n items: rawItems,\n ids: identity.ids,\n selected: selection.selected,\n };\n }\n\n const parsed = parseSource(last.value);\n\n return {\n value: last.value,\n items: isPrimitive ? parsed.primitiveItems : parsed.objectItems,\n ids: last.ids,\n selected: last.selected,\n };\n };\n\n // Where the item this render showed at `elementIndex` is in `snapshot`,\n // followed by identity so an edit lands on the same item after a\n // same-tick move. `null` when a same-tick edit removed it; `undefined`\n // when this render has no such item, so the caller keeps the position it\n // was given.\n const locate = (snapshot: Snapshot, elementIndex: number) => {\n const shown = rawItems.find(item => item.elementIndex === elementIndex);\n\n if (!shown) {\n return undefined;\n }\n\n const index = snapshot.ids.indexOf(identity.ids[shown.index]!);\n\n return index >= 0 ? snapshot.items[index] : null;\n };\n\n // `null` means the edit could not be applied. `nextSelection` is where the\n // selection stands once it is: applied now, since a non-null `next` means\n // the edit succeeded, and again when this exact source comes back as\n // `value`. Any other new `value` clears it (useStructuralSelection).\n const commit = (\n snapshot: Snapshot,\n next: string | null,\n nextIds: string[] | undefined,\n nextSelection: Set<number>,\n ) => {\n if (next === null) {\n reportError({\n type: 'items',\n title: 'Failed to update this item',\n description:\n 'The source was preserved. Structural edits require a dense array without spreads; use the code editor for unsupported syntax.',\n });\n\n return false;\n }\n\n const parsed = parseSource(next);\n const nextItems =\n kind === 'primitive' ? parsed.primitiveItems : parsed.objectItems;\n const ids = nextIds ?? snapshot.ids;\n\n pending.write({\n from: value,\n value: next,\n ids,\n selected: nextSelection,\n });\n setIdentityState(createIdentityState(next, kind, nextItems, ids));\n record(nextSelection, revision => revision === next, { now: true });\n onChange?.(next);\n\n return true;\n };\n\n // Selection indices are positions among the visible items; every AST\n // function addresses element positions. Keeping the two apart is what\n // stops an edit from dropping the items that aren't on screen.\n const elementIndicesOf = (snapshot: Snapshot, indices: Set<number>) =>\n new Set(\n snapshot.items\n .filter(item => indices.has(item.index))\n .map(item => item.elementIndex),\n );\n\n const updateProperty = (\n elementIndex: number,\n propertyKey: string,\n next: unknown,\n ) => {\n const snapshot = latest();\n const item = locate(snapshot, elementIndex);\n\n if (item === null) {\n return;\n }\n\n // A value edit moves nothing, so the selection stands.\n commit(\n snapshot,\n updateArrayItemProperty(\n snapshot.value,\n item?.elementIndex ?? elementIndex,\n propertyKey,\n next,\n render,\n ),\n undefined,\n new Set(snapshot.selected),\n );\n };\n\n const updateValue = (elementIndex: number, next: unknown) => {\n const snapshot = latest();\n const item = locate(snapshot, elementIndex);\n\n if (item === null) {\n return;\n }\n\n commit(\n snapshot,\n updateArrayItemValue(\n snapshot.value,\n item?.elementIndex ?? elementIndex,\n next,\n ),\n undefined,\n new Set(snapshot.selected),\n );\n };\n\n const actions: DndItemsActions = {\n add: () => {\n const snapshot = latest();\n const next = appendArrayItem(snapshot.value, kind);\n\n commit(\n snapshot,\n next,\n next ? [...snapshot.ids, nanoid(6)] : undefined,\n selectionAfter(\n { type: 'append' },\n snapshot.selected,\n snapshot.items.length,\n ),\n );\n },\n\n move: (elementIndex, toIndex) => {\n const snapshot = latest();\n const from = locate(snapshot, elementIndex);\n const target = snapshot.items.find(item => item.index === toIndex);\n\n if (!from || !target) {\n return;\n }\n\n // Positions shift after a move but the count doesn't, so the\n // selection is cleared rather than left on the wrong items (#285).\n commit(\n snapshot,\n moveArrayItem(snapshot.value, from.elementIndex, target.elementIndex),\n moveId(snapshot.ids, from.index, target.index),\n new Set(),\n );\n },\n\n remove: elementIndex => {\n const snapshot = latest();\n const removed = locate(snapshot, elementIndex);\n\n if (removed === null) {\n return;\n }\n\n // Removing an item shifts every position after it; same reasoning.\n commit(\n snapshot,\n removeArrayItems(\n snapshot.value,\n new Set([removed?.elementIndex ?? elementIndex]),\n kind,\n ),\n removed ? removeIds(snapshot.ids, new Set([removed.index])) : undefined,\n new Set(),\n );\n },\n\n duplicateSelected: () => {\n const snapshot = latest();\n const selected = elementIndicesOf(snapshot, snapshot.selected);\n const next = duplicateArrayItems(snapshot.value, selected);\n const copied = snapshot.items\n .filter(item => selected.has(item.elementIndex))\n .sort((a, b) => a.elementIndex - b.elementIndex)\n .map(() => nanoid(6));\n\n commit(\n snapshot,\n next,\n next ? [...snapshot.ids, ...copied] : undefined,\n selectionAfter(\n { type: 'duplicate', indices: [...snapshot.selected] },\n snapshot.selected,\n snapshot.items.length,\n ),\n );\n },\n\n moveSelected: direction => {\n const snapshot = latest();\n const nextIdentity = moveSelectedIndices(\n snapshot.ids,\n snapshot.selected,\n direction,\n );\n const result = moveArrayItems(\n snapshot.value,\n elementIndicesOf(snapshot, snapshot.selected),\n direction,\n );\n\n if (!result) {\n commit(snapshot, null, undefined, snapshot.selected);\n return;\n }\n\n // Translate the moved source positions back into the visible kind.\n const parsed = parseArrayExpression(result.code);\n const visible =\n parsed?.elements.flatMap((node, index) =>\n t.isExpression(node) && t.isObjectExpression(node) === !isPrimitive\n ? [index]\n : [],\n ) ?? [];\n // The moved block, mapped back from element positions: in a mixed\n // array a step can pass a hidden element, so this is not the same as\n // shifting the visible indices.\n commit(\n snapshot,\n result.code,\n nextIdentity.items,\n new Set(\n visible.flatMap((position, index) =>\n result.indices.has(position) ? [index] : [],\n ),\n ),\n );\n },\n\n removeSelected: () => {\n const snapshot = latest();\n\n commit(\n snapshot,\n removeArrayItems(\n snapshot.value,\n elementIndicesOf(snapshot, snapshot.selected),\n kind,\n ),\n removeIds(snapshot.ids, snapshot.selected),\n new Set(),\n );\n },\n };\n\n // Built fresh each render rather than inside the memo above: these close\n // over `onChange`/`onNodeChange`, and the work is a plain walk of the\n // already-parsed result — no Babel.\n const items: DndItemsItem[] = isPrimitive\n ? primitiveItems.map(item => ({\n id: identity.ids[item.index] ?? item.id,\n index: item.index,\n elementIndex: item.elementIndex,\n properties: [],\n nested: [],\n value: {\n id: `primitive-${item.id}`,\n label: `item-${item.index}`,\n property: item.type,\n value: item.value ?? '',\n rawValue:\n item.type === 'unknown' ? item.source : String(item.value ?? ''),\n canEditValue: canLosslesslyEvaluateSource(item.source),\n onChange: next => updateValue(item.elementIndex, next),\n },\n }))\n : objectItems.map(item => {\n const id = identity.ids[item.index] ?? item.id;\n const properties: PanelBinding[] = Object.entries(\n item.editableProperties,\n ).map(([key, prop]) => {\n const binding = resolveRenderEntry(render, key);\n const propertySource = value.slice(\n prop.astNode.start!,\n prop.astNode.end!,\n );\n\n return {\n ...toBindingFields(binding),\n id: `item-${id}-${key}`,\n // Merged over the leaf's own metadata, never under it: a consumer\n // labels the control with the property's actual kind, as the\n // built-in panel does, so an authored `valueType` can't shadow it.\n meta: { ...binding.meta, valueType: prop.type },\n value: parseValue(String(prop.value)),\n rawValue:\n prop.type === 'unknown' ? propertySource : String(prop.value),\n canEditValue: canLosslesslyEvaluateSource(propertySource),\n onChange: next => updateProperty(item.elementIndex, key, next),\n };\n });\n\n const nested: DndItemsNestedGroup[] = [\n ...Object.entries(item.jsxBindings).map(([property, nodes]) => ({\n property,\n elements: nodes.flatMap(node => {\n const source = resolvePanelBindings(node);\n\n if (!source) {\n return [];\n }\n\n return [\n {\n id: source.id,\n tagName: source.tagName,\n bindings: withPanelCommit(source.bindings, onNodeChange),\n },\n ];\n }),\n })),\n ...Object.entries(item.jsxFallbacks).map(([property, code]) => ({\n property,\n elements: [],\n fallback: {\n id: `item-${id}-${property}-jsx`,\n label: property,\n property,\n type: 'jsx' as const,\n value: code,\n rawValue: code,\n canEditValue: true,\n onChange: (next: unknown) =>\n updateProperty(item.elementIndex, property, next),\n },\n })),\n ];\n\n return {\n id,\n index: item.index,\n elementIndex: item.elementIndex,\n properties,\n nested,\n };\n });\n\n const expansion: DndItemsExpansion = {\n expandedIds: items.flatMap(item =>\n collapsed.has(item.id) ? [] : [item.id],\n ),\n isExpanded: id => !collapsed.has(id),\n toggle: id =>\n setCollapsed(previous => {\n const next = new Set(previous);\n\n if (!next.delete(id)) {\n next.add(id);\n }\n\n return next;\n }),\n setExpanded: ids => {\n const expanded = new Set(ids);\n\n setCollapsed(\n new Set(\n items.flatMap(item => (expanded.has(item.id) ? [] : [item.id])),\n ),\n );\n },\n };\n\n return {\n kind,\n items,\n selection,\n expansion,\n actions,\n canEditStructure,\n parseError,\n };\n};\n","import { Button, Checkbox } from '@jbpark/ui-kit';\nimport { ArrowDown, ArrowUp, Plus, X } from 'lucide-react';\n\nimport type { BindingRenderMap } from '~/utils/ast';\n\nimport type { PanelNodeChange } from '../dnd';\nimport BulkActionsBar from './bulk-actions-bar';\nimport Field from './field';\nimport { ItemCard, SortableItems } from './sortable-items';\nimport {\n type DndItemsItem,\n type DndItemsNestedGroup,\n useDndItems,\n} from './use-dnd-items';\n\ninterface Props {\n value: string;\n render?: BindingRenderMap;\n onChange?: (value: string) => void;\n onChildChange?: PanelNodeChange;\n}\n\n// The data-bound elements found inside one JSX-valued property, or the\n// raw-source fallback when that property declared no binding at all (#298).\nconst NestedGroup = ({\n group,\n onNodeChange,\n}: {\n group: DndItemsNestedGroup;\n onNodeChange?: PanelNodeChange;\n}) => {\n if (group.fallback) {\n return (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {group.property}\n </div>\n <Field binding={group.fallback} onNodeChange={onNodeChange} />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"text-xs font-medium text-blue-700\">\n {group.property} Bindings ({group.elements.length}):\n </div>\n {group.elements.map(element => (\n <div\n key={`${group.property}-${element.id}`}\n data-node-id={element.id}\n className=\"rounded border border-blue-100 bg-blue-50 p-2\n data-[picked]:ring-2 data-[picked]:ring-blue-400\"\n >\n <div className=\"mb-1 text-xs text-blue-600\">\n &lt;{element.tagName}&gt;\n </div>\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {element.bindings.map(binding => (\n <div\n key={`${binding.property}-${binding.label}`}\n className=\"space-y-1\"\n >\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">\n ({binding.property})\n </span>\n </label>\n <Field binding={binding} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n </div>\n </div>\n ))}\n </div>\n );\n};\n\n// Presentation for `useDndItems`. Everything that reads or writes the\n// array source lives in that hook, which is exported so a consumer can put\n// their own markup over the same engine — see its doc comment (#237/#308).\nconst Items = ({ value, render, onChange, onChildChange }: Props) => {\n const {\n kind,\n items,\n selection,\n expansion,\n actions,\n canEditStructure,\n parseError,\n } = useDndItems(value, {\n render,\n onChange,\n onNodeChange: onChildChange,\n });\n\n const header = (\n <div className=\"flex items-center justify-between\">\n <div className=\"text-sm font-semibold\">Items ({items.length})</div>\n {/* Add copies an existing item, so it is offered only once there is\n one to copy — see the empty-list notice below (#316). */}\n {items.length > 0 && canEditStructure && (\n <Button\n size=\"small\"\n icon={<Plus />}\n variant=\"solid\"\n color=\"green\"\n onClick={actions.add}\n >\n Add Item\n </Button>\n )}\n </div>\n );\n\n if (parseError) {\n return (\n <div className=\"space-y-4\">\n {header}\n <div\n className=\"rounded border border-dashed border-red-200 p-3 text-xs\n text-red-600\"\n >\n This value could not be read as a list. Edit it in the code editor.\n </div>\n </div>\n );\n }\n\n // An array binding is editable only while it holds at least one item: the\n // panel derives an item's shape from its siblings and will not invent one.\n // `removeArrayItems` already refuses to empty a populated array, so this\n // state means the source itself declared `[]` (or only holes/spreads).\n if (items.length === 0) {\n return (\n <div className=\"space-y-4\">\n {header}\n <div\n className=\"rounded border border-dashed border-gray-200 p-3 text-xs\n text-gray-500\"\n >\n No editable items. The panel copies an existing item rather than\n guessing the shape of a new one — add the first item in the code\n editor.\n </div>\n </div>\n );\n }\n\n const bulkBar = (\n <BulkActionsBar\n count={selection.selected.size}\n disabled={!canEditStructure}\n onDuplicate={actions.duplicateSelected}\n onMoveUp={() => actions.moveSelected('up')}\n onMoveDown={() => actions.moveSelected('down')}\n onDelete={actions.removeSelected}\n onClear={selection.clear}\n />\n );\n\n const itemControls = (item: DndItemsItem) => (\n <div className=\"flex space-x-1\">\n <Button\n size=\"small\"\n icon={<ArrowUp />}\n disabled={!canEditStructure || item.index === 0}\n onClick={() => actions.move(item.elementIndex, item.index - 1)}\n />\n <Button\n size=\"small\"\n icon={<ArrowDown />}\n disabled={!canEditStructure || item.index === items.length - 1}\n onClick={() => actions.move(item.elementIndex, item.index + 1)}\n />\n <Button\n danger\n size=\"small\"\n icon={<X />}\n disabled={!canEditStructure || items.length <= 1}\n onClick={() => actions.remove(item.elementIndex)}\n />\n </div>\n );\n\n const itemCheckbox = (item: DndItemsItem) => (\n <div\n onClick={e =>\n canEditStructure && selection.toggle(item.index, e.shiftKey)\n }\n className=\"inline-flex\"\n >\n <Checkbox\n checked={selection.isSelected(item.index)}\n disabled={!canEditStructure}\n onChange={() => {}}\n />\n </div>\n );\n\n const objectBody = (item: DndItemsItem) => (\n <>\n <div className=\"space-y-2\">\n {item.properties.map(binding => (\n <div key={`${item.id}-${binding.property}-${binding.label}`}>\n <div className=\"flex flex-col space-y-2\">\n <label className=\"w-20 shrink-0 text-xs font-medium\">\n {binding.label}\n </label>\n <Field binding={binding} onNodeChange={onChildChange} />\n </div>\n <span className=\"text-right text-xs text-gray-500\">\n ({String(binding.meta?.valueType)})\n </span>\n </div>\n ))}\n </div>\n <div className=\"space-y-3 border-t pt-2\">\n {item.nested.length ? (\n item.nested.map(group => (\n <NestedGroup\n key={group.property}\n group={group}\n onNodeChange={onChildChange}\n />\n ))\n ) : (\n <div className=\"text-xs text-gray-500\">✓ No JSX bindings found</div>\n )}\n </div>\n </>\n );\n\n const allExpanded = expansion.expandedIds.length === items.length;\n\n return (\n <div className=\"space-y-4\">\n {header}\n\n {items.length > 1 && (\n <div className=\"flex justify-end\">\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() =>\n expansion.setExpanded(\n allExpanded ? [] : items.map(item => item.id),\n )\n }\n >\n {allExpanded ? 'Collapse all' : 'Expand all'}\n </Button>\n </div>\n )}\n\n {bulkBar}\n\n {!canEditStructure && (\n <div\n className=\"rounded border border-dashed border-amber-200 p-3 text-xs\n text-amber-700\"\n >\n Values remain editable, but moving, copying, adding, and deleting\n require a dense array without spreads or parenthesized top-level\n items. Use the code editor for those structural changes.\n </div>\n )}\n\n <SortableItems\n items={items}\n disabled={!canEditStructure}\n onMove={(item, toIndex) => actions.move(item.elementIndex, toIndex)}\n >\n {item => (\n <ItemCard\n key={item.id}\n id={item.id}\n title={`Item ${item.index + 1}`}\n disabled={!canEditStructure}\n expanded={expansion.isExpanded(item.id)}\n onToggle={() => expansion.toggle(item.id)}\n checkbox={itemCheckbox(item)}\n controls={itemControls(item)}\n className={\n kind === 'primitive'\n ? 'space-y-2 rounded border border-gray-100 bg-gray-50 p-2'\n : 'space-y-3 rounded border bg-gray-50 p-3'\n }\n >\n {kind === 'primitive' ? (\n <Field binding={item.value!} onNodeChange={onChildChange} />\n ) : (\n objectBody(item)\n )}\n </ItemCard>\n )}\n </SortableItems>\n </div>\n );\n};\n\nexport default Items;\n","import {\n type ComponentProps,\n type FocusEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport {\n Checkbox,\n ColorPicker,\n DatePicker,\n Input,\n RichTextEditor,\n Select,\n} from '@jbpark/ui-kit';\nimport { useDebounce } from '@jbpark/use-hooks';\nimport type {\n EditorSelection,\n EditorView,\n ViewUpdate,\n} from '@uiw/react-codemirror';\n\nimport CoreEditor from '~/components/editor/core';\nimport {\n type DataAttrNode,\n parseValue,\n validateBindingValue,\n} from '~/utils/ast';\n\nimport type { PanelBinding, PanelNodeChange } from '../dnd';\nimport { useDndEditOptions } from '../edit-options';\nimport { resolveRenderEntry, toBindingFields } from '../panel-binding';\nimport Children from './children';\nimport { getFieldKind } from './field-kind';\nimport Items from './items';\n\n// Exported as `Live.Dnd.Field` (see index.ts) so a custom panel can\n// hand any single binding back to the built-in control instead of\n// reimplementing it — most usefully for `items`/`children` bindings, whose\n// editors discover nested data-bound elements by re-extracting the value's\n// own JSX (~100 lines of Babel walking a consumer would otherwise have to\n// reproduce). Renders the *control* only; the built-in panel's label comes\n// from `FieldGroup`, so a consumer supplies their own heading and layout.\nexport interface FieldProps {\n binding: PanelBinding;\n // `Items`/`Children` edit a *different* element than `binding` itself —\n // an array item or a sibling child, each with its own id/label/property —\n // which `binding.onChange`'s single-value shape can't express. This is\n // the node-level escape hatch those two need (see #237's documented\n // items/children boundary). Not part of `PanelBinding`, which is\n // per-binding; it reaches a custom panel through `useDndPanel()`\n // instead (#308). Omit it and nested array/children edits won't commit.\n onNodeChange?: PanelNodeChange;\n}\n\nconst normalizeToHex = (value: string): string => {\n const trimmed = value.trim();\n\n if (/^#([0-9A-Fa-f]{3}){1,2}$/.test(trimmed)) {\n return trimmed;\n }\n return '#000000';\n};\n\nconst parseDateValue = (value: string): Date | undefined => {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(value.trim());\n\n if (!match) {\n return undefined;\n }\n\n const [, year, month, day] = match;\n const date = new Date(Number(year), Number(month) - 1, Number(day));\n\n return Number.isNaN(date.getTime()) ? undefined : date;\n};\n\nconst formatDateValue = (date: Date): string => {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return `${year}-${month}-${day}`;\n};\n\n// ColorPicker's onChange fires on every drag frame — committing straight\n// to `onChange` (which drives the AST parse/mutate/re-serialize +\n// generateSections + compile pipeline, see #130) makes a single drag cost\n// upward of 15-25ms per frame. Debouncing the *commit* keeps that pipeline\n// to roughly one run per pause instead of one per frame, while a local\n// `liveValue` state keeps the swatch/hex text updating every frame for\n// responsiveness — ColorPicker is fully controlled (`useControllableState`\n// with `value` always set here), so without this it would visually snap\n// back to the last committed color between debounced commits.\nconst COLOR_COMMIT_DELAY = 75;\n\n// A curated subset rather than `toolbar` (every preset): the panel is a\n// small sidebar field, not a full document editor, so this keeps to the\n// formatting controls most binding content actually needs.\nconst RICHTEXT_TOOLBAR: ComponentProps<typeof RichTextEditor>['toolbar'] = [\n 'bold',\n 'italic',\n 'underline',\n 'bulletList',\n 'orderedList',\n 'link',\n];\n\ninterface ColorPickerFieldProps {\n value: string;\n onChange: (value: string) => void;\n}\n\ninterface JSXEditorFieldProps {\n value: string;\n isHTML: boolean;\n onSave: (value: string) => void;\n}\n\n// Moving a keyed item reconnects descendant effects under Strict Effects.\n// `@uiw/react-codemirror` recreates its EditorView during that reconnect,\n// replacing the `.cm-editor` DOM and otherwise losing focus/selection. Keep\n// those user-facing values above the view lifecycle and restore them when the\n// replacement view is created (#359).\nconst JSXEditorField = ({ value, isHTML, onSave }: JSXEditorFieldProps) => {\n const selectionRef = useRef<EditorSelection | null>(null);\n const focusedRef = useRef(false);\n\n const handleUpdate = useCallback((update: ViewUpdate) => {\n selectionRef.current = update.state.selection;\n }, []);\n\n const handleCreateEditor = useCallback((view: EditorView) => {\n if (selectionRef.current) {\n view.dispatch({ selection: selectionRef.current });\n }\n\n if (focusedRef.current) {\n view.focus();\n }\n }, []);\n\n const handleFocus = useCallback(() => {\n focusedRef.current = true;\n }, []);\n\n const handleBlur = useCallback((event: FocusEvent<HTMLDivElement>) => {\n if (\n event.relatedTarget &&\n !event.currentTarget.contains(event.relatedTarget as Node)\n ) {\n focusedRef.current = false;\n }\n }, []);\n\n return (\n <div onFocusCapture={handleFocus} onBlurCapture={handleBlur}>\n <CoreEditor\n value={value}\n height=\"150px\"\n fragment={!isHTML}\n raw={isHTML}\n onSave={onSave}\n onUpdate={handleUpdate}\n onCreateEditor={handleCreateEditor}\n />\n </div>\n );\n};\n\nconst ColorPickerField = ({ value, onChange }: ColorPickerFieldProps) => {\n const [liveValue, setLiveValue] = useState(value);\n // Tracks `value` purely to detect an external change during render (see\n // below) — refs can't be read/written during render, so this has to be\n // state even though nothing here reads `prevValue` itself afterward.\n const [prevValue, setPrevValue] = useState(value);\n const lastCommittedRef = useRef(value);\n\n // The committed `value` can also change from outside (undo/redo, another\n // field touching the same binding) — stay in sync with it rather than\n // only ever tracking our own commits. Adjusted during render (React's\n // recommended \"reset state when a prop changes\" pattern) rather than in\n // an effect, so the mismatched frame never actually paints.\n if (value !== prevValue) {\n setPrevValue(value);\n setLiveValue(value);\n }\n\n // `lastCommittedRef` only needs to be current by the time `commit` next\n // runs (always from an event handler / debounce timer, never render), so\n // syncing it in an effect — instead of alongside the state adjustment\n // above — keeps the ref access out of the render phase entirely.\n useEffect(() => {\n lastCommittedRef.current = value;\n }, [value]);\n\n const commit = (next: string) => {\n if (next === lastCommittedRef.current) {\n return;\n }\n lastCommittedRef.current = next;\n onChange(next);\n };\n\n const debouncedCommit = useDebounce(() => commit(liveValue), {\n delay: COLOR_COMMIT_DELAY,\n autoInvoke: false,\n });\n\n return (\n <ColorPicker\n showText\n value={liveValue}\n onChange={next => {\n setLiveValue(next);\n debouncedCommit();\n }}\n onOpenChange={open => {\n // Flush immediately on close (picker dismissed / selection\n // finished) instead of waiting out the debounce window, so the\n // last color is never at risk of being dropped by an unmount\n // racing the pending timeout.\n if (!open) {\n commit(liveValue);\n }\n }}\n />\n );\n};\n\n// `mb-0` is deliberate: `dist/style.css` ships without a preflight, so a bare\n// `<p>` keeps the UA's `margin-block: 1em` in a consumer that doesn't reset\n// it. That bottom margin collapses out of the field's wrapper and overrides\n// `FieldGroup`'s `space-y-1`, shifting every field below as the error toggles\n// (#409). `mt-1` already declares the top; this declares the bottom.\nconst FieldError = ({ message }: { message: string | null }) =>\n message ? <p className=\"mt-1 mb-0 text-xs text-red-500\">{message}</p> : null;\n\nconst BuiltinField = ({ binding, onNodeChange }: FieldProps) => {\n // `value` is already structured (its real JS type); `rawValue` is the exact\n // source text used for the raw editors (Items/code/textarea) and as the\n // <input> defaultValue. See #238.\n const { id, value, rawValue, onChange } = binding;\n\n const [validationError, setValidationError] = useState<string | null>(null);\n\n // The text-like inputs below (url/number/textarea) commit on blur, so\n // they need local live state to hold what the user is typing. Left\n // uncontrolled (`defaultValue`), they ignored later changes to the canonical\n // value — an undo/redo or another field touching the same binding — because\n // `Field` reconciles rather than remounts (a stable key, now\n // `property`+`label` — see #318).\n // The stale text then got re-committed on blur, clobbering the undo. Track\n // the canonical `rawValue` with a render-phase reset, the same pattern\n // `ColorPickerField` uses above. See #284. (The date picker commits on\n // change, not blur, so it can bind the prop directly with no local state.)\n const [text, setText] = useState(rawValue);\n const [prevRawValue, setPrevRawValue] = useState(rawValue);\n\n if (rawValue !== prevRawValue) {\n setPrevRawValue(rawValue);\n setText(rawValue);\n }\n\n const kind = getFieldKind(binding);\n\n if (kind === 'readonly') {\n return (\n <div\n className=\"space-y-1 rounded border border-dashed border-amber-200 p-3\n text-xs text-amber-700\"\n >\n <div>This expression is preserved but is not editable here.</div>\n <code className=\"block overflow-x-auto text-amber-800\">{rawValue}</code>\n <div>Use the code editor to change it.</div>\n </div>\n );\n }\n\n // Guard against the canonical value with the same shape as the commit:\n // raw source text for string-in/string-out controls, structured values\n // for typed controls. Comparing across those shapes lets no-op edits\n // through when, for example, `'42'` and `42` describe the same field.\n const commitIfChanged = (next: unknown) => {\n const current = typeof next === 'string' ? rawValue : value;\n\n if (next !== current) {\n onChange(next);\n }\n };\n\n if (kind === 'items') {\n return (\n <Items\n value={rawValue}\n render={binding.render}\n onChange={onChange}\n onChildChange={onNodeChange}\n />\n );\n }\n\n if (kind === 'richtext') {\n return (\n <RichTextEditor\n value={rawValue}\n toolbar={RICHTEXT_TOOLBAR}\n onChange={commitIfChanged}\n />\n );\n }\n\n if (kind === 'html' || kind === 'jsx') {\n return (\n <JSXEditorField\n value={rawValue}\n isHTML={kind === 'html'}\n onSave={commitIfChanged}\n />\n );\n }\n\n if (kind === 'children') {\n return (\n <Children\n value={value as DataAttrNode[]}\n onChange={onChange}\n onNodeChange={onNodeChange}\n />\n );\n }\n\n if (kind === 'object') {\n const objectValue = value as Record<string, unknown>;\n\n return (\n <div className=\"space-y-2 rounded border border-gray-200 bg-gray-50 p-2\">\n {Object.entries(objectValue).map(([key, val]) => {\n const nested = resolveRenderEntry(binding.render, key);\n\n return (\n <div key={key} className=\"space-y-1\">\n <label className=\"block text-xs font-medium text-gray-600\">\n {nested.label}\n </label>\n <Field\n binding={{\n ...toBindingFields(nested),\n id,\n value: val,\n rawValue:\n typeof val === 'object' && val !== null\n ? JSON.stringify(val)\n : String(val),\n onChange: next => {\n onChange({ ...objectValue, [key]: next });\n },\n }}\n onNodeChange={onNodeChange}\n />\n </div>\n );\n })}\n </div>\n );\n }\n\n if (kind === 'boolean') {\n return (\n <Checkbox\n checked={value === true || value === 'true'}\n onChange={checked => {\n onChange(checked);\n }}\n />\n );\n }\n\n const stringValue = rawValue;\n\n if (kind === 'select') {\n return (\n <Select\n value={stringValue}\n options={binding.options ?? []}\n onChange={commitIfChanged}\n />\n );\n }\n\n if (kind === 'color') {\n return (\n <ColorPickerField\n value={normalizeToHex(stringValue)}\n onChange={commitIfChanged}\n />\n );\n }\n\n if (kind === 'date') {\n return (\n <div>\n <DatePicker\n value={parseDateValue(stringValue)}\n onChange={date => {\n const next = date ? formatDateValue(date) : '';\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n }\n\n if (kind === 'url') {\n return (\n <div>\n <Input\n type=\"url\"\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"https://example.com\"\n onBlur={e => {\n const next = e.target.value.trim();\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n }\n\n if (kind === 'number') {\n return (\n <div>\n <Input\n type=\"number\"\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"Enter a numeric value\"\n onBlur={e => {\n const raw = e.target.value.trim();\n // Commit a real number, not a numeric string — the AST boundary\n // and `validateBindingValue` (its `min`/`max`) both expect the\n // value as its declared type now. An unparseable entry falls\n // back to the raw text so a genuine mistake still round-trips\n // rather than becoming `NaN`.\n const next: unknown =\n raw !== '' && !Number.isNaN(Number(raw)) ? Number(raw) : raw;\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n }\n\n return (\n <div>\n <Input.TextArea\n value={text}\n onChange={e => setText(e.target.value)}\n placeholder=\"Enter a value\"\n onBlur={e => {\n const raw = e.target.value.trim();\n // Untyped field: infer the value's type from the text the user\n // entered (so `42` commits as a number), the way the old boundary\n // did — but here, in the presentation layer, not by re-guessing in\n // the AST pipeline. A declared string-family type keeps the text\n // verbatim, so `\"{x}\"` stays a string.\n const next: unknown = binding.type ? raw : parseValue(raw);\n const result = validateBindingValue(binding, next);\n\n if (!result.valid) {\n setValidationError(result.message ?? 'Invalid value.');\n return;\n }\n\n setValidationError(null);\n\n commitIfChanged(next);\n }}\n />\n <FieldError message={validationError} />\n </div>\n );\n};\n\n// The public control: a consumer's `renderField` gets the first say, with the\n// built-in control as its fallback. Every field goes through here — nested\n// object keys and item properties render `Field` too — so an override\n// reaches them without any per-editor wiring.\nconst Field = (props: FieldProps) => {\n const { renderField } = useDndEditOptions();\n const builtin = <BuiltinField {...props} />;\n\n if (!renderField) {\n return builtin;\n }\n\n const custom = renderField(props, builtin);\n\n return custom === undefined ? builtin : <>{custom}</>;\n};\n\nexport default Field;\n","import type { PanelBinding, PanelNodeChange } from '../dnd';\nimport Field from './field';\n\ninterface Props {\n bindings: PanelBinding[];\n onNodeChange?: PanelNodeChange;\n}\n\n// One bordered group per element `id` — the same visual grouping `Node`\n// (panel/node.tsx) renders, but for the top-level panel list, where\n// `bindings` are already resolved PanelBindings (see dnd.tsx's `bindings`\n// useMemo). `Node` stays a separate component: it still parses a raw\n// DataAttrNode itself, which `Items` needs for elements it discovers\n// dynamically inside an array item's `children` (not present in the\n// top-level `bindings` array at all) — see #237's items/children boundary.\nconst FieldGroup = ({ bindings, onNodeChange }: Props) => (\n <div className=\"space-y-2 rounded\">\n <div className=\"space-y-1\">\n {bindings.map(binding => (\n <div key={`${binding.property}-${binding.label}`} className=\"space-y-1\">\n <label className=\"block text-xs font-semibold text-gray-700\">\n {binding.label}\n <span className=\"ml-1 text-gray-400\">({binding.property})</span>\n </label>\n <Field binding={binding} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n </div>\n);\n\nexport default FieldGroup;\n","import { useContext, useEffect, useRef } from 'react';\n\nimport { Button, Typography } from '@jbpark/ui-kit';\nimport { ChevronDown, ChevronUp, Trash } from 'lucide-react';\n\nimport type { Section } from '~/types';\nimport { cn } from '~/utils/cn';\n\nimport type { PanelBinding, PanelNodeChange } from '../dnd';\nimport { DndInspectorContext } from '../inspector';\nimport FieldGroup from './field-group';\n\n// The built-in property panel. Reached publicly as `Live.Dnd.Panel`, which\n// is this in the container the desktop pane wants, driven from\n// `useDndPanel()` — every field here lines up with what that hook returns\n// (drop `onChange`, which this panel never needed), so the built-in panel and\n// a custom one run on the same data and the public surface can't drift into a\n// subset of it (#237).\n//\n// `onNodeChange` is the node-level escape hatch `Items`/`Children` use to\n// commit a *different* element's edit than any single\n// `PanelBinding.onChange` can express (see field.tsx's items/children\n// boundary note from step 1). Optional here only so this can be rendered\n// read-only for nested edits; leave it out with real data and nested\n// array/children edits silently don't commit (#308).\nexport interface PanelProps {\n item?: Section;\n onDelete?: (id: string) => void;\n // Reordering by dragging a section on the canvas doesn't work from\n // inside this panel on mobile — the canvas sits behind the Drawer this\n // panel renders in, so there's nothing visible to drag onto. These give\n // an explicit alternative that works regardless of layout.\n onMoveUp?: () => void;\n onMoveDown?: () => void;\n canMoveUp?: boolean;\n canMoveDown?: boolean;\n // `item`'s editable fields, already resolved to PanelBindings by Dnd —\n // the same data a custom panel receives, so this panel doesn't re-derive\n // it from DataAttrNode a second time (#237).\n bindings: PanelBinding[];\n onNodeChange?: PanelNodeChange;\n // The document doesn't parse, so these fields are from the last version\n // that did and edits are refused (#433).\n readOnly?: boolean;\n}\n\n// `bindings` is flat (one entry per bound property, across every editable\n// element in the section) — regroup by `id` to render the same \"one\n// bordered box per element\" layout as before. `bindings` is already\n// ordered element-by-element, property-by-property (dnd.tsx builds it by\n// flat-mapping the extracted fields), so a Map preserves both the element\n// order and each element's own property order with no extra sorting.\n//\n// Not memoized: Dnd rebinds `bindings` every render so its commit callbacks\n// can't go stale against the document (#336), which means a dependency on\n// it would miss every time. This is a single pass over an already-parsed\n// list, so the miss costs more than the walk.\nconst groupBindingsById = (bindings: PanelBinding[]): PanelBinding[][] => {\n const groups = new Map<string, PanelBinding[]>();\n\n for (const binding of bindings) {\n const group = groups.get(binding.id);\n\n if (group) {\n group.push(binding);\n } else {\n groups.set(binding.id, [binding]);\n }\n }\n\n return [...groups.values()];\n};\n\nconst Panel = ({\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp = false,\n canMoveDown = false,\n bindings,\n onNodeChange,\n readOnly = false,\n}: PanelProps) => {\n const groups = groupBindingsById(bindings);\n const rootRef = useRef<HTMLDivElement>(null);\n // Read without the throwing hook: this panel also renders outside\n // `Live.Dnd`, read-only, where there's no picker.\n const picked = useContext(DndInspectorContext)?.picked ?? null;\n const pickedId = picked?.id;\n\n // Brings the fields of an element picked in the preview into view and\n // marks them, whether they're a top-level group or nested in an Items or\n // Children editor (#432). A collapsed array item hides its nested fields,\n // so there's nothing to scroll to then.\n useEffect(() => {\n const root = rootRef.current;\n\n if (!root || !pickedId) {\n return;\n }\n\n const target = root.querySelector(\n `[data-node-id=\"${CSS.escape(pickedId)}\"]`,\n );\n\n if (!target) {\n return;\n }\n\n target.setAttribute('data-picked', '');\n\n // Fields above the target can still grow for a moment after it renders\n // (a rich-text editor mounting, for one), pushing it back out of view.\n // So keep it in view for the first few hundred milliseconds.\n const until = performance.now() + 600;\n let frame = 0;\n\n const keepInView = () => {\n const box = target.getBoundingClientRect();\n const view = root.getBoundingClientRect();\n\n if (box.top < view.top || box.bottom > view.bottom) {\n target.scrollIntoView?.({ block: 'nearest' });\n }\n\n if (performance.now() < until) {\n frame = requestAnimationFrame(keepInView);\n }\n };\n\n keepInView();\n\n return () => {\n cancelAnimationFrame(frame);\n target.removeAttribute('data-picked');\n };\n }, [pickedId, groups.length]);\n\n if (!item) {\n return (\n <Typography.Paragraph\n className={cn(\n 'p-4 text-sm text-gray-500',\n //\n )}\n >\n Please select a section.\n </Typography.Paragraph>\n );\n }\n\n return (\n <div\n ref={rootRef}\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 {readOnly && (\n <Typography.Text role=\"status\" className=\"block text-xs text-amber-700\">\n The document has a syntax error. These fields are from the last\n version that parsed, and can&apos;t be edited until it parses again.\n </Typography.Text>\n )}\n {!groups.length && (\n <Typography.Text className=\"text-xs text-gray-400\">\n No editable elements.\n </Typography.Text>\n )}\n {groups.map(group => (\n <div\n key={group[0]!.id}\n data-node-id={group[0]!.id}\n className=\"rounded data-[picked]:ring-2 data-[picked]:ring-blue-400\n data-[picked]:ring-offset-2\"\n >\n <FieldGroup bindings={group} onNodeChange={onNodeChange} />\n </div>\n ))}\n </div>\n );\n};\n\nexport default Panel;\n","import { Button, Drawer, Space, Splitter } from '@jbpark/ui-kit';\nimport { Crosshair, LayoutGrid } from 'lucide-react';\n\nimport { cn } from '~/utils/cn';\n\nimport { DefaultDraggableItem } from './draggable';\nimport { useDndInspector } from './inspector';\nimport { useDndRegions } from './layout-context';\nimport PropertyPanel from './panel';\n\n// The regions take their content from context, so `children` is never a\n// consumer's to pass — everything else about the wrapper div is (className\n// is tailwind-merged over the defaults, so overriding one of them wins\n// rather than fighting).\nexport type DndRegionProps = Omit<\n React.ComponentPropsWithRef<'div'>,\n 'children'\n>;\n\n// The built-in palette and panel without their region wrapper. Both exist\n// because `Layout` renders them twice on mobile — once in a pane, once in a\n// Drawer that's already the scroll container and shouldn't inherit the\n// pane's background.\nconst PaletteItems = ({ subject }: { subject: string }) => {\n const {\n palette: { items, onAdd },\n isMobile,\n } = useDndRegions(subject);\n\n return (\n <Space orientation=\"vertical\" align=\"start\">\n {items.map(item => (\n <DefaultDraggableItem\n key={item.id}\n item={item}\n onAdd={onAdd}\n tapToAdd={isMobile}\n />\n ))}\n </Space>\n );\n};\n\nconst PanelFields = ({ subject }: { subject: string }) => {\n const {\n panel: {\n item,\n onDelete,\n onMoveUp,\n onMoveDown,\n canMoveUp,\n canMoveDown,\n bindings,\n onNodeChange,\n readOnly,\n },\n } = useDndRegions(subject);\n\n return (\n <PropertyPanel\n item={item}\n onDelete={onDelete}\n onMoveUp={onMoveUp}\n onMoveDown={onMoveDown}\n canMoveUp={canMoveUp}\n canMoveDown={canMoveDown}\n bindings={bindings}\n onNodeChange={onNodeChange}\n readOnly={readOnly}\n />\n );\n};\n\n// The built-in palette, in the scroll container the desktop pane wants.\n// Replace it by putting your own component in `Layout`'s `palette` slot, or\n// anywhere in `Live.Dnd`'s children — `useDndPalette()` hands over the same\n// items and `onAdd` this reads.\nexport const Palette = ({ className, ...restProps }: DndRegionProps) => (\n <div\n className={cn(\n 'h-full overflow-y-auto bg-gray-50 p-4',\n className,\n //\n )}\n {...restProps}\n >\n <PaletteItems subject=\"<Live.Dnd.Palette>\" />\n </div>\n);\n\n// Owns the scroll container each section's iframe resolves by\n// `closest('[data-frame-container]')` to size itself against (see\n// frame/iframe.tsx), plus the containment/isolation styles that keep a\n// section's compiled CSS out of the editor chrome — hence a region rather\n// than a plain slot: a custom layout can move it, not lose it. Needs a\n// height-constrained parent, since it fills one (`h-full`). Render it\n// exactly once — the droppable and the sortable list inside use fixed ids,\n// and a second instance would duplicate both.\nexport const Canvas = ({ className, style, ...restProps }: DndRegionProps) => {\n const { canvas, documentError } = useDndRegions('<Live.Dnd.Canvas>');\n const inspector = useDndInspector();\n\n return (\n <div\n className={cn(\n 'relative h-full w-full overflow-y-auto',\n className,\n //\n )}\n data-frame-container\n style={{\n isolation: 'isolate',\n contain: 'layout style',\n transform: 'translateZ(0)',\n ...style,\n }}\n {...restProps}\n >\n {canvas}\n {/* The element picker's switch (#432). Pinned to the bottom-left of\n the scroll area, clear of the selected section's own buttons at its\n top-right and of the mobile palette button at the bottom-right. */}\n {!documentError && (\n <div className=\"pointer-events-none sticky bottom-0 z-70 h-0\">\n <div className=\"pointer-events-auto absolute bottom-3 left-3\">\n <Button\n icon={<Crosshair />}\n color=\"primary\"\n variant={inspector.active ? 'solid' : 'outlined'}\n aria-pressed={inspector.active}\n aria-label=\"Pick an element\"\n title={\n inspector.active\n ? 'Click an element to edit it. Esc to cancel.'\n : 'Pick an element'\n }\n onClick={inspector.toggle}\n />\n </div>\n </div>\n )}\n </div>\n );\n};\n\n// The built-in property panel. Same deal as `Palette`: replace it via\n// `Layout`'s `panel` slot or by placing your own component in `Live.Dnd`'s\n// children, driving it from `useDndPanel()`.\nexport const Panel = ({ className, ...restProps }: DndRegionProps) => (\n <div\n className={cn(\n 'h-full',\n className,\n //\n )}\n {...restProps}\n >\n <PanelFields subject=\"<Live.Dnd.Panel>\" />\n </div>\n);\n\nexport interface DndLayoutProps {\n // Replacements for the palette/panel regions, kept as slots so swapping\n // one out doesn't mean rebuilding the 3-pane Splitter and the mobile\n // Drawers around it. A slot is placed raw — it owns its own container,\n // unlike the built-in regions, which bring theirs. Drive it from\n // `useDndPalette()` / `useDndPanel()`.\n palette?: React.ReactNode;\n panel?: React.ReactNode;\n}\n\n// What `Live.Dnd` renders when given no children — the 3-pane desktop\n// Splitter, the stacked mobile canvas, and the mobile FAB/Drawers. Exported\n// so children can keep the built-in arrangement while wrapping it (a toolbar\n// above it, say) or while replacing just one region — and because\n// `@jbpark/ui-kit` is a dependency rather than a peer, so `Splitter` isn't\n// necessarily importable on the consumer's side.\nexport const Layout = ({ palette, panel }: DndLayoutProps) => {\n const { isMobile, selectedId, clearSelection, paletteOpen, setPaletteOpen } =\n useDndRegions('<Live.Dnd.Layout>');\n\n return (\n <>\n {isMobile ? (\n <Canvas />\n ) : (\n <Splitter withHandle orientation=\"horizontal\">\n <Splitter.Panel\n defaultSize=\"20%\"\n minSize=\"15%\"\n maxSize=\"35%\"\n collapsible\n >\n {palette ?? <Palette />}\n </Splitter.Panel>\n <Splitter.Panel defaultSize=\"60%\">\n <Canvas />\n </Splitter.Panel>\n <Splitter.Panel\n defaultSize=\"20%\"\n minSize=\"15%\"\n maxSize=\"35%\"\n collapsible\n >\n {panel ?? <Panel />}\n </Splitter.Panel>\n </Splitter>\n )}\n <Button\n type=\"primary\"\n shape=\"circle\"\n icon={<LayoutGrid />}\n aria-label=\"Components\"\n className=\"fixed right-4 bottom-4 z-20 md:hidden\"\n onClick={() => setPaletteOpen(true)}\n />\n {/* A slot goes in as-is; the built-ins go in without their region\n wrapper, since the Drawer is already the scroll container and the\n palette's gray background belongs to the desktop pane. */}\n <Drawer\n open={isMobile && paletteOpen}\n onClose={() => setPaletteOpen(false)}\n direction=\"bottom\"\n size=\"large\"\n title=\"Components\"\n >\n {palette ?? <PaletteItems subject=\"<Live.Dnd.Layout>\" />}\n </Drawer>\n <Drawer\n open={isMobile && Boolean(selectedId)}\n onClose={clearSelection}\n direction=\"bottom\"\n size=\"large\"\n title=\"Properties\"\n >\n {panel ?? <PanelFields subject=\"<Live.Dnd.Layout>\" />}\n </Drawer>\n </>\n );\n};\n\nexport default Layout;\n","import { createContext } from 'react';\n\nimport type { Section } from '~/types';\n\nexport interface DndSectionFallbackArgs {\n section: Section;\n // `compile`: the section's code failed to compile. `runtime`: it threw\n // while rendering. `forced`: `shouldForceSectionFallback` returned true, so\n // it was never compiled.\n reason: 'compile' | 'runtime' | 'forced';\n // The compiler or runtime message. `undefined` for `forced`.\n message?: string;\n}\n\n// Return a node to show in the section's place, or `undefined` for the\n// built-in error box.\nexport type DndRenderSectionFallback = (\n args: DndSectionFallbackArgs,\n) => React.ReactNode | undefined;\n\n// Only `SectionFallback` reads this, and it renders only for a failed\n// section, so a host passing a fresh inline function each render re-renders\n// those fallbacks alone, never a healthy memoized section (#97).\nexport const SectionFallbackContext = createContext<\n DndRenderSectionFallback | undefined\n>(undefined);\n","import { useContext } from 'react';\n\nimport ErrorBoundary from '~/components/error/boundary';\n\nimport {\n type DndRenderSectionFallback,\n type DndSectionFallbackArgs,\n SectionFallbackContext,\n} from './section-fallback-context';\n\ninterface ConsumerFallbackProps {\n render: DndRenderSectionFallback;\n args: DndSectionFallbackArgs;\n builtin: React.ReactElement;\n}\n\n// Its own component so the consumer's function runs inside the guard below:\n// a throw from the call itself, not only from what it returns, is caught.\nconst ConsumerFallback = ({ render, args, builtin }: ConsumerFallbackProps) => {\n const node = render(args);\n\n return node === undefined ? builtin : <>{node}</>;\n};\n\ninterface Props {\n args: DndSectionFallbackArgs;\n // What renders when no consumer fallback is set, when it returns\n // `undefined`, or when it throws.\n builtin: React.ReactElement;\n}\n\nconst SectionFallback = ({ args, builtin }: Props) => {\n const render = useContext(SectionFallbackContext);\n\n if (!render) {\n return builtin;\n }\n\n // A broken fallback must not break the canvas: revert to the built-in\n // error for this section only.\n return (\n <ErrorBoundary fallback={() => builtin}>\n <ConsumerFallback render={render} args={args} builtin={builtin} />\n </ErrorBoundary>\n );\n};\n\nexport default SectionFallback;\n","import { memo } from 'react';\n\nimport ErrorBoundary from '~/components/error/boundary';\nimport LiveError from '~/components/error/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { useCompiledModule } from '~/components/preview/use-compiled-module';\nimport { useDynamicTailwind } from '~/components/preview/use-dynamic-tailwind';\n\nimport SectionFallback from './section-fallback';\n\ninterface Props {\n preview: string;\n // The section's identity for `renderSectionFallback`, as primitives rather\n // than the `Section` object: sections are re-extracted on every document\n // change, so an object prop would defeat the memo below.\n sectionId?: string;\n sectionName?: string;\n sectionCode?: string;\n // Skip compiling and render the fallback (`shouldForceSectionFallback`).\n forceFallback?: boolean;\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 sectionId = '',\n sectionName = '',\n sectionCode = preview,\n forceFallback = false,\n headers,\n modules,\n frame,\n dynamicTailwind = false,\n provider,\n}: Props) => {\n // Empty code compiles to nothing, so a forced section never reaches the\n // compiler or runs any of its top-level code.\n const module = useCompiledModule(forceFallback ? '' : preview, modules);\n const section = { id: sectionId, name: sectionName, code: sectionCode };\n\n // In `shadow` mode there's no separate document to load a stylesheet into\n // — the shadow root only gets whatever CSS naturally inherits across the\n // boundary (see `frame/shadow.tsx`), not utility classes. So this section's\n // own Tailwind classes are compiled and portalled in as a `<style>` tag\n // alongside the rendered content, which crosses the shadow boundary fine\n // since it lives inside the same portal target.\n const { ref: wrapperRef, css: dynamicCSS } = useDynamicTailwind(\n preview,\n dynamicTailwind && !forceFallback,\n );\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\n };\n\n // Rendered in place of the frame rather than inside it: there is nothing to\n // portal into an iframe for code that never produced a component, and a\n // silent blank slot (the previous behaviour) gives the author no clue why\n // their section vanished. Mirrors preview/client.tsx's compile-error branch.\n if (forceFallback) {\n return (\n <SectionFallback\n args={{ section, reason: 'forced' }}\n builtin={\n <LiveError\n message=\"This section is not rendered in this editor.\"\n title=\"Section Unavailable\"\n />\n }\n />\n );\n }\n\n if (module?.error) {\n return (\n <SectionFallback\n args={{ section, reason: 'compile', message: module.error }}\n builtin={<LiveError message={module.error} title=\"Compile Error\" />}\n />\n );\n }\n\n const Component = module?.exports?.default;\n\n if (!Component) {\n return null;\n }\n\n return (\n <Frame {...frame} autoHeight>\n {container => (\n <div\n ref={wrapperRef}\n className=\"w-full overflow-x-hidden\"\n data-editor-mode\n >\n {/*\n Without this, a render error in any single canvas section\n propagated past Dnd and unmounted the whole editor — palette,\n canvas and panel — while the same error in <Preview> was caught\n and displayed (see #246). Kept inside the frame so the failure is\n reported in the slot the broken section occupies, and so a\n transient error while the author is mid-edit doesn't tear down and\n rebuild the iframe (script loading, style sync, resize observers)\n on every keystroke. `Error` is inline-styled, so it stays readable\n even in a frame that never received the host's CSS.\n\n resetKeys={[preview]} makes the fix itself the recovery signal: the\n next edit to this section produces a new preview string, which\n clears the caught error without needing a remount.\n\n No `Error.Guard` here, unlike client.tsx: it listens on `window`,\n not on its subtree, so one per section would mean N global\n listeners all tripping on any single error — every section would\n show a runtime error regardless of which one actually threw.\n\n Errors also stay local rather than going to ErrorContext, whose\n `error` is a single string shared by the whole tree: N sections\n reporting into it would overwrite each other with no way to tell\n which section failed.\n */}\n <ErrorBoundary\n resetKeys={[preview]}\n fallback={(message, reset) => (\n <SectionFallback\n args={{ section, reason: 'runtime', message }}\n builtin={\n <LiveError\n message={message}\n onReset={reset}\n title=\"Rendering Error\"\n />\n }\n />\n )}\n >\n {renderProvider(\n <>\n <Component\n headers={headers}\n container={container}\n //\n />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </>,\n )}\n </ErrorBoundary>\n </div>\n )}\n </Frame>\n );\n};\n\n// `frame` is configuration — strings, flags, string arrays, a style object —\n// and callers usually write it inline (`frame={{ mode: 'iframe' }}`), so it is\n// a new object on every render. Compared by identity, that alone re-rendered\n// every section on every edit (#348). Compare it by value instead: arrays by\n// their entries, objects (`style`) shallowly, anything else — a callback\n// included — by identity, so a changed `onLoaded` still re-renders.\nconst sameValue = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) {\n return true;\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((item, i) => Object.is(item, b[i]));\n }\n\n if (\n a &&\n b &&\n typeof a === 'object' &&\n typeof b === 'object' &&\n Object.getPrototypeOf(a) === Object.prototype &&\n Object.getPrototypeOf(b) === Object.prototype\n ) {\n const aKeys = Object.keys(a);\n\n return (\n aKeys.length === Object.keys(b).length &&\n aKeys.every(key =>\n Object.is(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key],\n ),\n )\n );\n }\n\n return false;\n};\n\nconst sameFrame = (a?: FrameProps, b?: FrameProps): boolean => {\n if (a === b) {\n return true;\n }\n\n if (!a || !b) {\n return false;\n }\n\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]);\n\n return [...keys].every(key =>\n sameValue(a[key as keyof FrameProps], b[key as keyof FrameProps]),\n );\n};\n\n// Every other prop is compared by identity, as `memo` does by default.\nconst arePropsEqual = (prev: Props, next: Props): boolean => {\n const keys = new Set([...Object.keys(prev), ...Object.keys(next)]);\n\n return [...keys].every(key =>\n key === 'frame'\n ? sameFrame(prev.frame, next.frame)\n : Object.is(prev[key as keyof Props], next[key as keyof Props]),\n );\n};\n\nexport default memo(Renderer, arePropsEqual);\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/cn';\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 // Registers the focusable wrapper, so the canvas can move focus to it.\n nodeRef?: (node: HTMLElement | null) => void;\n // Arrow keys and Home/End on a focused section, outside a drag (#435).\n onNavigate?: (to: SectionNavigation) => void;\n // Delete or Backspace on a focused section (#435).\n onDeleteKey?: () => void;\n // The element picker is on (#432): the section can't be dragged, and the\n // pointer over it reports positions instead of selecting it.\n inspecting?: boolean;\n onInspectMove?: (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => void;\n onInspectPick?: (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => void;\n onInspectLeave?: () => void;\n}\n\nexport type SectionNavigation = 'previous' | 'next' | 'first' | 'last';\n\nconst NAVIGATION_KEYS: Record<string, SectionNavigation> = {\n ArrowUp: 'previous',\n ArrowDown: 'next',\n Home: 'first',\n End: 'last',\n};\n\nconst Sortable = ({\n id,\n children,\n selected,\n onClick,\n onDelete: _onDelete,\n onCopy: _onCopy,\n nodeRef,\n onNavigate,\n onDeleteKey,\n inspecting = false,\n onInspectMove,\n onInspectPick,\n onInspectLeave,\n}: Props) => {\n const {\n attributes,\n listeners,\n setNodeRef,\n setActivatorNodeRef,\n transform,\n transition,\n isDragging,\n isOver,\n active,\n } = useSortable({ id, disabled: inspecting });\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n opacity: isDragging ? 0.5 : 1,\n cursor: inspecting ? 'crosshair' : 'grab',\n };\n\n const isNewItemOver = isOver && active?.data.current?.type === 'new-item';\n\n // The wrapper is a `role=\"button\"`, so Enter selects it the way a click\n // does. Only when the key lands on the wrapper itself, not on its copy and\n // delete buttons, and not while a drag is on (Enter drops one then) (#435).\n //\n // The same rule covers the other keys handled here. Keys pressed inside a\n // section's own inputs never count: those sit in the section's frame, or\n // retarget to its shadow host, so the event target isn't the wrapper.\n const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n listeners?.onKeyDown?.(e);\n\n if (e.target !== e.currentTarget || active || e.defaultPrevented) {\n return;\n }\n\n if (e.key === 'Enter') {\n e.preventDefault();\n onClick?.();\n\n return;\n }\n\n const to = NAVIGATION_KEYS[e.key];\n\n if (to && onNavigate) {\n // Otherwise the arrow keys also scroll the canvas.\n e.preventDefault();\n onNavigate(to);\n\n return;\n }\n\n if ((e.key === 'Delete' || e.key === 'Backspace') && onDeleteKey) {\n e.preventDefault();\n onDeleteKey();\n }\n };\n\n // The same element is the activator, so Space on the copy or delete button\n // presses that button instead of picking the section up.\n const setRefs = (node: HTMLDivElement | null) => {\n setNodeRef(node);\n setActivatorNodeRef(node);\n nodeRef?.(node);\n };\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={setRefs}\n style={style}\n {...attributes}\n {...listeners}\n onKeyDown={onKeyDown}\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 onPointerMove={\n inspecting\n ? e =>\n onInspectMove?.(\n e.currentTarget.parentElement!,\n e.currentTarget,\n e.clientX,\n e.clientY,\n )\n : undefined\n }\n onPointerLeave={inspecting ? onInspectLeave : undefined}\n onClick={\n inspecting\n ? e => {\n // The pick selects the section itself.\n e.stopPropagation();\n onInspectPick?.(\n e.currentTarget.parentElement!,\n e.currentTarget,\n e.clientX,\n e.clientY,\n );\n }\n : undefined\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/sections';\n\nimport { DefaultDraggableItem } from './draggable';\nimport Renderer from './renderer';\nimport Sortable from './sortable';\n\ninterface Props {\n sections: Section[];\n isForced?: (section: Section) => boolean;\n renderProps: {\n fullCode: string;\n containerId?: string;\n modules: Record<string, unknown>;\n frame?: FrameProps;\n dynamicTailwind?: boolean;\n };\n}\n\nconst Overlay = ({ sections, isForced, 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 containerId: renderProps.containerId,\n });\n\n return (\n <Sortable id={section.id} name={section.name}>\n <Renderer\n preview={preview}\n sectionId={section.id}\n sectionName={section.name}\n sectionCode={section.code}\n forceFallback={isForced?.(section) ?? false}\n modules={renderProps.modules}\n frame={renderProps.frame}\n dynamicTailwind={renderProps.dynamicTailwind}\n />\n </Sortable>\n );\n }\n\n return null;\n};\n\nexport default Overlay;\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { arrayMove } from '@dnd-kit/sortable';\n\nimport type { Section } from '~/types';\nimport {\n type DocumentProblem,\n type SectionOptions,\n fillSectionIds,\n inspectDocument,\n replaceIds,\n} from '~/utils/ast';\nimport {\n createSectionPreviewCache,\n extractSections,\n replaceSections,\n} from '~/utils/sections';\n\nimport { usePreview } from '../context/states';\n\nexport interface SectionDocument {\n sections: Section[];\n previews: string[];\n selectedId: string | null;\n selectedItem?: Section;\n selectedIndex: number;\n select: (id: string) => void;\n // Selects `id` outright, where `select` toggles. For keyboard navigation,\n // which lands on a section and must not deselect it (#435).\n selectOnly: (id: string) => void;\n clearSelection: () => void;\n add: (item: Pick<Section, 'name' | 'code'>, atIndex?: number) => void;\n remove: (id: string) => void;\n copy: (id: string) => void;\n move: (id: string | null, direction: 'up' | 'down') => void;\n reorder: (activeId: string, overId: string) => void;\n patch: (next: Partial<Section> & { id: string }) => void;\n // The section as the latest commit left it, when a commit has landed since\n // this render; `undefined` when nothing has, or when that commit removed\n // it. Lets a caller that edits inside a section build on a same-tick\n // commit instead of this render's `sections` (#450).\n getCommittedSection: (id: string) => Section | undefined;\n // Why `value` isn't a usable document, or `null` when it is (#433, #449).\n problem: DocumentProblem | null;\n // True while `value` doesn't parse and `sections`/`previews` are the last\n // ones that did. Every mutation is refused then, through `onBlockedEdit`:\n // the only ranges to edit are from a different source (#433).\n stale: boolean;\n}\n\nexport interface SectionDocumentOptions extends SectionOptions {\n // Called instead of committing when a mutation is refused because the\n // document doesn't parse. Pass a stable function.\n onBlockedEdit?: (problem: DocumentProblem) => void;\n}\n\n// The last document that parsed, per container id. A box held in `useState`\n// and written from the derivation below, like `createSectionPreviewCache`:\n// it only remembers a value, it never decides what renders on its own.\nconst createLastParsed = () => {\n let last: { containerId?: string; document: string } | null = null;\n\n return {\n read: (containerId?: string) =>\n last && last.containerId === containerId ? last.document : undefined,\n write: (containerId: string | undefined, document: string) => {\n last = { containerId, document };\n },\n };\n};\n\n// Owns the document side of the DnD canvas: deriving sections from the code\n// string, tracking which one is selected, and committing every mutation.\n//\n// Extracted from Dnd (#245), where the commit sequence\n// `replaceSections -> onChange -> setCode` was spelled out seven separate\n// times. Naming it once means no mutation can perform half of it, and it\n// puts the section logic somewhere reachable without rendering dnd-kit.\nexport const useSectionDocument = (\n value: string,\n onChange?: (value: string) => void,\n {\n containerId,\n sectionNameFallback,\n onBlockedEdit,\n }: SectionDocumentOptions = {},\n): SectionDocument => {\n const { setCode } = usePreview();\n const [selectedId, setSelectedId] = useState<string | null>(null);\n\n // Every read of a document into sections goes through here, so a section\n // without `data-name` is named the same way wherever it's read (#448).\n const readSections = useCallback(\n (code: string) =>\n extractSections(code, { containerId, sectionNameFallback }),\n [containerId, sectionNameFallback],\n );\n\n // Sections identify themselves by `data-id`; `getSections` falls back to a\n // positional id for documents predating that (see #245). Filling the gap\n // here makes the ids below real identities rather than positions, so a\n // held `selectedId` survives an insert, copy, move or delete.\n //\n // Deliberately not committed on its own — like dnd.tsx's existing use of\n // fillIds for field ids, the filled document only reaches\n // `onChange`/`setCode` when a real mutation commits, so merely opening a\n // document never rewrites the author's code.\n const document = useMemo(\n () => fillSectionIds(value, undefined, { containerId }),\n [containerId, value],\n );\n\n // What the canvas and panel show. Normally `document` itself. While the\n // source doesn't parse, which is usually the moment an author is typing in\n // the code editor, it's the last version that did, so the canvas and panel\n // keep their content instead of emptying on every keystroke (#433). A\n // missing container isn't covered: that isn't a passing state, and the\n // canvas says what's wrong instead (#449).\n //\n // Not a regex scan of the broken source: section ranges are where every\n // commit writes back, and a guessed range could put an edit in the wrong\n // place. The last parsed version is shown read-only instead.\n const [lastParsed] = useState(createLastParsed);\n const view = useMemo(() => {\n const inspection = inspectDocument(document, { containerId });\n\n if (inspection.ok) {\n lastParsed.write(containerId, document);\n\n return { document, problem: null, stale: false };\n }\n\n const { ok: _ok, ...problem } = inspection;\n const last =\n problem.reason === 'parse-error'\n ? lastParsed.read(containerId)\n : undefined;\n\n return { document: last ?? document, problem, stale: last !== undefined };\n }, [containerId, document, lastParsed]);\n\n const sections = useMemo(\n () => readSections(view.document),\n [readSections, view.document],\n );\n\n // One cache per hook instance (lazy `useState` initializer, never\n // replaced) — see createSectionPreviewCache (#131). It's stateful by\n // design (remembers the previous render's previews to reuse the ones that\n // didn't change), which a `useMemo`/`useRef` can't do without touching a\n // ref during render; a cache object stored via `useState` and only ever\n // mutated through its own method isn't subject to that restriction the way\n // `ref.current` is.\n const [previewCache] = useState(() => createSectionPreviewCache());\n const previews = useMemo(\n () => previewCache.compute(view.document, sections, { containerId }),\n [containerId, previewCache, sections, view.document],\n );\n\n const selectedIndex = sections.findIndex(s => s.id === selectedId);\n const selectedItem = selectedIndex >= 0 ? sections[selectedIndex] : undefined;\n\n // The document the last commit produced, tagged with the render document\n // it was built on. A commit's own `document`/`sections` are this render's\n // snapshot, and the host only hands the new value back on the next render,\n // so two commits in the same tick both started from the snapshot and the\n // second wrote the first one's section back as it was (#450). Every\n // mutation below reads through `latestDocument()` instead.\n //\n // Dropped after each render: from then on the render's own `value` is the\n // source of truth, including when the host chose not to accept a commit.\n // The `from` check covers the window between that render and this effect.\n const pendingRef = useRef<{ from: string; code: string } | null>(null);\n\n useEffect(() => {\n pendingRef.current = null;\n });\n\n const latestDocument = useCallback(() => {\n const pending = pendingRef.current;\n\n return pending?.from === document ? pending.code : document;\n }, [document]);\n\n // `extractSections` goes through the document parse cache, so re-reading\n // an unchanged document here costs a cache hit, not a parse.\n const latestSections = useCallback(\n () => readSections(latestDocument()),\n [latestDocument, readSections],\n );\n\n // The single place a set of sections becomes a new document. Takes only\n // `code` because that is genuinely all a commit reads — ids and names are\n // re-derived from the result, never carried across.\n //\n // Runs `fillSectionIds` on the way out so a section that arrived without\n // one still lands with an id: a palette template is a bare `<section>`\n // snippet with no `#app-container`, so it cannot be filled until after\n // it's spliced in. Returns the resulting sections so a caller that needs\n // to select what it just created can read the real id back rather than\n // inventing one.\n const commit = useCallback(\n (nextSections: { code: string }[]): Section[] => {\n const nextCode = fillSectionIds(\n replaceSections(\n latestDocument(),\n nextSections.map(s => s.code),\n { containerId },\n ),\n undefined,\n { containerId },\n );\n\n pendingRef.current = { from: document, code: nextCode };\n onChange?.(nextCode);\n setCode(nextCode);\n\n return readSections(nextCode);\n },\n [containerId, document, latestDocument, onChange, readSections, setCode],\n );\n\n const getCommittedSection = useCallback(\n (id: string) => {\n const pending = pendingRef.current;\n\n if (pending?.from !== document) {\n return undefined;\n }\n\n return readSections(pending.code).find(s => s.id === id);\n },\n [document, readSections],\n );\n\n // Every mutation starts here. Refusing up front, rather than letting the\n // edit reach `replaceSections`, matters: on a source that doesn't parse\n // that returns the source unchanged, so the edit used to \"commit\" nothing\n // and say nothing.\n const { problem, stale } = view;\n const refuse = useCallback(() => {\n if (!stale || !problem) {\n return false;\n }\n\n onBlockedEdit?.(problem);\n\n return true;\n }, [onBlockedEdit, problem, stale]);\n\n const select = useCallback((id: string) => {\n setSelectedId(prev => (prev === id ? null : id));\n }, []);\n\n const selectOnly = useCallback((id: string) => setSelectedId(id), []);\n\n const clearSelection = useCallback(() => setSelectedId(null), []);\n\n const add = useCallback(\n (item: Pick<Section, 'name' | 'code'>, atIndex?: number) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n const next = { code: item.code };\n\n commit(\n atIndex === undefined || atIndex < 0\n ? [...current, next]\n : [...current.slice(0, atIndex), next, ...current.slice(atIndex)],\n );\n },\n [commit, refuse, latestSections],\n );\n\n const remove = useCallback(\n (id: string) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n // Removes by position, not by predicate: `fillSectionIds` keeps ids\n // unique, but a filter would delete every match if that invariant ever\n // slipped — and this is the one destructive operation here, so it\n // shouldn't be the one relying on it.\n const index = current.findIndex(s => s.id === id);\n\n if (index < 0) {\n return;\n }\n\n // Only the deleted section loses the selection. The previous\n // implementation cleared it unconditionally, so deleting any section\n // closed the panel for whichever one was open.\n if (id === selectedId) {\n setSelectedId(null);\n }\n\n commit(current.filter((_, i) => i !== index));\n },\n [commit, refuse, latestSections, selectedId],\n );\n\n const copy = useCallback(\n (id: string) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n const index = current.findIndex(s => s.id === id);\n const source = current[index];\n\n if (!source) {\n return;\n }\n\n // replaceIds refreshes every data-id in the snippet, the section's own\n // included, so the copy carries a distinct identity into the document.\n const committed = commit([\n ...current.slice(0, index + 1),\n { code: replaceIds(source.code) },\n ...current.slice(index + 1),\n ]);\n\n // Read the new id back from the committed document. This used to\n // select a `uuidv4()` that was never written into the code and so\n // didn't exist after the next parse, leaving the panel empty right\n // after a copy (#245).\n setSelectedId(committed[index + 1]?.id ?? null);\n },\n [commit, refuse, latestSections],\n );\n\n const move = useCallback(\n (id: string | null, direction: 'up' | 'down') => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n const index = current.findIndex(s => s.id === id);\n const targetIndex = direction === 'up' ? index - 1 : index + 1;\n\n if (index < 0 || targetIndex < 0 || targetIndex >= current.length) {\n return;\n }\n\n // No `setSelectedId` compensation needed any more: the id travels with\n // the section's own markup, so the selection follows it across a move.\n commit(arrayMove(current, index, targetIndex));\n },\n [commit, refuse, latestSections],\n );\n\n const reorder = useCallback(\n (activeId: string, overId: string) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n const prevIndex = current.findIndex(s => s.id === activeId);\n const nextIndex = current.findIndex(s => s.id === overId);\n\n if (prevIndex < 0 || nextIndex < 0 || prevIndex === nextIndex) {\n return;\n }\n\n commit(arrayMove(current, prevIndex, nextIndex));\n },\n [commit, refuse, latestSections],\n );\n\n const patch = useCallback(\n (next: Partial<Section> & { id: string }) => {\n if (refuse()) {\n return;\n }\n\n const current = latestSections();\n\n commit(current.map(s => (s.id === next.id ? { ...s, ...next } : s)));\n },\n [commit, refuse, latestSections],\n );\n\n return {\n sections,\n previews,\n selectedId,\n selectedItem,\n selectedIndex,\n select,\n selectOnly,\n clearSelection,\n add,\n remove,\n copy,\n move,\n reorder,\n patch,\n getCommittedSection,\n problem,\n stale,\n };\n};\n","import {\n Children,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport {\n type Announcements,\n DndContext,\n type DragEndEvent,\n type DragOverEvent,\n DragOverlay,\n type DragStartEvent,\n KeyboardSensor,\n type Modifier,\n PointerSensor,\n type ScreenReaderInstructions,\n closestCenter,\n useSensor,\n useSensors,\n} from '@dnd-kit/core';\nimport { restrictToVerticalAxis } from '@dnd-kit/modifiers';\nimport {\n SortableContext,\n sortableKeyboardCoordinates,\n verticalListSortingStrategy,\n} from '@dnd-kit/sortable';\nimport { Space, Typography } from '@jbpark/ui-kit';\nimport { useResponsiveSize } from '@jbpark/use-hooks';\n\nimport { DATA_ATTR, DRAGGABLE_ITEMS } from '~/constants';\nimport type { Section } from '~/types';\nimport {\n type DataAttrNode,\n type DocumentProblem,\n extract,\n updateAll,\n} from '~/utils/ast';\nimport type { UpdateFailure } from '~/utils/ast';\nimport { fillIdsFrom } from '~/utils/ast/tree';\n\nimport { cn } from '../../utils/cn';\nimport { preloadScripts } from '../../utils/scripts';\nimport { usePreview } from '../context/states';\nimport { type FrameProps } from '../frame';\nimport { useStableModules } from '../preview/use-stable-modules';\nimport Droppable from './droppable';\nimport {\n type DndEditError,\n DndEditOptionsContext,\n type DndRenderField,\n toastEditError,\n} from './edit-options';\nimport {\n type DndInspector,\n DndInspectorContext,\n type DndNodePick,\n pickElement,\n viewportRect,\n} from './inspector';\nimport InspectorHighlight from './inspector-highlight';\nimport Layout from './layout';\nimport { DndRegionContext } from './layout-context';\nimport Overlay from './overlay';\nimport {\n type PanelBinding,\n type PanelNodeChange,\n type PanelNodesChange,\n resolvePanelBindings,\n withPanelCommit,\n} from './panel-binding';\nimport Renderer from './renderer';\nimport {\n type DndRenderSectionFallback,\n SectionFallbackContext,\n} from './section-fallback-context';\nimport Sortable, { type SectionNavigation } from './sortable';\nimport { useSectionDocument } from './use-section-document';\n\n// Turn a structured `update` failure into a toast that names the actual\n// fault. Before #270 every failure showed \"Failed to update this field /\n// Check the console for details\" — but nothing was logged, so the console\n// was empty. Most of these are a wrong `property`/`label` in the element's\n// `data-binding`, not the value the author just typed, so the message points\n// there. `description` is only set for paths that genuinely log (parse\n// errors), so \"check the console\" is never a dead end again.\nconst describeUpdateFailure = (\n failure: UpdateFailure | undefined,\n label: string,\n): { title: string; description?: string } => {\n switch (failure?.reason) {\n case 'attribute-not-found':\n return {\n title: `Failed to update \"${label}\"`,\n description: `This element has no \"${failure.property}\" attribute — check the property in its data-binding.`,\n };\n case 'binding-not-declared':\n return {\n title: `Failed to update \"${label}\"`,\n description: `No binding for ${\n failure.property\n ? `property \"${failure.property}\"`\n : `label \"${label}\"`\n } is declared on this element's data-binding.`,\n };\n case 'duplicate-binding':\n return {\n title: `Failed to update \"${label}\"`,\n description: `${failure.count} bindings share ${\n failure.property\n ? `property \"${failure.property}\"`\n : `label \"${label}\"`\n } on this element — remove the duplicate in its data-binding.`,\n };\n case 'reserved-property':\n return {\n title: `Cannot edit \"${label}\" in the panel`,\n description: `\"${failure.property}\" is managed by the editor, so a binding can't change it.`,\n };\n case 'required-property':\n return {\n title: `Cannot remove \"${label}\"`,\n description: `\"${failure.property}\" is marked required in its data-binding, so it can't be removed.`,\n };\n case 'no-binding':\n return {\n title: `Failed to update \"${label}\"`,\n description: 'This element has no data-binding declaration.',\n };\n case 'element-not-found':\n return {\n title: `Failed to update \"${label}\"`,\n description: 'The target element could not be found in this section.',\n };\n case 'unsupported-syntax':\n return {\n title: `Cannot edit \"${label}\" in the panel`,\n description: `The \"${failure.property}\" expression was preserved. Change it in the code editor instead.`,\n };\n case 'parse-error':\n return {\n title: `Failed to update \"${label}\"`,\n description:\n failure.error instanceof Error\n ? failure.error.message\n : 'Check the console for details.',\n };\n default:\n return { title: `Failed to update \"${label}\"` };\n }\n};\n\n// Enter is left out of `start` so it can select the focused section (#435).\nconst KEYBOARD_CODES = {\n start: ['Space'],\n cancel: ['Escape'],\n end: ['Space', 'Enter'],\n};\n\nconst SCREEN_READER_INSTRUCTIONS: ScreenReaderInstructions = {\n draggable:\n 'On a palette item, press Enter to add it to the canvas. On a canvas section, press Enter to select it, the up and down arrow keys to go to the previous or next section, and Delete to remove it. Press Space to pick a section up, the arrow keys to move it, and Space or Enter to drop it. Press Escape to cancel.',\n};\n\n// Section wrappers by id, with one stable ref callback per id so React\n// doesn't detach and reattach every wrapper on each render. Held in a\n// `useState` box and only read from handlers and effects.\nconst createNodeRegistry = () => {\n const nodes = new Map<string, HTMLElement>();\n const callbacks = new Map<string, (node: HTMLElement | null) => void>();\n\n return {\n get: (id: string) => nodes.get(id),\n register: (id: string) => {\n let callback = callbacks.get(id);\n\n if (!callback) {\n callback = node => {\n if (node) {\n nodes.set(id, node);\n } else {\n // A wrapper only detaches when its section leaves the canvas\n // (sections are keyed by id), so its callback can go too.\n nodes.delete(id);\n callbacks.delete(id);\n }\n };\n callbacks.set(id, callback);\n }\n\n return callback;\n },\n };\n};\n\n// An edit refused because the document doesn't parse (#433).\nconst blockedEditError = (error: unknown): DndEditError => ({\n type: 'parse',\n target: 'document',\n reason: 'parse-error',\n error,\n title: 'The document has a syntax error',\n description:\n 'The canvas shows the last version that parsed. Fix the error in the code, then edit here again.',\n});\n\n// What `useDndPalette()` returns. Deliberately just data: the drag wiring is\n// a component (`Live.Dnd.DraggableItem`) and the breakpoint belongs to\n// `useDndLayout()`, so a custom palette takes each from where it lives\n// rather than having all three funnelled through one object.\nexport interface DndPalette {\n items: Section[];\n // Appends the item to the canvas. Closes the mobile palette Drawer too,\n // which is a no-op wherever it isn't open.\n onAdd: (item: Section) => void;\n}\n\n// `PanelNodeChange`/`PanelBinding` live in `./panel-binding` alongside the\n// DataAttrNode -> PanelBinding conversion they describe, and are re-exported\n// here so `Live.Dnd`'s public types keep their original import path (#340).\nexport type {\n PanelBinding,\n PanelNodeChange,\n PanelNodesChange,\n} from './panel-binding';\n\n// What `useDndPanel()` returns — everything the built-in property panel runs\n// on, so a custom panel starts from the same place rather than re-deriving\n// any of it.\nexport interface DndPanel {\n item?: Section;\n onChange: (next: Partial<Section>) => void;\n onDelete: (id: string) => void;\n // Alternative to dragging a section to reorder it — needed since the\n // canvas sits behind the mobile Drawer the panel renders in, so\n // there's nothing visible to drag onto there.\n onMoveUp: () => void;\n onMoveDown: () => void;\n canMoveUp: boolean;\n canMoveDown: boolean;\n // `item`'s editable data-binding fields, already flattened to one entry\n // per bound property (across every non-<section> descendant carrying a\n // `data-binding` attribute). Each entry carries the binding's `type` and\n // current `value` plus an `onChange` wired straight into the same\n // AST-update pipeline the built-in panel uses — including the error Toast\n // on a bad edit. Switch on `type` to render your own control (an\n // `<input>`, `<textarea>`, `<select>`, ...) instead of the built-in one.\n bindings: PanelBinding[];\n // Node-level commit for elements that aren't in `bindings` — the nested\n // data-bound JSX held inside an `items`/`children` value, which the\n // built-in Items/Children editors discover by re-extracting that value's\n // own JSX. Those `data-id`s never reach `bindings` (the top-level\n // `extract()` doesn't walk into an attribute expression), and no single\n // `PanelBinding.onChange` can address them since each one closes over a\n // fixed `id` — hence this `(id, label, property, value)` channel. Hand it\n // to `Live.Dnd.Field` along with the binding, otherwise nested\n // array/children edits inside it silently don't commit (#308).\n onNodeChange: PanelNodeChange;\n // Several node-level edits as one commit: applied in array order, all or\n // none. Reach for it when one interaction writes more than one binding (an\n // image picker setting `src` and `alt`, say), so the host sees a single\n // `onChange` and a failure can't leave half of it behind (#425).\n onNodesChange: PanelNodesChange;\n // True while the document doesn't parse: `item` and `bindings` are from the\n // last version that did, and every commit is refused (and reported through\n // `onEditError`) until the source parses again. Disable your controls, or\n // say why edits aren't landing (#433).\n readOnly: boolean;\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 // Replaces the built-in control for any field, wherever it renders — the\n // built-in panel, `Live.Dnd.Field` in a custom panel, nested object keys\n // and array item properties. Return `undefined` to keep the built-in one.\n // See `DndRenderField`.\n renderField?: DndRenderField;\n // Receives every edit the editor could not apply. When set, the built-in\n // error toast is not shown; the payload carries the same title and\n // description so a host can show them its own way.\n onEditError?: (error: DndEditError) => void;\n // Renders in place of a canvas section that failed to compile, threw while\n // rendering, or was skipped by `shouldForceSectionFallback`. Return\n // `undefined` for the built-in error box. See `DndSectionFallbackArgs`.\n renderSectionFallback?: DndRenderSectionFallback;\n // Checked for every section before it is compiled. Return `true` to skip\n // compiling it (so none of its top-level code runs) and render the\n // fallback with reason `forced`.\n shouldForceSectionFallback?: (section: Section) => boolean;\n // Asked before a section is deleted, from the canvas, the panel, or a\n // custom panel's `onDelete`. Return `false` (or a promise of it) to keep the\n // section; use it to show your own confirmation. Deleting is immediate and\n // has no undo inside `Live.Dnd`, so this is the host's chance to ask (#435).\n onBeforeDelete?: (section: Section) => boolean | Promise<boolean>;\n // Names a section whose `<section>` has no `data-name`, from its 0-based\n // position on the canvas. The name shows on the canvas, in the panel and\n // in `renderSectionFallback`'s `section`. Defaults to \"Section 1\",\n // \"Section 2\", ...\n sectionNameFallback?: (index: number) => string;\n // The `id` of the element whose `<section>` children are the document's\n // sections. Defaults to `app-container`. A document without that element\n // has no sections, and `onEditError` (or the toast) says so. Start a new\n // document with `createDocument({ containerId })` from\n // `@jbpark/live-editor/utils`. Without a `value`, `Live.Dnd` starts from\n // the default template, which uses `app-container`, so pass a `value`\n // when you change this.\n containerId?: string;\n // Called when an element is picked in the canvas preview with the element\n // picker (`useDndInspector()`, or the canvas's picker button). Receives the\n // element's `data-id`, the key its fields carry in `useDndPanel()`, and its\n // section's id. The section is selected as well (#432).\n onNodePick?: (pick: DndNodePick) => void;\n // The single customization slot. Omit it for the built-in editor. Supply\n // it and you own the arrangement: compose `Live.Dnd.Palette` /\n // `Live.Dnd.Canvas` / `Live.Dnd.Panel` (each the built-in region, in the\n // container it needs) and your own components in any structure you like.\n // The drag context wraps all of it, so drag-and-drop and field editing\n // keep working wherever a region lands. Your components read the same data\n // the built-ins do through `useDndPalette()` / `useDndPanel()` /\n // `useDndLayout()`.\n //\n // Note this replaces the mobile chrome too — the FAB and both Drawers live\n // in `Live.Dnd.Layout`, which is what runs when children are omitted.\n // Render it yourself (`<Live.Dnd.Layout panel={<MyPanel />} />`) to keep\n // the built-in arrangement while swapping one region. Render `Canvas` at\n // most once either way.\n children?: React.ReactNode;\n}\n\nconst conditionalModifiers: Modifier = args => {\n const { active } = args;\n\n if (active?.data.current?.type === 'new-item') {\n return args.transform;\n }\n\n return restrictToVerticalAxis(args);\n};\n\n// Shared, not `= {}` in the parameter list: a fresh object on every render\n// is a new `modules` prop for every section, which defeats `Renderer`'s memo\n// (#97) and re-runs `compile()` for every section on every edit. Past the\n// compilation cache's limit that meant recompiling most sections with Babel\n// per keystroke-commit — 1.4 s per edit at 90 sections (#348).\nconst NO_MODULES: Record<string, unknown> = {};\n\nconst Dnd = ({\n value: _value,\n props,\n modules: _modules = NO_MODULES,\n onChange: _onChange,\n className,\n items = [],\n frame,\n dynamicTailwind = false,\n provider,\n renderField,\n onEditError,\n renderSectionFallback,\n shouldForceSectionFallback,\n onBeforeDelete,\n sectionNameFallback,\n containerId,\n onNodePick,\n children,\n ...restProps\n}: Props) => {\n const modules = useStableModules(_modules);\n const [mobilePaletteOpen, setMobilePaletteOpen] = useState(false);\n\n const { breakpoint } = useResponsiveSize();\n const isMobile = breakpoint.current === 'xs' || breakpoint.current === 'sm';\n\n // Read-only here — `useSectionDocument` below owns `setCode` (the commit\n // side). `code` is still needed locally: it feeds `value`'s fallback\n // chain just below, and `value` itself is read again further down for\n // the drag overlay's `fullCode` — not something `useSectionDocument`\n // exposes back out.\n const { code } = usePreview();\n\n // A throwing predicate is treated as \"not forced\" rather than taking the\n // whole editor down with it.\n const isForced = (section: Section) => {\n try {\n return shouldForceSectionFallback?.(section) === true;\n } catch (error) {\n console.error('shouldForceSectionFallback threw', error);\n\n return false;\n }\n };\n\n // Space picks a focused section up, the arrow keys move it, and Space or\n // Enter drops it (Escape cancels). Enter doesn't pick up, unlike dnd-kit's\n // default: a focused section is a `role=\"button\"`, and Enter selects it\n // like a click does (see Sortable). Before, sections could be reached with\n // Tab but neither selected nor moved from the keyboard (#435).\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 10,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n keyboardCodes: KEYBOARD_CODES,\n }),\n );\n\n // dnd-kit announces drags by id, which here is a generated `data-id`.\n const nameOf = (id: string | number, data?: { current?: unknown }) => {\n const current = data?.current as { item?: Section } | undefined;\n\n return (\n current?.item?.name ??\n sections.find(section => section.id === id)?.name ??\n 'section'\n );\n };\n\n const positionOf = (id: string | number) =>\n sections.findIndex(section => section.id === id) + 1;\n\n const announcements: Announcements = {\n onDragStart: ({ active }) => `Picked up ${nameOf(active.id, active.data)}.`,\n onDragOver: ({ active, over }) =>\n over && positionOf(over.id) > 0\n ? `${nameOf(active.id, active.data)} moved to position ${positionOf(over.id)} of ${sections.length}.`\n : `${nameOf(active.id, active.data)} is no longer over a position.`,\n onDragEnd: ({ active, over }) =>\n over && positionOf(over.id) > 0\n ? `${nameOf(active.id, active.data)} dropped at position ${positionOf(over.id)} of ${sections.length}.`\n : `${nameOf(active.id, active.data)} dropped.`,\n onDragCancel: ({ active }) =>\n `Moving ${nameOf(active.id, active.data)} was cancelled.`,\n };\n\n // Uncontrolled usage (`<Live.Dnd />` with no `value`) used to read\n // nothing but DEFAULT_TEMPLATE forever: every edit committed through\n // useSectionDocument writes into PreviewContext, but this component\n // never read `code` back — so the section a reader just dragged in\n // vanished on the very next render. `Client` (preview/client.tsx)\n // resolves the same dual-source situation by distinguishing an omitted\n // prop from an explicitly empty string; mirror that contract here. The\n // ContextProvider supplies DEFAULT_TEMPLATE for a fresh document.\n const value = _value === undefined ? code : _value;\n\n const reportError = onEditError ?? toastEditError;\n\n // Read through a ref so the effects below fire once per failure, not again\n // on every render a host passes a fresh inline `onEditError`.\n const reportErrorRef = useRef(reportError);\n\n useEffect(() => {\n reportErrorRef.current = reportError;\n });\n\n // Reported only when an author tries to edit, not whenever the source\n // stops parsing: that happens on most keystrokes in the code editor, and\n // the canvas already says it's showing the last valid version (#433).\n const onBlockedEdit = useCallback((problem: DocumentProblem) => {\n if (problem.reason === 'parse-error') {\n reportErrorRef.current(blockedEditError(problem.error));\n }\n }, []);\n\n const {\n sections,\n previews,\n selectedId,\n selectedItem,\n selectedIndex,\n select,\n selectOnly,\n clearSelection,\n add: addItem,\n remove,\n copy: onCopy,\n move: moveSection,\n reorder,\n patch,\n getCommittedSection,\n problem,\n stale,\n } = useSectionDocument(value, _onChange, {\n containerId,\n sectionNameFallback,\n onBlockedEdit,\n });\n\n // The container id the document is missing, or `null`.\n const missingContainer =\n problem?.reason === 'container-not-found' ? problem.containerId : null;\n\n const onDragStart = (_: DragStartEvent) => {};\n\n const onDragOver = (_e: DragOverEvent) => {};\n\n const onDragEnd = (event: DragEndEvent) => {\n const { active, over } = event;\n\n if (!over) {\n return;\n }\n\n if (active.data.current?.type === 'new-item') {\n const item = active.data.current.item as Section;\n const atBottom =\n over.id === 'sortable-area' || over.id === 'sortable-area-bottom';\n\n addItem(\n item,\n atBottom ? undefined : sections.findIndex(s => s.id === over.id),\n );\n return;\n }\n\n if (active.id !== over.id && sections.some(s => s.id === active.id)) {\n reorder(String(active.id), String(over.id));\n }\n };\n\n const onSelect = (id: string) => select(id);\n\n // The element picker (#432). `picked` follows the selection: picking\n // selects the element's section, and selecting another section clears it.\n const [inspecting, setInspecting] = useState(false);\n const [picked, setPicked] = useState<DndNodePick | null>(null);\n const [highlight, setHighlight] = useState<DOMRect | null>(null);\n\n if (picked && picked.sectionId !== selectedId) {\n setPicked(null);\n }\n\n const stopInspecting = useCallback(() => {\n setInspecting(false);\n setHighlight(null);\n }, []);\n\n useEffect(() => {\n if (!inspecting) {\n return;\n }\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n stopInspecting();\n }\n };\n\n window.addEventListener('keydown', onKeyDown);\n\n return () => window.removeEventListener('keydown', onKeyDown);\n }, [inspecting, stopInspecting]);\n\n const inspector: DndInspector = {\n active: inspecting,\n activate: () => setInspecting(true),\n deactivate: stopInspecting,\n toggle: () => (inspecting ? stopInspecting() : setInspecting(true)),\n picked,\n };\n\n const onInspectMove = (\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => {\n const element = pickElement(section, overlay, x, y);\n\n setHighlight(element ? viewportRect(element) : null);\n };\n\n const onInspectPick = (\n sectionId: string,\n section: HTMLElement,\n overlay: Element,\n x: number,\n y: number,\n ) => {\n const id = pickElement(section, overlay, x, y)?.getAttribute(DATA_ATTR.ID);\n\n if (!id) {\n return;\n }\n\n const pick = { id, sectionId };\n\n selectOnly(sectionId);\n setPicked(pick);\n stopInspecting();\n onNodePick?.(pick);\n };\n\n // Read through a ref after an async `onBeforeDelete`: while a confirmation\n // is open the document can change, and the `remove` from the render that\n // asked would commit against the document as it was then.\n const removeRef = useRef(remove);\n\n useEffect(() => {\n removeRef.current = remove;\n });\n\n // Asks `onBeforeDelete` first when there is one, then removes the section.\n // `onDeleted` runs only once it's actually gone.\n const requestDelete = (id: string, onDeleted?: () => void) => {\n const section = sections.find(candidate => candidate.id === id);\n\n if (!onBeforeDelete || !section) {\n remove(id);\n onDeleted?.();\n\n return;\n }\n\n const decide = (allowed: boolean) => {\n if (allowed) {\n removeRef.current(id);\n onDeleted?.();\n }\n };\n\n try {\n const answer = onBeforeDelete(section);\n\n if (typeof answer === 'boolean') {\n decide(answer);\n\n return;\n }\n\n answer.then(decide, error => {\n console.error('onBeforeDelete rejected; the section was kept', error);\n });\n } catch (error) {\n console.error('onBeforeDelete threw; the section was kept', error);\n }\n };\n\n const onDelete = (id: string) => requestDelete(id);\n\n // The focusable wrapper of each section, so the keyboard can move focus\n // between them (#435).\n const [sectionNodes] = useState(createNodeRegistry);\n\n // `focus()` also scrolls the section into view.\n const focusSection = (id: string) => sectionNodes.get(id)?.focus();\n\n // Arrow keys and Home/End move focus to another section and select it, so\n // the panel follows. Outside a drag only: during one, dnd-kit owns them.\n const onNavigate = (fromId: string, to: SectionNavigation) => {\n const from = sections.findIndex(section => section.id === fromId);\n const index =\n to === 'first'\n ? 0\n : to === 'last'\n ? sections.length - 1\n : from + (to === 'next' ? 1 : -1);\n const target = sections[index];\n\n if (from < 0 || !target || target.id === fromId) {\n return;\n }\n\n selectOnly(target.id);\n focusSection(target.id);\n };\n\n // Delete on a focused section. Focus goes to the section that takes its\n // place (or the one before it, for the last), so it isn't dropped on the\n // page body.\n const onDeleteKey = (id: string) => {\n const index = sections.findIndex(section => section.id === id);\n const neighbor = sections[index + 1] ?? sections[index - 1];\n\n requestDelete(id, () => {\n if (neighbor) {\n focusSection(neighbor.id);\n }\n });\n };\n\n // Keeps the selected section on screen when it moves out of view without\n // the keyboard taking it there: a move from the panel, or a copy that lands\n // below the fold. After the next frame, once the new order is laid out.\n useEffect(() => {\n if (selectedId === null) {\n return;\n }\n\n const frame = requestAnimationFrame(() => {\n sectionNodes.get(selectedId)?.scrollIntoView?.({ block: 'nearest' });\n });\n\n return () => cancelAnimationFrame(frame);\n }, [sectionNodes, selectedId, selectedIndex]);\n\n const onChange = (next: Partial<Section>) => {\n if (!next.id) {\n return;\n }\n\n patch(next as Partial<Section> & { id: string });\n };\n\n // Reads only the extracted `code` local, not `selectedItem`, so the\n // compiler can verify this dependency array actually matches what the\n // body reads — matches Panel's own former version of this same logic,\n // now shared here so both the built-in Panel and a custom one built on\n // `useDndPanel()` get the same extraction/update pipeline instead of each\n // needing it.\n const selectedCode = selectedItem?.code;\n const selectedSectionId = selectedItem?.id;\n const { fields, updatedCode, parseError } = useMemo(() => {\n if (!selectedCode) {\n return {\n fields: [] as DataAttrNode[],\n updatedCode: '',\n parseError: null,\n };\n }\n\n try {\n // The same ids the canvas preview fills this section with, so an\n // element's `data-id` there matches its fields here (#432).\n const updated = fillIdsFrom(selectedCode, selectedSectionId ?? '');\n // Every element, the section's own root included: a `<section>` with a\n // `data-binding` is editable like any other element, and one without\n // resolves to no bindings below. It used to be dropped here, so a\n // binding written on the section itself was silently ignored (#429).\n const allNodes = extract(updated);\n\n return {\n fields: allNodes,\n updatedCode: updated !== selectedCode ? updated : selectedCode,\n parseError: null,\n };\n } catch (e) {\n console.warn('⚠️ Parsing error', e);\n return {\n fields: [] as DataAttrNode[],\n updatedCode: '',\n parseError: { error: e },\n };\n }\n }, [selectedCode, selectedSectionId]);\n\n // Keyed on the missing id alone, so it fires when a document reaches this\n // state and not again for every edit that leaves it there.\n useEffect(() => {\n if (missingContainer !== null) {\n reportErrorRef.current({\n type: 'parse',\n target: 'document',\n reason: 'container-not-found',\n containerId: missingContainer,\n title: `No #${missingContainer} element in the document`,\n description: `Sections are the <section> elements inside the element with id=\"${missingContainer}\". Start from createDocument(), or set containerId to match your document.`,\n });\n }\n }, [missingContainer]);\n\n useEffect(() => {\n if (parseError) {\n reportErrorRef.current({\n type: 'parse',\n target: 'section',\n error: parseError.error,\n title: 'Failed to parse this section',\n description: 'Check the console for details.',\n });\n }\n }, [parseError]);\n\n // The one commit path for panel edits, whether one node or several. A single\n // `PanelNodeChange` is a batch of one, so the guards and the base document\n // below can't drift between the two (#425).\n const commitChanges = (changes: Parameters<PanelNodeChange>[0][]) => {\n if (changes.length === 0) {\n return;\n }\n\n // The fields show the last version that parsed while the source doesn't,\n // and their ids point into that version, not the current source (#433).\n if (stale && problem?.reason === 'parse-error') {\n reportError(blockedEditError(problem.error));\n return;\n }\n\n // Builds on an earlier commit from this same tick when that commit\n // changed this section: `updatedCode` is this render's snapshot, so a\n // second commit made from it would write the first one's edit back out\n // (#450). A section the earlier commit left alone (a sibling was added,\n // say) still reads as `selectedCode`, whose empty `data-id`s haven't been\n // filled yet — `updatedCode` holds the ids the bindings point at.\n const committed =\n selectedItem && getCommittedSection(selectedItem.id)?.code;\n const base =\n committed && committed !== selectedCode ? committed : updatedCode;\n const result = updateAll(\n base,\n changes.map(({ id, label, property, value: changeValue }) => ({\n dataId: id,\n label,\n property,\n value: changeValue,\n })),\n );\n\n if (!result.success) {\n const { id, label, property } = changes[result.index]!;\n\n reportError({\n type: 'update',\n id,\n label,\n property,\n failure: result.failure,\n ...describeUpdateFailure(result.failure, label),\n });\n return;\n }\n\n if (selectedItem) {\n onChange({ ...selectedItem, code: result.code });\n }\n };\n\n const onFieldChange: PanelNodeChange = change => commitChanges([change]);\n\n // Flattens the extracted `fields` (one DataAttrNode per element) down to\n // one descriptor per bound property — the same walk the built-in\n // FieldEditor/Node does internally (data-id + parsed data-binding +\n // current value). Everything here is derived from `fields` alone, so the\n // memo key is honest and the parse/read work still happens once per\n // parsed section.\n //\n // Deliberately no `onChange`: a callback belongs to the render that made\n // it, not to the parse. Keeping the two in one memo is what caused #336 —\n // editing another section leaves `selectedCode` (and therefore `fields`)\n // identical, so the memo was reused and handed back callbacks still bound\n // to the previous document, whose commit wrote the sibling's old source\n // back over the newer one.\n const bindingFields = useMemo(\n () => fields.flatMap(node => resolvePanelBindings(node)?.bindings ?? []),\n [fields],\n );\n\n // Bound fresh each render on top of the memo above — the same split\n // `useDndItems` uses for its `items`. This is a plain walk of an\n // already-parsed result with no Babel in it, and it's what guarantees a\n // commit reads the current `updatedCode`/`selectedItem`/`onChange`.\n //\n // The identity churn the previous memo was guarding against was never\n // real: the `DndRegionContext` value and the `panel` object holding this\n // array are both fresh object literals every render, so every\n // `useDndPanel()` consumer already re-rendered regardless.\n const bindings: PanelBinding[] = withPanelCommit(\n bindingFields,\n onFieldChange,\n );\n\n useEffect(() => {\n if (frame?.scripts?.length) {\n preloadScripts(frame.scripts);\n }\n }, [frame?.scripts]);\n\n // Data, not nodes: the built-in palette and panel read these back through\n // `useDndPalette()`/`useDndPanel()` exactly as a custom one does, so\n // there's a single path and no way for the public surface to drift into a\n // subset of what the built-ins use — the point of #237.\n const palette: DndPalette = {\n items: items?.length ? items : DRAGGABLE_ITEMS,\n onAdd: (item: Section) => {\n addItem(item);\n setMobilePaletteOpen(false);\n },\n };\n\n const panel: DndPanel = {\n item: selectedItem,\n onChange,\n onDelete,\n onMoveUp: () => moveSection(selectedId, 'up'),\n onMoveDown: () => moveSection(selectedId, 'down'),\n canMoveUp: selectedIndex > 0,\n canMoveDown: selectedIndex >= 0 && selectedIndex < sections.length - 1,\n bindings,\n onNodeChange: onFieldChange,\n onNodesChange: commitChanges,\n readOnly: stale,\n };\n\n // Content only — the frame container that wraps this (`data-frame-container`\n // plus the containment styles) belongs to `Live.Dnd.Canvas`, so a custom\n // layout can't accidentally drop it while still placing the canvas.\n const canvas = (\n <>\n {stale && (\n <div\n role=\"status\"\n className={cn(\n 'sticky top-0 z-70',\n 'border-b border-amber-200 bg-amber-50 px-3 py-2',\n 'text-sm text-amber-900',\n )}\n >\n Showing the last version that parsed. Fix the syntax error in the code\n to edit here again.\n </div>\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 {problem?.reason === 'parse-error' ? (\n <Space orientation=\"vertical\" align=\"center\">\n <Typography.Paragraph>\n The document has a syntax error\n </Typography.Paragraph>\n <Typography.Text>\n Fix it in the code to see its sections\n </Typography.Text>\n </Space>\n ) : missingContainer !== null ? (\n <Space orientation=\"vertical\" align=\"center\">\n <Typography.Paragraph>\n No #{missingContainer} element in the document\n </Typography.Paragraph>\n <Typography.Text>\n Sections go inside the element with id=&quot;\n {missingContainer}&quot;\n </Typography.Text>\n </Space>\n ) : (\n <Space orientation=\"vertical\" align=\"center\">\n <Typography.Paragraph>\n No sections available\n </Typography.Paragraph>\n <Typography.Text>\n {isMobile\n ? 'Tap a component to add it'\n : 'Drag a component from the left to add it'}\n </Typography.Text>\n </Space>\n )}\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 nodeRef={sectionNodes.register(section.id)}\n onNavigate={to => onNavigate(section.id, to)}\n onDeleteKey={() => onDeleteKey(section.id)}\n inspecting={inspecting}\n onInspectMove={onInspectMove}\n onInspectPick={(...args) => onInspectPick(section.id, ...args)}\n onInspectLeave={() => setHighlight(null)}\n >\n <Renderer\n preview={previews[index]!}\n sectionId={section.id}\n sectionName={section.name}\n sectionCode={section.code}\n forceFallback={isForced(section)}\n modules={modules}\n frame={frame}\n dynamicTailwind={dynamicTailwind}\n provider={provider}\n {...props}\n />\n </Sortable>\n ))}\n </SortableContext>\n )}\n </Droppable>\n </>\n );\n\n return (\n <SectionFallbackContext.Provider value={renderSectionFallback}>\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n accessibility={{\n announcements,\n screenReaderInstructions: SCREEN_READER_INSTRUCTIONS,\n }}\n modifiers={[\n conditionalModifiers,\n //\n ]}\n onDragStart={onDragStart}\n onDragOver={onDragOver}\n onDragEnd={onDragEnd}\n >\n <div\n className={cn(\n 'relative flex h-full w-full',\n className,\n //\n )}\n {...restProps}\n >\n {/* Not memoized: `palette`, `panel` and `canvas` are all rebuilt\n each render anyway, so a memo would only add a dependency list\n to keep in sync. */}\n <DndEditOptionsContext.Provider value={{ renderField, reportError }}>\n <DndRegionContext.Provider\n value={{\n palette,\n panel,\n canvas,\n isMobile,\n selectedId,\n clearSelection,\n paletteOpen: mobilePaletteOpen,\n setPaletteOpen: setMobilePaletteOpen,\n documentError: problem?.reason ?? null,\n }}\n >\n {/* `Children.toArray` rather than a plain `children ??`: a JSX\n comment, or a `{cond && <MyLayout />}` that fell through,\n leaves `children` set but empty — and honouring that\n literally renders an editor with no regions at all, which\n looks like a broken build rather than a mistake in the\n layout. Falling back keeps the failure legible. */}\n <DndInspectorContext.Provider value={inspector}>\n {Children.toArray(children).length ? children : <Layout />}\n </DndInspectorContext.Provider>\n </DndRegionContext.Provider>\n <InspectorHighlight rect={inspecting ? highlight : null} />\n </DndEditOptionsContext.Provider>\n </div>\n <DragOverlay>\n <Overlay\n sections={sections}\n isForced={isForced}\n renderProps={{\n fullCode: value,\n modules,\n frame,\n dynamicTailwind,\n ...props,\n // After the spread, so a preview prop with the same name can't\n // point the overlay at a different container.\n containerId,\n }}\n />\n </DragOverlay>\n </DndContext>\n </SectionFallbackContext.Provider>\n );\n};\n\nexport default Dnd;\n","import DndImpl, {\n type DndPalette,\n type DndPanel,\n type PanelBinding,\n type PanelNodeChange,\n type PanelNodesChange,\n type Props,\n} from './dnd';\nimport DraggableItem, {\n type DraggableItemDragState,\n type DraggableItemProps,\n} from './draggable';\nimport type { DndEditError, DndRenderField } from './edit-options';\nimport {\n type DndInspector,\n type DndNodePick,\n useDndInspector,\n} from './inspector';\nimport {\n Canvas,\n type DndLayoutProps,\n type DndRegionProps,\n Layout,\n Palette,\n Panel,\n} from './layout';\nimport {\n type DndLayout,\n useDndLayout,\n useDndPalette,\n useDndPanel,\n} from './layout-context';\nimport Field, { type FieldProps } from './panel/field';\nimport {\n type DndChildren,\n type DndChildrenOptions,\n useDndChildren,\n} from './panel/use-dnd-children';\nimport {\n type DndItems,\n type DndItemsActions,\n type DndItemsExpansion,\n type DndItemsItem,\n type DndItemsNestedElement,\n type DndItemsNestedGroup,\n type DndItemsOptions,\n useDndItems,\n} from './panel/use-dnd-items';\nimport type {\n DndRenderSectionFallback,\n DndSectionFallbackArgs,\n} from './section-fallback-context';\n\ntype DndComponent = typeof DndImpl & {\n // Owns the dnd-kit wiring for a palette item and hands back `ref` /\n // `dragProps` / `isDragging`, so a custom palette decides how an item\n // *looks* without reimplementing how dragging works.\n DraggableItem: typeof DraggableItem;\n // The built-in control for one binding, exported so a custom panel can mix\n // its own controls with the built-in one per binding rather than choosing\n // all-or-nothing. Takes a `PanelBinding` straight out of `bindings` plus\n // `onNodeChange` — both `useDndPanel()` fields, so nothing internal is\n // needed to drive it. Most useful for `items`/`children` bindings, whose\n // editors find nested data-bound elements a consumer can't reach through\n // `bindings`. Renders the control only — supply your own label.\n Field: typeof Field;\n // The three built-in regions, each in the container it needs. Pass them as\n // `children` of `Live.Dnd` in any arrangement to own the layout, mixing in\n // your own components where you want to replace one. `Canvas` is the one\n // that can't be replaced — the droppable, the sortable list and each\n // section's compiled iframe are Dnd's own machinery — so render it exactly\n // once wherever the canvas belongs.\n Palette: typeof Palette;\n Canvas: typeof Canvas;\n Panel: typeof Panel;\n // The built-in arrangement: the 3-pane desktop Splitter, the stacked\n // mobile canvas, and the mobile FAB/Drawers. What `Live.Dnd` renders when\n // given no children, exported so children can wrap it (a toolbar above it,\n // say) or replace one region through its `palette`/`panel` slots without\n // rebuilding the rest. Also the only way to reach the built-in Splitter\n // layout without importing `@jbpark/ui-kit` directly, which a consumer may\n // not have as a direct dependency.\n Layout: typeof Layout;\n};\n\nconst Dnd = DndImpl as DndComponent;\n\nDnd.DraggableItem = DraggableItem;\nDnd.Field = Field;\nDnd.Palette = Palette;\nDnd.Canvas = Canvas;\nDnd.Panel = Panel;\nDnd.Layout = Layout;\n\nexport { DraggableItem, Field };\nexport { Palette, Canvas, Panel, Layout };\n// The data behind each region, so a component placed in `Live.Dnd`'s children\n// can replace one without losing what drives it: the palette's items and\n// `onAdd`, the panel's selected section/bindings/commit callbacks, and the\n// layout state the built-in mobile chrome runs on (`isMobile`, `selectedId` /\n// `clearSelection`, the palette Drawer's open state) — needed because\n// supplying children replaces that chrome along with the Splitter.\nexport { useDndPalette, useDndPanel, useDndLayout };\n// The element picker: turn it on, and clicking an element in the canvas\n// preview selects its section and reports the element's `data-id` (#432).\nexport { useDndInspector };\n// The array-editing engine behind the built-in Items panel, exposed for a\n// consumer who wants their own markup rather than the built-in control\n// (`Field` covers the latter). Everything it returns is `PanelBinding`s, so\n// the two compose: render the hook's own layout and hand individual\n// bindings to `Field` where the built-in control is good enough.\nexport { useDndChildren };\nexport type { DndChildren, DndChildrenOptions };\nexport { useDndItems };\n// The two steps behind `useDndPanel().bindings`, for an element the panel\n// doesn't hand over itself — most often a child's fields under\n// `useDndChildren`, which returns raw `DataAttrNode`s. `resolvePanelBindings`\n// reads a node into bindings without a commit; `withPanelCommit` attaches\n// `onNodeChange`. Together they produce `PanelBinding`s ready for `Field`.\nexport { resolvePanelBindings, withPanelCommit } from './panel-binding';\nexport type { PanelBindingData, PanelBindingSource } from './panel-binding';\n// The rule `Field` uses to pick its built-in control, so a custom panel that\n// routes some bindings to `Field` or a hook (most often the structural\n// `items`/`children` ones) asks the library instead of copying the checks.\nexport { getFieldKind, isStructuralFieldKind } from './panel/field-kind';\nexport type { FieldKind, FieldKindBinding } from './panel/field-kind';\n\n// The names these hooks and types shipped under before they joined the\n// `useDnd*` family. Kept as aliases so existing imports keep compiling; drop\n// them in the next major. Each maps mechanically: `useItemsEditor` →\n// `useDndItems`, `useChildrenEditor` → `useDndChildren`, `ItemsEditor*` →\n// `DndItems*`, `ChildrenEditor*` → `DndChildren*`.\n/** @deprecated Renamed to `useDndItems`. */\nexport const useItemsEditor = useDndItems;\n/** @deprecated Renamed to `useDndChildren`. */\nexport const useChildrenEditor = useDndChildren;\n/** @deprecated Renamed to `DndItems`. */\nexport type ItemsEditor = DndItems;\n/** @deprecated Renamed to `DndItemsActions`. */\nexport type ItemsEditorActions = DndItemsActions;\n/** @deprecated Renamed to `DndItemsItem`. */\nexport type ItemsEditorItem = DndItemsItem;\n/** @deprecated Renamed to `DndItemsNestedElement`. */\nexport type ItemsEditorNestedElement = DndItemsNestedElement;\n/** @deprecated Renamed to `DndItemsNestedGroup`. */\nexport type ItemsEditorNestedGroup = DndItemsNestedGroup;\n/** @deprecated Renamed to `DndItemsOptions`. */\nexport type ItemsEditorOptions = DndItemsOptions;\n/** @deprecated Renamed to `DndChildren`. */\nexport type ChildrenEditor = DndChildren;\n/** @deprecated Renamed to `DndChildrenOptions`. */\nexport type ChildrenEditorOptions = DndChildrenOptions;\nexport type {\n Props,\n DndPalette,\n DndPanel,\n DndLayout,\n DndInspector,\n DndNodePick,\n DndLayoutProps,\n DndRegionProps,\n PanelBinding,\n PanelNodeChange,\n PanelNodesChange,\n FieldProps,\n DndEditError,\n DndRenderField,\n DndRenderSectionFallback,\n DndSectionFallbackArgs,\n DndItems,\n DndItemsActions,\n DndItemsExpansion,\n DndItemsItem,\n DndItemsNestedElement,\n DndItemsNestedGroup,\n DndItemsOptions,\n DraggableItemProps,\n DraggableItemDragState,\n};\nexport default Dnd;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAKA,MAAM,aAAa,EACjB,UACA,gBACwC;CACxC,MAAM,EAAE,YAAY,QAAQ,WAAW,aAAa,EAClD,IAAI,gBACN,CAAC;CAED,MAAM,EAAE,YAAY,cAAc,QAAQ,iBAAiB,aAAa,EACtE,IAAI,uBACN,CAAC;CAED,MAAM,oBAAoB,QAAQ,KAAK,SAAS,SAAS;CACzD,MAAM,kBAAkB,UAAU;CAClC,MAAM,wBAAwB,gBAAgB;CAE9C,OACE,qBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,cACA,8BACA,kBAAkB,+BAA+B,mBACjD,SACF;EAPF,UAAA,CASG,UACA,qBACC,oBAAC,OAAD;GACE,KAAK;GACL,WAAW,GACT,iBACA,qCACA,+BACA,oCACA,wBACI,gCACA,4BACN;GAEA,UAAA,oBAAC,WAAW,MAAZ;IAAiB,WAAU;IACxB,UAAA,wBAAwB,cAAc;GACxB,CAAA;EACd,CAAA,CAEJ;;AAET;;;AC4BA,MAAa,kBAAkB,UAAwB;CACrD,MAAM,MACJ,MAAM,OACN,MAAM,cAAc,EAAE,aAAa,MAAM,YAAY,IAAI,KAAA,CAC3D;AACF;AAOA,MAAa,wBAAwB,cAA8B,EACjE,aAAa,eACf,CAAC;AAED,MAAa,0BAA0B,WAAW,qBAAqB;;;ACvEvE,MAAa,sBAAsB,cAAmC,IAAI;AAE1E,MAAa,wBAAsC;CACjD,MAAM,YAAY,WAAW,mBAAmB;CAEhD,IAAI,CAAC,WACH,MAAM,IAAI,MAAM,mDAAmD;CAGrE,OAAO;AACT;AAKA,MAAM,WAAW,UAAiC,YAChD,QAAQ,YAAY,MAAM;AAO5B,MAAM,aACJ,MACA,GACA,GACA,SACmB;CACnB,MAAM,UAAU,KACb,kBAAkB,GAAG,CAAC,CAAC,CACvB,MAAK,cAAa,CAAC,KAAK,SAAS,CAAC;CAErC,IAAI,CAAC,SACH,OAAO;CAGT,IAAI,mBAAmB,mBAAmB;EACxC,MAAM,WAAW,QAAQ;EAEzB,IAAI,CAAC,UACH,OAAO;EAGT,MAAM,OAAO,QAAQ,sBAAsB;EAE3C,OACE,UAAU,UAAU,IAAI,KAAK,MAAM,IAAI,KAAK,KAAK,QAAQ,QAAQ,CAAC,KAClE;CAEJ;CAEA,IAAI,QAAQ,cAAc,QAAQ,eAAe,MAC/C,OACE,UAAU,QAAQ,YAAY,GAAG,GAAG,QAAQ,QAAQ,UAAU,CAAC,KAC/D;CAIJ,OAAO;AACT;AAEA,MAAM,SAAS,YAAqB,QAAQ,QAAQ,aAAa,UAAU,EAAE,CAAC;AAK9E,MAAa,eACX,SACA,SACA,GACA,MACmB;CACnB,IAAI,UAAU,UACZ,QAAQ,eACR,GACA,IACA,cACE,cAAc,WACd,cAAc,WACd,CAAC,QAAQ,SAAS,SAAS,CAC/B;CAIA,OAAO,WAAW,YAAY,WAAW,CAAC,MAAM,OAAO,GACrD,UACE,QAAQ,iBAEP,QAAQ,YAAkC,QAC3C;CAGJ,OAAO,YAAY,UAAU,OAAO;AACtC;AAIA,MAAa,gBAAgB,YAA8B;CACzD,MAAM,OAAO,QAAQ,sBAAsB;CAC3C,IAAI,IAAI,KAAK;CACb,IAAI,IAAI,KAAK;CACb,IAAI,QAAQ,QAAQ,cAAc,aAAa,gBAAgB;CAE/D,OAAO,OAAO;EACZ,MAAM,YAAY,MAAM,sBAAsB;EAE9C,KAAK,UAAU;EACf,KAAK,UAAU;EACf,QAAQ,MAAM,cAAc,aAAa,gBAAgB;CAC3D;CAEA,OAAO,IAAI,QAAQ,GAAG,GAAG,KAAK,OAAO,KAAK,MAAM;AAClD;;;ACrIA,MAAM,sBAAsB,EAAE,WAC5B,OACI,aACE,oBAAC,OAAD;CACE,eAAA;CACA,gCAAA;CACA,OAAO;EACL,UAAU;EACV,MAAM,KAAK;EACX,KAAK,KAAK;EACV,OAAO,KAAK;EACZ,QAAQ,KAAK;EACb,eAAe;EACf,SAAS;EACT,eAAe;EACf,YAAY;EACZ,QAAQ;CACV;AACD,CAAA,GACD,SAAS,IACX,IACA;;;ACJN,MAAM,iBAAiB,EAAE,MAAM,eAAmC;CAChE,MAAM,EAAE,YAAY,WAAW,YAAY,eAAe,aAAa;EACrE,IAAI,KAAK;EACT,MAAM;GAAE,MAAM;GAAY;EAAK;CACjC,CAAC;CAED,OAAO,SAAS;EACd,KAAK;EACL,WAAW;GAAE,GAAG;GAAW,GAAG;EAAW;EACzC;CACF,CAAC;AACH;AAkBA,MAAa,wBAAwB,EACnC,MACA,OACA,WAAW,YAEX,oBAAC,eAAD;CAAqB;CACjB,WAAA,EAAE,KAAK,WAAW,iBAClB,oBAAC,MAAD;EACO;EACL,OAAO,EAAE,SAAS,aAAa,KAAM,EAAE;EACvC,GAAI;EACJ,WAAW,GACT,eAGA,iEACA,yCACA,cAAc,YAChB;EACA,SAAS,YAAY,cAAc,MAAM,IAAI,IAAI,KAAA;EACjD,eAAe,cAAc,MAAM,IAAI,IAAI,KAAA;EAI3C,YAAW,UAAS;GAClB,UAAU,YAAY,KAAK;GAE3B,IACE,SACA,MAAM,QAAQ,WACd,MAAM,WAAW,MAAM,iBACvB,CAAC,MAAM,kBACP;IACA,MAAM,eAAe;IACrB,MAAM,IAAI;GACZ;EACF;EAEC,UAAA,KAAK;CACF,CAAA;AAEK,CAAA;;;AChDjB,MAAa,mBAAmB,cAAiC,IAAI;AAMrE,MAAa,iBAAiB,YAAgC;CAC5D,MAAM,UAAU,WAAW,gBAAgB;CAE3C,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,GAAG,QAAQ,iCAAiC;CAG9D,OAAO;AACT;AAKA,MAAa,sBACX,cAAc,iBAAiB,CAAC,CAAC;AAKnC,MAAa,oBAA8B,cAAc,eAAe,CAAC,CAAC;AAI1E,MAAa,qBAAgC,cAAc,gBAAgB;;;ACkD3E,MAAM,iBAAiB,MAAoB,SACzC,KAAK,eAAe,MAAK,cAAa,UAAU,SAAS,IAAI,CAAC,EAAE;AAElE,MAAM,uBAAuB,MAAoB,YAAyB;CAExE,IAAI,4BAA4B,SAAS,QAAQ,QAAQ,GACvD,OAAO;CAGT,IACE,QAAQ,aAAa,cACrB,QAAQ,aAAa,eACrB,QAAQ,aAAa,eACrB,QAAQ,aAAa,WACrB,QAAQ,aAAa,UACrB,QAAQ,SAAS,WACjB,QAAQ,SAAS,SACjB,QAAQ,SAAS,YAEjB,OAAO;CAGT,MAAM,YAAY,KAAK,WAAW,MAChC,cAAa,UAAU,SAAS,QAAQ,QAC1C;CAGA,IAAI,CAAC,WACH,OAAO;CAGT,OACE,UAAU,oBAAoB,QAC9B,4BAA4B,WAAW,SAAS,EAAE;AAEtD;AAOA,MAAa,mBACX,aAC4D;CAC5D,OAAO,QAAQ;CACf,UAAU,QAAQ;CAClB,MAAM,QAAQ;CACd,QAAQ,QAAQ;CAChB,SAAS,QAAQ;CACjB,QAAQ,QAAQ;CAChB,KAAK,QAAQ;CACb,KAAK,QAAQ;CACb,SAAS,QAAQ;CACjB,UAAU,QAAQ;CAClB,MAAM,QAAQ;AAChB;AAOA,MAAa,sBACX,QACA,QACgB;CAChB,MAAM,QAAQ,SAAS;CAEvB,IAAI,SAAS,UAAU,OAAO;EAC5B,MAAM,OAAO;EAEb,OAAO;GACL,GAAG;GACH,OAAO,KAAK,SAAS;GACrB,UAAU,KAAK,YAAY;EAC7B;CACF;CAEA,OAAO;EAAE,OAAO;EAAK,UAAU;EAAK,QAAQ;CAA0B;AACxE;AAIA,MAAM,qCAAqB,IAAI,IAAI;CAAC;CAAa;CAAa;AAAU,CAAC;AAEzE,MAAM,qBAAqB,MAAoB,YAC7C,CAAC,mBAAmB,IAAI,QAAQ,QAAQ,KACxC,CAAC,KAAK,WAAW,MAAK,cAAa,UAAU,SAAS,QAAQ,QAAQ;AAExE,MAAM,sBACJ,MACA,IACA,aACsB;CACtB,GAAG,gBAAgB,OAAO;CAC1B;CACA,OAAO,mBAAmB,MAAM,QAAQ,UAAU,QAAQ,IAAI;CAC9D,UAAU,gBAAgB,MAAM,QAAQ,QAAQ;CAChD,GAAI,CAAC,oBAAoB,MAAM,OAAO,KAAK,EAAE,cAAc,MAAM;CACjE,GAAI,kBAAkB,MAAM,OAAO,KAAK,EAAE,SAAS,MAAM;AAC3D;AAUA,MAAa,wBACX,SAC8B;CAC9B,MAAM,KAAK,cAAc,MAAM,SAAS;CACxC,MAAM,cAAc,cAAc,MAAM,cAAc;CAEtD,IAAI,CAAC,MAAM,CAAC,aACV,OAAO;CAGT,MAAM,SAAS,KAAK,YAAY,aAAa,WAAW;CAExD,IAAI,CAAC,OAAO,QACV,OAAO;CAGT,OAAO;EACL;EACA,SAAS,KAAK,WAAW;EACzB,UAAU,OAAO,KAAI,YAAW,mBAAmB,MAAM,IAAI,OAAO,CAAC;CACvE;AACF;AAMA,MAAa,mBACX,UACA,WAEA,SAAS,KAAI,aAAY;CACvB,GAAG;CACH,WAAW,UACT,SAAS;EACP,IAAI,QAAQ;EACZ,OAAO,QAAQ;EACf,UAAU,QAAQ;EAClB;CACF,CAAC;AACL,EAAE;;;ACrQJ,MAAM,kBAAkB,EACtB,OACA,WAAW,OACX,aACA,UACA,YACA,UACA,cACyB;CACzB,IAAI,UAAU,GACZ,OAAO;CAGT,OACE,qBAAC,OAAD;EACE,WAAU;EADZ,UAAA,CAIE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CAAoD,OAAM,WAAc;EACxE,CAAA,GAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,oBAAC,QAAD;KACE,MAAK;KACL,MAAM,oBAAC,MAAD,CAAO,CAAA;KACb,OAAM;KACI;KACV,SAAS;IACV,CAAA;IACD,oBAAC,QAAD;KACE,MAAK;KACL,MAAM,oBAAC,SAAD,CAAU,CAAA;KAChB,OAAM;KACI;KACV,SAAS;IACV,CAAA;IACD,oBAAC,QAAD;KACE,MAAK;KACL,MAAM,oBAAC,WAAD,CAAY,CAAA;KAClB,OAAM;KACI;KACV,SAAS;IACV,CAAA;IACD,oBAAC,QAAD;KACE,QAAA;KACA,MAAK;KACL,MAAM,oBAAC,GAAD,CAAI,CAAA;KACV,OAAM;KACI;KACV,SAAS;IACV,CAAA;IACD,oBAAC,QAAD;KAAQ,MAAK;KAAQ,SAAS;KAAS,UAAA;IAE/B,CAAA;GACL;EACF,CAAA,CAAA;;AAET;;;ACtDA,MAAM,QAAQ,EAAE,MAAM,eAAiC;CACrD,MAAM,SAAS,qBAAqB,IAAI;CAExC,IAAI,CAAC,QACH,OAAO;CAKT,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA,gBAAgB,OAAO,UAAU,QAAQ,CAAC,CAAC,KAAI,YAC9C,qBAAC,OAAD;IAA+C,WAAU;IAAzD,UAAA,CACE,qBAAC,SAAD;KAAO,WAAU;KAAjB,UAAA,CACG,QAAQ,OACT,qBAAC,QAAD;MAAM,WAAU;MAAhB,UAAA;OAAqC;OAAE,QAAQ;OAAS;MAAO;KAC1D,CAAA,CAAA;IACP,CAAA,GAAA,oBAAC,OAAD;KAAgB;KAAS,cAAc;IAAW,CAAA,CAC/C;GANK,GAAA,GAAG,QAAQ,GAAG,GAAG,QAAQ,UAM9B,CACN;EACE,CAAA;CACF,CAAA;AAET;;;ACvBA,MAAa,kBACX,SACA,UACA,UACgB;CAChB,QAAQ,QAAQ,MAAhB;EACE,KAAK;EACL,KAAK,aAEH,OAAO,IAAI,IAAI,QAAQ;EACzB,KAAK,iBACH,OAAO,oBACL,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,UAAU,KAAK,GACjD,IAAI,IAAI,QAAQ,OAAO,GACvB,QAAQ,SACV,CAAC,CAAC;EACJ,SACE,uBAAO,IAAI,IAAI;CACnB;AACF;AAqBA,MAAa,0BAA0B,OAAe,aAAqB;CACzE,MAAM,YAAY,eAAe,KAAK;CACtC,MAAM,CAAC,MAAM,WAAW,SAAS,QAAQ;CACzC,MAAM,CAAC,SAAS,cAAc,SAAyB,IAAI;CAI3D,IAAI,aAAa,MAAM;EACrB,QAAQ,QAAQ;EAChB,WAAW,IAAI;EAEf,IAAI,SAAS,QAAQ,QAAQ,KAAK,QAAQ,UAAU,OAAO,GACzD,UAAU,QAAQ,QAAQ,SAAS;OAEnC,UAAU,MAAM;CAEpB;CAEA,MAAM,UACJ,MACA,SACA,EAAE,MAAM,UAAyB,CAAC,MAC/B;EACH,WAAW;GAAE;GAAS,WAAW;EAAK,CAAC;EAEvC,IAAI,CAAC,KACH;EAIF,IAAI,KAAK,OAAO,GACd,UAAU,QAAQ,IAAI;OAEtB,UAAU,MAAM;CAEpB;CAEA,OAAO;EAAE;EAAW;CAAO;AAC7B;;;ACtEA,MAAM,cACJ,UACA,WACoC;CACpC,IAAI,OAAO,SAAS,iBAAiB;EACnC,MAAM,QAAQ,KAAK,UACjB,oBAAoB,UAAU,IAAI,IAAI,OAAO,OAAO,GAAG,OAAO,SAAS,CAAC,CACrE,KACL;EAEA,QAAO,aAAY,aAAa;CAClC;CAEA,MAAM,QACJ,OAAO,SAAS,WACZ,IACA,OAAO,SAAS,cACd,OAAO,QAAQ,SACf;CAER,QAAO,aAAY;EACjB,MAAM,OAAO,KAAK,MAAM,QAAQ;EAEhC,OACE,KAAK,WAAW,SAAS,SAAS,SAClC,SAAS,OAAO,WAAW,UAAU,KAAK,WAAW,SAAS;CAElE;AACF;AAKA,MAAa,kBACX,OACA,EAAE,aAAiC,CAAC,MACjC;CACH,MAAM,WAAW,cAAc,sBAAsB,KAAK,GAAG,CAAC,KAAK,CAAC;CACpE,MAAM,WAAW,KAAK,UAAU,QAAQ;CACxC,MAAM,EAAE,WAAW,WAAW,uBAAuB,MAAM,QAAQ,QAAQ;CAK3E,MAAM,UAAU,WAA2B;EACzC,MAAM,OAAqB;GAAE,MAAM;GAAiB;GAAU;EAAO;EACrE,MAAM,OAAO,eAAe,QAAQ,UAAU,UAAU,MAAM,MAAM;EAEpE,IAAI,KAAK,OAAO,GACd,OAAO,MAAM,WAAW,UAAU,MAAM,CAAC;EAG3C,WAAW,KAAK,UAAU,IAAI,CAAC;CACjC;CAEA,OAAO;EACL;EACA;EACA,SAAS;GACP,OAAO,MAAc,OAAe,OAAO;IAAE,MAAM;IAAQ;IAAM;GAAG,CAAC;GACrE,SAAS,UAAkB,OAAO;IAAE,MAAM;IAAU,SAAS,CAAC,KAAK;GAAE,CAAC;GACtE,WAAW,OAAO,EAAE,MAAM,SAAS,CAAC;GACpC,yBACE,OAAO;IAAE,MAAM;IAAa,SAAS,CAAC,GAAG,UAAU,QAAQ;GAAE,CAAC;GAChE,eAAe,cACb,OAAO;IACL,MAAM;IACN,SAAS,CAAC,GAAG,UAAU,QAAQ;IAC/B;GACF,CAAC;GACH,sBACE,OAAO;IAAE,MAAM;IAAU,SAAS,CAAC,GAAG,UAAU,QAAQ;GAAE,CAAC;EAC/D;CACF;AACF;;;AC/EA,MAAMA,cAAY,EAAE,OAAO,UAAU,mBAA0B;CAC7D,MAAM,QAAQ,cAAe,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,GAAI,CAAC,KAAK,CAAC;CAExE,MAAM,EAAE,WAAW,YAAY,eAAe,OAAO,EAAE,SAAS,CAAC;CAEjE,MAAM,sBAAsB,cAAc;EACxC,MAAM,sBAAM,IAAI,IAA4B;EAC5C,MAAM,SAAS,MAAM,UAAU;GAC7B,MAAM,gBAAgB,qBAAqB,IAAI;GAC/C,IAAI,cAAc,SAAS,GACzB,IAAI,IAAI,OAAO,aAAa;EAEhC,CAAC;EACD,OAAO;CACT,GAAG,CAAC,KAAK,CAAC;CAEV,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MAAsD;MACnC,MAAM;MAAO;KAC3B;IACL,CAAA,GAAA,oBAAC,QAAD;KACE,MAAK;KACL,OAAM;KACN,MAAM,oBAAC,MAAD,CAAO,CAAA;KACb,SAAS,QAAQ;KAClB,UAAA;IAEO,CAAA,CACL;;GAEL,oBAAC,gBAAD;IACE,OAAO,UAAU,SAAS;IAC1B,aAAa,QAAQ;IACrB,gBAAgB,QAAQ,aAAa,IAAI;IACzC,kBAAkB,QAAQ,aAAa,MAAM;IAC7C,UAAU,QAAQ;IAClB,SAAS,UAAU;GACpB,CAAA;GAEA,MAAM,KAAK,MAAM,cAChB,qBAAC,OAAD;IAEE,WAAU;IAFZ,UAAA;KAIE,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,oBAAC,OAAD;QACE,UAAS,MAAK,UAAU,OAAO,WAAW,EAAE,QAAQ;QACpD,WAAU;QAEV,UAAA,oBAAC,UAAD;SACE,SAAS,UAAU,WAAW,SAAS;SACvC,gBAAgB,CAAC;QAClB,CAAA;OACE,CAAA,GACL,qBAAC,OAAD;QAAK,WAAU;QAAf,UAAA;SAAoD;SAC3C,YAAY;SAAE;SAAG,KAAK,WAAW;SAAW;QAChD;OACF,CAAA,CAAA;MAEL,CAAA,GAAA,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA;QACE,oBAAC,QAAD;SACE,MAAK;SACL,MAAM,oBAAC,SAAD,CAAU,CAAA;SAChB,UAAU,cAAc;SACxB,eAAe,QAAQ,KAAK,WAAW,YAAY,CAAC;QACrD,CAAA;QACD,oBAAC,QAAD;SACE,MAAK;SACL,MAAM,oBAAC,WAAD,CAAY,CAAA;SAClB,UAAU,cAAc,MAAM,SAAS;SACvC,eAAe,QAAQ,KAAK,WAAW,YAAY,CAAC;QACrD,CAAA;QACD,oBAAC,QAAD;SACE,OAAM;SACN,QAAA;SACA,MAAK;SACL,MAAM,oBAAC,GAAD,CAAI,CAAA;SACV,eAAe,QAAQ,OAAO,SAAS;QACxC,CAAA;OACE;MACF,CAAA,CAAA;;KAEJ,oBAAoB,IAAI,SAAS,KAChC,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,oBAAC,OAAD;OAAK,WAAU;OAAqC,UAAA;MAE/C,CAAA,GACJ,oBAAoB,IAAI,SAAS,CAAC,CAAE,KAAK,cAAc,QAAQ;OAC9D,MAAM,SAAS,aAAa,eAAe,MACzC,MAAK,EAAE,SAAS,SAClB,CAAC,EAAE;OAEH,OACE,qBAAC,OAAD;QAEE,gBAAc;QACd,WAAU;QAHZ,UAAA,CAME,oBAAC,OAAD;SAAK,WAAU;SACZ,UAAA,aAAa;QACX,CAAA,GACL,oBAAC,MAAD;SAAM,MAAM;SAAc,UAAU;QAAe,CAAA,CAChD;OATE,GAAA,YAAY,UAAU,KASxB;MAET,CAAC,CACE;;KAGN,CAAC,CAAC,KAAK,YAAY,CAAC,oBAAoB,IAAI,SAAS,KACpD,qBAAC,OAAD;MAAK,WAAU;MAAf,UAAA,CACE,oBAAC,OAAD;OAAK,WAAU;OAAqC,UAAA;MAE/C,CAAA,GACJ,KAAK,SAAS,KAAK,MAAM,cACxB,oBAAC,OAAD;OAEE,WAAU;OAEV,UAAA,oBAAC,MAAD;QAAM,MAAM;QAAM,UAAU;OAAe,CAAA;MACxC,GAJE,QAAQ,UAAU,GAAG,WAIvB,CACN,CACE;;IAEJ;GApFE,GAAA,KAAK,MAAM,SAoFb,CACN;EACE;;AAET;;;AClHA,MAAM,mBAAmB,aACvB,SAAS,YAAY,CAAC,CAAC,SAAS,OAAO;AAMzC,MAAa,gBAAgB,YAAyC;CACpE,MAAM,EAAE,UAAU,MAAM,UAAU;CAElC,IAAI,QAAQ,iBAAiB,OAC3B,OAAO;CAGT,IAAI,aAAa,WAAW,aAAa,UAAU,SAAS,SAC1D,OAAO;CAGT,IAAI,SAAS,YACX,OAAO;CAGT,IAAI,aAAa,aAAa,YAC5B,OAAO;CAGT,IAAI,SAAS,OACX,OAAO;CAGT,IAAI,aAAa,cAAc,MAAM,QAAQ,KAAK,GAChD,OAAO;CAGT,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,GACrE,OAAO;CAGT,IAAI,SAAS,aAAa,OAAO,UAAU,WACzC,OAAO;CAGT,IAAI,QAAQ,WAAW,MAAM,QAAQ,QAAQ,OAAO,GAClD,OAAO;CAGT,IAAI,SAAS,WAAW,gBAAgB,QAAQ,GAC9C,OAAO;CAGT,IAAI,SAAS,QACX,OAAO;CAGT,IAAI,SAAS,OACX,OAAO;CAGT,IAAI,SAAS,YAAY,OAAO,UAAU,UACxC,OAAO;CAGT,OAAO;AACT;AAIA,MAAa,yBACX,SACiC,SAAS,WAAW,SAAS;;;AC5EhE,MAAM,SAAS,OAAuB,OAAwB;CAC5D,MAAM,QAAQ,MAAM,WAAU,SAAQ,KAAK,OAAO,EAAE;CAEpD,OAAO,SAAS,IAAI,QAAQ,QAAQ,MAAM;AAC5C;AAUA,MAAa,iBAAiB,EAC5B,OACA,UACA,QACA,eAMI;CACJ,MAAM,UAAU,WACd,UAAU,aAAa,EAAE,sBAAsB,EAAE,UAAU,EAAE,EAAE,CAAC,GAChE,UAAU,aAAa,EACrB,sBAAsB;EAAE,OAAO;EAAK,WAAW;CAAE,EACnD,CAAC,GACD,UAAU,gBAAgB,EACxB,kBAAkB,4BACpB,CAAC,CACH;CAEA,MAAM,aAAa,EAAE,QAAQ,WAAyB;EACpD,MAAM,OAAO,MAAM,MAAK,SAAQ,KAAK,OAAO,OAAO,EAAE;EACrD,MAAM,KAAK,MAAM,MAAK,SAAQ,KAAK,OAAO,MAAM,EAAE;EAElD,IAAI,QAAQ,MAAM,SAAS,IACzB,OAAO,MAAM,GAAG,KAAK;CAEzB;CAiBA,OACE,oBAAC,YAAD;EACW;EACT,oBAAoB;EACpB,WAAW,CAAC,wBAAwB,uBAAuB;EAC3D,eAAe,EAAE,eAAA;GAlBnB,cAAc,EAAE,aAAa,aAAa,MAAM,OAAO,OAAO,EAAE,EAAE;GAClE,aAAa,EAAE,QAAQ,WACrB,OACI,GAAG,MAAM,OAAO,OAAO,EAAE,EAAE,WAAW,MAAM,OAAO,KAAK,EAAE,EAAE,KAC5D,KAAA;GACN,YAAY,EAAE,QAAQ,WACpB,OACI,GAAG,MAAM,OAAO,OAAO,EAAE,EAAE,6BAA6B,MAAM,OAAO,KAAK,EAAE,EAAE,KAC9E,GAAG,MAAM,OAAO,OAAO,EAAE,EAAE;GACjC,eAAe,EAAE,aACf,UAAU,MAAM,OAAO,OAAO,EAAE,EAAE;EAQL,EAAE;EACpB;EAEX,UAAA,oBAAC,iBAAD;GACE,OAAO,MAAM,KAAI,SAAQ,KAAK,EAAE;GAChC,UAAU;GACA;GAEV,UAAA,oBAAC,OAAD;IAAK,WAAU;IAAa,UAAA,MAAM,IAAI,QAAQ;GAAO,CAAA;EACtC,CAAA;CACP,CAAA;AAEhB;AAIA,MAAa,YAAY,EACvB,IACA,OACA,UACA,UACA,UACA,UACA,UACA,WACA,eAWI;CACJ,MAAM,EACJ,YACA,WACA,YACA,qBACA,WACA,YACA,eACE,YAAY;EAAE;EAAI;CAAS,CAAC;CAEhC,OACE,qBAAC,OAAD;EACE,KAAK;EACL,OAAO;GAAE,WAAWC,MAAI,UAAU,SAAS,SAAS;GAAG;EAAW;EAClE,WAAW,GAAG,WAAW,cAAc,yBAAyB;EAHlE,UAAA,CAKE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,oBAAC,UAAD;MACE,MAAK;MACL,KAAK;MACL,GAAI;MACJ,GAAI;MACJ,cAAY,WAAW;MACb;MACV,WAAU;MAIV,UAAA,oBAAC,cAAD,EAAc,MAAM,GAAK,CAAA;KACnB,CAAA;KACP;KACD,qBAAC,UAAD;MACE,MAAK;MACL,iBAAe;MACf,SAAS;MACT,WAAU;MAJZ,UAAA,CAOG,WAAW,oBAAC,aAAD,EAAa,MAAM,GAAK,CAAA,IAAI,oBAAC,cAAD,EAAc,MAAM,GAAK,CAAA,GACjE,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA,CACb;;IACL;GACJ,CAAA,GAAA,QACE;EACJ,CAAA,GAAA,YAAY,QACV;;AAET;;;ACKA,MAAM,4BAA4B;CAChC,IAAI,UAAgC;CAEpC,OAAO;EACL,YAAY;EACZ,QAAQ,SAAwB;GAC9B,UAAU;EACZ;EACA,aAAa;GACX,UAAU;EACZ;CACF;AACF;AAYA,MAAM,iBAAiB,WAAmC;CACxD,MAAM,QAAQ,QAAQ,MAAM;CAC5B,MAAM,YAAY,MAAM,MAAK,MAC3B,EAAE,UAAU,MAAK,MAAK,EAAE,aAAa,UAAU,CACjD;CAEA,IAAI,WACF,OAAO,CAAC,SAAS;CAGnB,MAAM,WAA2B,CAAC;CAElC,MAAM,SAAQ,MAAK;EACjB,IACE,EAAE,YACF,EAAE,SAAS,SAAS,KACpB,EAAE,eAAe,MAAK,MAAK,EAAE,SAAS,SAAS,GAE/C,SAAS,KAAK,CAAC;EAGjB,SAAS,KAAK,GAAG,qBAAqB,CAAC,CAAC;CAC1C,CAAC;CAED,OAAO;AACT;AAKA,MAAM,eAAe,UAAkB;CACrC,MAAM,MAAM,qBAAqB,KAAK;CAEtC,IAAI,CAAC,KACH,OAAO;EAAE,aAAa,CAAC;EAAG,gBAAgB,CAAC;EAAG,YAAY;CAAK;CAGjE,MAAM,cAA+B,CAAC;CACtC,MAAM,iBAAqC,CAAC;CAC5C,IAAI,SAAS,SAAS,SAAS,iBAAiB;EAC9C,IAAI,CAACC,WAAE,aAAa,OAAO,GACzB;EAGF,IAAI,CAACA,WAAE,mBAAmB,OAAO,GAAG;GAClC,MAAM,YAAY,iBAAiB,OAAO;GAE1C,eAAe,KAAK;IAClB,IAAI,OAAO,CAAC;IACZ,OAAO,eAAe;IACtB;IACA,QAAQ,MAAM,MAAM,QAAQ,OAAQ,QAAQ,GAAI;IAChD,OAAO,UAAU;IACjB,MAAM,UAAU;GAClB,CAAC;GACD;EACF;EAEA,MAAM,cAA8C,CAAC;EACrD,MAAM,eAAuC,CAAC;EAE9C,QAAQ,WAAW,SAAQ,SAAQ;GACjC,IACE,CAACA,WAAE,iBAAiB,IAAI,KACxB,CAACA,WAAE,aAAa,KAAK,GAAG,KACxB,EAAEA,WAAE,aAAa,KAAK,KAAK,KAAKA,WAAE,cAAc,KAAK,KAAK,IAE1D;GAGF,MAAM,eAAe,KAAK,IAAI;GAE9B,IAAI;IACF,MAAM,QAAQ,cACZ,MAAM,MAAM,KAAK,MAAM,OAAQ,KAAK,MAAM,GAAI,CAChD;IAEA,IAAI,MAAM,SAAS,GACjB,YAAY,gBAAgB;SAE5B,aAAa,gBAAgB,MAAM,MACjC,KAAK,MAAM,OACX,KAAK,MAAM,GACb;GAEJ,SAAS,OAAO;IACd,QAAQ,MACN,oCAAoC,aAAa,KACjD,KACF;GACF;EACF,CAAC;EAED,MAAM,qBAAqB,wBAAwB,OAAO;EAE1D,KAAK,MAAM,YAAY,OAAO,OAAO,kBAAkB,GACrD,IAAI,SAAS,SAAS,WAAW,SAAS,SAAS,UACjD,SAAS,QAAQ,MAAM,MACrB,SAAS,QAAQ,OACjB,SAAS,QAAQ,GACnB;EAIJ,YAAY,KAAK;GACf,IAAI,OAAO,CAAC;GACZ,OAAO,YAAY;GACnB;GACA,QAAQ,MAAM,MAAM,QAAQ,OAAQ,QAAQ,GAAI;GAChD;GACA;GACA;EACF,CAAC;CACH,CAAC;CAED,OAAO;EAAE;EAAa;EAAgB,YAAY;CAAM;AAC1D;AAEA,MAAM,uBACJ,OACA,MACA,OACA,MAAgB,MAAM,KAAI,SAAQ,KAAK,EAAE,OAClB;CACvB;CACA;CACA;CACA,YAAY,MAAM,KAAI,SAAQ,KAAK,MAAM;AAC3C;AAEA,MAAM,0BACJ,SACA,OACA,MACA,UACsB;CACtB,IACE,WACA,QAAQ,UAAU,SAClB,QAAQ,SAAS,QACjB,QAAQ,IAAI,WAAW,MAAM,QAE7B,OAAO;CAGT,IAAI,CAAC,WAAW,QAAQ,SAAS,MAC/B,OAAO,oBAAoB,OAAO,MAAM,KAAK;CAG/C,MAAM,iCAAiB,IAAI,IAAoB;CAC/C,MAAM,6BAAa,IAAI,IAAoB;CAE3C,QAAQ,WAAW,SAAQ,cAAa;EACtC,eAAe,IAAI,YAAY,eAAe,IAAI,SAAS,KAAK,KAAK,CAAC;CACxE,CAAC;CACD,MAAM,SAAQ,SAAQ;EACpB,WAAW,IAAI,KAAK,SAAS,WAAW,IAAI,KAAK,MAAM,KAAK,KAAK,CAAC;CACpE,CAAC;CAED,MAAM,MAAM,MAAM,KAAI,SAAQ;EAC5B,MAAM,gBAAgB,QAAQ,WAAW,QAAQ,KAAK,MAAM;EAE5D,OAAO,iBAAiB,KACtB,eAAe,IAAI,KAAK,MAAM,MAAM,KACpC,WAAW,IAAI,KAAK,MAAM,MAAM,IAC9B,QAAQ,IAAI,iBACZ,KAAK;CACX,CAAC;CAED,OAAO,oBAAoB,OAAO,MAAM,OAAO,GAAG;AACpD;AAEA,MAAM,UAAU,KAAe,MAAc,OAAe;CAC1D,MAAM,OAAO,CAAC,GAAG,GAAG;CACpB,MAAM,CAAC,SAAS,KAAK,OAAO,MAAM,CAAC;CACnC,KAAK,OAAO,IAAI,GAAG,KAAM;CAEzB,OAAO;AACT;AAEA,MAAM,aAAa,KAAe,YAAyB;CACzD,OAAO,IAAI,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC;AACrD;AAWA,MAAa,eACX,OACA,EAAE,QAAQ,UAAU,iBAAkC,CAAC,MAC1C;CACb,MAAM,EAAE,aAAa,gBAAgB,eAAe,cAC5C,YAAY,KAAK,GACvB,CAAC,KAAK,CACR;CACA,MAAM,mBAAmB,cACjB,yBAAyB,KAAK,GACpC,CAAC,KAAK,CACR;CAEA,MAAM,EAAE,gBAAgB,kBAAkB;CAI1C,MAAM,iBAAiB,OAAO,WAAW;CAEzC,gBAAgB;EACd,eAAe,UAAU;CAC3B,CAAC;CAED,gBAAgB;EACd,IAAI,YACF,eAAe,QAAQ;GACrB,MAAM;GACN,QAAQ;GACR,OAAO;GACP,aAAa;EACf,CAAC;CAEL,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,OACJ,eAAe,SAAS,KAAK,YAAY,WAAW,IAChD,cACA;CACN,MAAM,cAAc,SAAS;CAC7B,MAAM,WAAW,cAAc,iBAAiB;CAChD,MAAM,CAAC,eAAe,oBAAoB,eACxC,oBAAoB,OAAO,MAAM,QAAQ,CAC3C;CACA,MAAM,WAAW,cACT,uBAAuB,eAAe,OAAO,MAAM,QAAQ,GACjE;EAAC;EAAe;EAAM;EAAU;CAAK,CACvC;CAKA,MAAM,CAAC,WAAW,gBAAgB,+BAC1B,IAAI,IAAI,CAChB;CAEA,MAAM,EAAE,WAAW,WAAW,uBAC5B,cAAc,eAAe,SAAS,YAAY,QAClD,KACF;CAiBA,MAAM,CAAC,WAAW,SAAS,mBAAmB;CAE9C,gBAAgB;EACd,QAAQ,MAAM;CAChB,CAAC;CAED,MAAM,eAAyB;EAC7B,MAAM,OAAO,QAAQ,KAAK;EAE1B,IAAI,MAAM,SAAS,OACjB,OAAO;GACL;GACA,OAAO;GACP,KAAK,SAAS;GACd,UAAU,UAAU;EACtB;EAGF,MAAM,SAAS,YAAY,KAAK,KAAK;EAErC,OAAO;GACL,OAAO,KAAK;GACZ,OAAO,cAAc,OAAO,iBAAiB,OAAO;GACpD,KAAK,KAAK;GACV,UAAU,KAAK;EACjB;CACF;CAOA,MAAM,UAAU,UAAoB,iBAAyB;EAC3D,MAAM,QAAQ,SAAS,MAAK,SAAQ,KAAK,iBAAiB,YAAY;EAEtE,IAAI,CAAC,OACH;EAGF,MAAM,QAAQ,SAAS,IAAI,QAAQ,SAAS,IAAI,MAAM,MAAO;EAE7D,OAAO,SAAS,IAAI,SAAS,MAAM,SAAS;CAC9C;CAMA,MAAM,UACJ,UACA,MACA,SACA,kBACG;EACH,IAAI,SAAS,MAAM;GACjB,YAAY;IACV,MAAM;IACN,OAAO;IACP,aACE;GACJ,CAAC;GAED,OAAO;EACT;EAEA,MAAM,SAAS,YAAY,IAAI;EAC/B,MAAM,YACJ,SAAS,cAAc,OAAO,iBAAiB,OAAO;EACxD,MAAM,MAAM,WAAW,SAAS;EAEhC,QAAQ,MAAM;GACZ,MAAM;GACN,OAAO;GACP;GACA,UAAU;EACZ,CAAC;EACD,iBAAiB,oBAAoB,MAAM,MAAM,WAAW,GAAG,CAAC;EAChE,OAAO,gBAAe,aAAY,aAAa,MAAM,EAAE,KAAK,KAAK,CAAC;EAClE,WAAW,IAAI;EAEf,OAAO;CACT;CAKA,MAAM,oBAAoB,UAAoB,YAC5C,IAAI,IACF,SAAS,MACN,QAAO,SAAQ,QAAQ,IAAI,KAAK,KAAK,CAAC,CAAC,CACvC,KAAI,SAAQ,KAAK,YAAY,CAClC;CAEF,MAAM,kBACJ,cACA,aACA,SACG;EACH,MAAM,WAAW,OAAO;EACxB,MAAM,OAAO,OAAO,UAAU,YAAY;EAE1C,IAAI,SAAS,MACX;EAIF,OACE,UACA,wBACE,SAAS,OACT,MAAM,gBAAgB,cACtB,aACA,MACA,MACF,GACA,KAAA,GACA,IAAI,IAAI,SAAS,QAAQ,CAC3B;CACF;CAEA,MAAM,eAAe,cAAsB,SAAkB;EAC3D,MAAM,WAAW,OAAO;EACxB,MAAM,OAAO,OAAO,UAAU,YAAY;EAE1C,IAAI,SAAS,MACX;EAGF,OACE,UACA,qBACE,SAAS,OACT,MAAM,gBAAgB,cACtB,IACF,GACA,KAAA,GACA,IAAI,IAAI,SAAS,QAAQ,CAC3B;CACF;CAEA,MAAM,UAA2B;EAC/B,WAAW;GACT,MAAM,WAAW,OAAO;GACxB,MAAM,OAAO,gBAAgB,SAAS,OAAO,IAAI;GAEjD,OACE,UACA,MACA,OAAO,CAAC,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,IAAI,KAAA,GACtC,eACE,EAAE,MAAM,SAAS,GACjB,SAAS,UACT,SAAS,MAAM,MACjB,CACF;EACF;EAEA,OAAO,cAAc,YAAY;GAC/B,MAAM,WAAW,OAAO;GACxB,MAAM,OAAO,OAAO,UAAU,YAAY;GAC1C,MAAM,SAAS,SAAS,MAAM,MAAK,SAAQ,KAAK,UAAU,OAAO;GAEjE,IAAI,CAAC,QAAQ,CAAC,QACZ;GAKF,OACE,UACA,cAAc,SAAS,OAAO,KAAK,cAAc,OAAO,YAAY,GACpE,OAAO,SAAS,KAAK,KAAK,OAAO,OAAO,KAAK,mBAC7C,IAAI,IAAI,CACV;EACF;EAEA,SAAQ,iBAAgB;GACtB,MAAM,WAAW,OAAO;GACxB,MAAM,UAAU,OAAO,UAAU,YAAY;GAE7C,IAAI,YAAY,MACd;GAIF,OACE,UACA,iBACE,SAAS,uBACT,IAAI,IAAI,CAAC,SAAS,gBAAgB,YAAY,CAAC,GAC/C,IACF,GACA,UAAU,UAAU,SAAS,qBAAK,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,KAAA,mBAC9D,IAAI,IAAI,CACV;EACF;EAEA,yBAAyB;GACvB,MAAM,WAAW,OAAO;GACxB,MAAM,WAAW,iBAAiB,UAAU,SAAS,QAAQ;GAC7D,MAAM,OAAO,oBAAoB,SAAS,OAAO,QAAQ;GACzD,MAAM,SAAS,SAAS,MACrB,QAAO,SAAQ,SAAS,IAAI,KAAK,YAAY,CAAC,CAAC,CAC/C,MAAM,GAAG,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,CAC/C,UAAU,OAAO,CAAC,CAAC;GAEtB,OACE,UACA,MACA,OAAO,CAAC,GAAG,SAAS,KAAK,GAAG,MAAM,IAAI,KAAA,GACtC,eACE;IAAE,MAAM;IAAa,SAAS,CAAC,GAAG,SAAS,QAAQ;GAAE,GACrD,SAAS,UACT,SAAS,MAAM,MACjB,CACF;EACF;EAEA,eAAc,cAAa;GACzB,MAAM,WAAW,OAAO;GACxB,MAAM,eAAe,oBACnB,SAAS,KACT,SAAS,UACT,SACF;GACA,MAAM,SAAS,eACb,SAAS,OACT,iBAAiB,UAAU,SAAS,QAAQ,GAC5C,SACF;GAEA,IAAI,CAAC,QAAQ;IACX,OAAO,UAAU,MAAM,KAAA,GAAW,SAAS,QAAQ;IACnD;GACF;GAIA,MAAM,UADS,qBAAqB,OAAO,IAEpC,CAAC,EAAE,SAAS,SAAS,MAAM,UAC9BA,WAAE,aAAa,IAAI,KAAKA,WAAE,mBAAmB,IAAI,MAAM,CAAC,cACpD,CAAC,KAAK,IACN,CAAC,CACP,KAAK,CAAC;GAIR,OACE,UACA,OAAO,MACP,aAAa,OACb,IAAI,IACF,QAAQ,SAAS,UAAU,UACzB,OAAO,QAAQ,IAAI,QAAQ,IAAI,CAAC,KAAK,IAAI,CAAC,CAC5C,CACF,CACF;EACF;EAEA,sBAAsB;GACpB,MAAM,WAAW,OAAO;GAExB,OACE,UACA,iBACE,SAAS,OACT,iBAAiB,UAAU,SAAS,QAAQ,GAC5C,IACF,GACA,UAAU,SAAS,KAAK,SAAS,QAAQ,mBACzC,IAAI,IAAI,CACV;EACF;CACF;CAKA,MAAM,QAAwB,cAC1B,eAAe,KAAI,UAAS;EAC1B,IAAI,SAAS,IAAI,KAAK,UAAU,KAAK;EACrC,OAAO,KAAK;EACZ,cAAc,KAAK;EACnB,YAAY,CAAC;EACb,QAAQ,CAAC;EACT,OAAO;GACL,IAAI,aAAa,KAAK;GACtB,OAAO,QAAQ,KAAK;GACpB,UAAU,KAAK;GACf,OAAO,KAAK,SAAS;GACrB,UACE,KAAK,SAAS,YAAY,KAAK,SAAS,OAAO,KAAK,SAAS,EAAE;GACjE,cAAc,4BAA4B,KAAK,MAAM;GACrD,WAAU,SAAQ,YAAY,KAAK,cAAc,IAAI;EACvD;CACF,EAAE,IACF,YAAY,KAAI,SAAQ;EACtB,MAAM,KAAK,SAAS,IAAI,KAAK,UAAU,KAAK;EAC5C,MAAM,aAA6B,OAAO,QACxC,KAAK,kBACP,CAAC,CAAC,KAAK,CAAC,KAAK,UAAU;GACrB,MAAM,UAAU,mBAAmB,QAAQ,GAAG;GAC9C,MAAM,iBAAiB,MAAM,MAC3B,KAAK,QAAQ,OACb,KAAK,QAAQ,GACf;GAEA,OAAO;IACL,GAAG,gBAAgB,OAAO;IAC1B,IAAI,QAAQ,GAAG,GAAG;IAIlB,MAAM;KAAE,GAAG,QAAQ;KAAM,WAAW,KAAK;IAAK;IAC9C,OAAO,WAAW,OAAO,KAAK,KAAK,CAAC;IACpC,UACE,KAAK,SAAS,YAAY,iBAAiB,OAAO,KAAK,KAAK;IAC9D,cAAc,4BAA4B,cAAc;IACxD,WAAU,SAAQ,eAAe,KAAK,cAAc,KAAK,IAAI;GAC/D;EACF,CAAC;EAED,MAAM,SAAgC,CACpC,GAAG,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,KAAK,CAAC,UAAU,YAAY;GAC9D;GACA,UAAU,MAAM,SAAQ,SAAQ;IAC9B,MAAM,SAAS,qBAAqB,IAAI;IAExC,IAAI,CAAC,QACH,OAAO,CAAC;IAGV,OAAO,CACL;KACE,IAAI,OAAO;KACX,SAAS,OAAO;KAChB,UAAU,gBAAgB,OAAO,UAAU,YAAY;IACzD,CACF;GACF,CAAC;EACH,EAAE,GACF,GAAG,OAAO,QAAQ,KAAK,YAAY,CAAC,CAAC,KAAK,CAAC,UAAU,WAAW;GAC9D;GACA,UAAU,CAAC;GACX,UAAU;IACR,IAAI,QAAQ,GAAG,GAAG,SAAS;IAC3B,OAAO;IACP;IACA,MAAM;IACN,OAAO;IACP,UAAU;IACV,cAAc;IACd,WAAW,SACT,eAAe,KAAK,cAAc,UAAU,IAAI;GACpD;EACF,EAAE,CACJ;EAEA,OAAO;GACL;GACA,OAAO,KAAK;GACZ,cAAc,KAAK;GACnB;GACA;EACF;CACF,CAAC;CA4BL,OAAO;EACL;EACA;EACA;EACA,WAAA;GA7BA,aAAa,MAAM,SAAQ,SACzB,UAAU,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CACxC;GACA,aAAY,OAAM,CAAC,UAAU,IAAI,EAAE;GACnC,SAAQ,OACN,cAAa,aAAY;IACvB,MAAM,OAAO,IAAI,IAAI,QAAQ;IAE7B,IAAI,CAAC,KAAK,OAAO,EAAE,GACjB,KAAK,IAAI,EAAE;IAGb,OAAO;GACT,CAAC;GACH,cAAa,QAAO;IAClB,MAAM,WAAW,IAAI,IAAI,GAAG;IAE5B,aACE,IAAI,IACF,MAAM,SAAQ,SAAS,SAAS,IAAI,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAE,CAChE,CACF;GACF;EAOQ;EACR;EACA;EACA;CACF;AACF;;;ACr1BA,MAAM,eAAe,EACnB,OACA,mBAII;CACJ,IAAI,MAAM,UACR,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA,MAAM;EACJ,CAAA,GACL,oBAAC,OAAD;GAAO,SAAS,MAAM;GAAwB;EAAe,CAAA,CAC1D;;CAIT,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,MAAM;IAAS;IAAY,MAAM,SAAS;IAAO;GAC/C;EACJ,CAAA,GAAA,MAAM,SAAS,KAAI,YAClB,qBAAC,OAAD;GAEE,gBAAc,QAAQ;GACtB,WAAU;GAHZ,UAAA,CAME,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KAA4C;KACrC,QAAQ;KAAQ;IAClB;GACL,CAAA,GAAA,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,QAAQ,SAAS,KAAI,YACpB,qBAAC,OAAD;MAEE,WAAU;MAFZ,UAAA,CAIE,qBAAC,SAAD;OAAO,WAAU;OAAjB,UAAA,CACG,QAAQ,OACT,qBAAC,QAAD;QAAM,WAAU;QAAhB,UAAA;SAAqC;SACjC,QAAQ;SAAS;QACf;OACD,CAAA,CAAA;MACP,CAAA,GAAA,oBAAC,OAAD;OAAgB;OAAuB;MAAe,CAAA,CACnD;KAVE,GAAA,GAAG,QAAQ,SAAS,GAAG,QAAQ,OAUjC,CACN;IACE,CAAA;GACF,CAAA,CACF;EA1BE,GAAA,GAAG,MAAM,SAAS,GAAG,QAAQ,IA0B/B,CACN,CACE;;AAET;AAKA,MAAM,SAAS,EAAE,OAAO,QAAQ,UAAU,oBAA2B;CACnE,MAAM,EACJ,MACA,OACA,WACA,WACA,SACA,kBACA,eACE,YAAY,OAAO;EACrB;EACA;EACA,cAAc;CAChB,CAAC;CAED,MAAM,SACJ,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IAAuC;IAAQ,MAAM;IAAO;GAAM;EAGjE,CAAA,GAAA,MAAM,SAAS,KAAK,oBACnB,oBAAC,QAAD;GACE,MAAK;GACL,MAAM,oBAAC,MAAD,CAAO,CAAA;GACb,SAAQ;GACR,OAAM;GACN,SAAS,QAAQ;GAClB,UAAA;EAEO,CAAA,CAEP;;CAGP,IAAI,YACF,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACG,QACD,oBAAC,OAAD;GACE,WAAU;GAEX,UAAA;EAEI,CAAA,CACF;;CAQT,IAAI,MAAM,WAAW,GACnB,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACG,QACD,oBAAC,OAAD;GACE,WAAU;GAEX,UAAA;EAII,CAAA,CACF;;CAIT,MAAM,UACJ,oBAAC,gBAAD;EACE,OAAO,UAAU,SAAS;EAC1B,UAAU,CAAC;EACX,aAAa,QAAQ;EACrB,gBAAgB,QAAQ,aAAa,IAAI;EACzC,kBAAkB,QAAQ,aAAa,MAAM;EAC7C,UAAU,QAAQ;EAClB,SAAS,UAAU;CACpB,CAAA;CAGH,MAAM,gBAAgB,SACpB,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,QAAD;IACE,MAAK;IACL,MAAM,oBAAC,SAAD,CAAU,CAAA;IAChB,UAAU,CAAC,oBAAoB,KAAK,UAAU;IAC9C,eAAe,QAAQ,KAAK,KAAK,cAAc,KAAK,QAAQ,CAAC;GAC9D,CAAA;GACD,oBAAC,QAAD;IACE,MAAK;IACL,MAAM,oBAAC,WAAD,CAAY,CAAA;IAClB,UAAU,CAAC,oBAAoB,KAAK,UAAU,MAAM,SAAS;IAC7D,eAAe,QAAQ,KAAK,KAAK,cAAc,KAAK,QAAQ,CAAC;GAC9D,CAAA;GACD,oBAAC,QAAD;IACE,QAAA;IACA,MAAK;IACL,MAAM,oBAAC,GAAD,CAAI,CAAA;IACV,UAAU,CAAC,oBAAoB,MAAM,UAAU;IAC/C,eAAe,QAAQ,OAAO,KAAK,YAAY;GAChD,CAAA;EACE;;CAGP,MAAM,gBAAgB,SACpB,oBAAC,OAAD;EACE,UAAS,MACP,oBAAoB,UAAU,OAAO,KAAK,OAAO,EAAE,QAAQ;EAE7D,WAAU;EAEV,UAAA,oBAAC,UAAD;GACE,SAAS,UAAU,WAAW,KAAK,KAAK;GACxC,UAAU,CAAC;GACX,gBAAgB,CAAC;EAClB,CAAA;CACE,CAAA;CAGP,MAAM,cAAc,SAClB,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,WAAU;EACZ,UAAA,KAAK,WAAW,KAAI,YACnB,qBAAC,OAAD,EAAA,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,SAAD;IAAO,WAAU;IACd,UAAA,QAAQ;GACJ,CAAA,GACP,oBAAC,OAAD;IAAgB;IAAS,cAAc;GAAgB,CAAA,CACpD;EACL,CAAA,GAAA,qBAAC,QAAD;GAAM,WAAU;GAAhB,UAAA;IAAmD;IAC/C,OAAO,QAAQ,MAAM,SAAS;IAAE;GAC9B;EACH,CAAA,CAAA,EAAA,GAVK,GAAG,KAAK,GAAG,GAAG,QAAQ,SAAS,GAAG,QAAQ,OAU/C,CACN;CACE,CAAA,GACL,oBAAC,OAAD;EAAK,WAAU;EACZ,UAAA,KAAK,OAAO,SACX,KAAK,OAAO,KAAI,UACd,oBAAC,aAAD;GAES;GACP,cAAc;EACf,GAHM,MAAM,QAGZ,CACF,IAED,oBAAC,OAAD;GAAK,WAAU;GAAwB,UAAA;EAA4B,CAAA;CAElE,CAAA,CACL,EAAA,CAAA;CAGJ,MAAM,cAAc,UAAU,YAAY,WAAW,MAAM;CAE3D,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACG;GAEA,MAAM,SAAS,KACd,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,QAAD;KACE,MAAK;KACL,SAAQ;KACR,eACE,UAAU,YACR,cAAc,CAAC,IAAI,MAAM,KAAI,SAAQ,KAAK,EAAE,CAC9C;KAGD,UAAA,cAAc,iBAAiB;IAC1B,CAAA;GACL,CAAA;GAGN;GAEA,CAAC,oBACA,oBAAC,OAAD;IACE,WAAU;IAEX,UAAA;GAII,CAAA;GAGP,oBAAC,eAAD;IACS;IACP,UAAU,CAAC;IACX,SAAS,MAAM,YAAY,QAAQ,KAAK,KAAK,cAAc,OAAO;IAEjE,WAAA,SACC,oBAAC,UAAD;KAEE,IAAI,KAAK;KACT,OAAO,QAAQ,KAAK,QAAQ;KAC5B,UAAU,CAAC;KACX,UAAU,UAAU,WAAW,KAAK,EAAE;KACtC,gBAAgB,UAAU,OAAO,KAAK,EAAE;KACxC,UAAU,aAAa,IAAI;KAC3B,UAAU,aAAa,IAAI;KAC3B,WACE,SAAS,cACL,4DACA;KAGL,UAAA,SAAS,cACR,oBAAC,OAAD;MAAO,SAAS,KAAK;MAAQ,cAAc;KAAgB,CAAA,IAE3D,WAAW,IAAI;IAET,GAnBH,KAAK,EAmBF;GAEC,CAAA;EACZ;;AAET;;;ACrPA,MAAM,kBAAkB,UAA0B;CAChD,MAAM,UAAU,MAAM,KAAK;CAE3B,IAAI,2BAA2B,KAAK,OAAO,GACzC,OAAO;CAET,OAAO;AACT;AAEA,MAAM,kBAAkB,UAAoC;CAC1D,MAAM,QAAQ,4BAA4B,KAAK,MAAM,KAAK,CAAC;CAE3D,IAAI,CAAC,OACH;CAGF,MAAM,GAAG,MAAM,OAAO,OAAO;CAC7B,MAAM,OAAO,IAAI,KAAK,OAAO,IAAI,GAAG,OAAO,KAAK,IAAI,GAAG,OAAO,GAAG,CAAC;CAElE,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,KAAA,IAAY;AACpD;AAEA,MAAM,mBAAmB,SAAuB;CAK9C,OAAO,GAJM,KAAK,YAIL,EAAE,GAHD,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,GAGhC,EAAE,GAFZ,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,GAAG,GAElB;AAC/B;AAWA,MAAM,qBAAqB;AAK3B,MAAM,mBAAqE;CACzE;CACA;CACA;CACA;CACA;CACA;AACF;AAkBA,MAAM,kBAAkB,EAAE,OAAO,QAAQ,aAAkC;CACzE,MAAM,eAAe,OAA+B,IAAI;CACxD,MAAM,aAAa,OAAO,KAAK;CAE/B,MAAM,eAAe,aAAa,WAAuB;EACvD,aAAa,UAAU,OAAO,MAAM;CACtC,GAAG,CAAC,CAAC;CAEL,MAAM,qBAAqB,aAAa,SAAqB;EAC3D,IAAI,aAAa,SACf,KAAK,SAAS,EAAE,WAAW,aAAa,QAAQ,CAAC;EAGnD,IAAI,WAAW,SACb,KAAK,MAAM;CAEf,GAAG,CAAC,CAAC;CAEL,MAAM,cAAc,kBAAkB;EACpC,WAAW,UAAU;CACvB,GAAG,CAAC,CAAC;CAEL,MAAM,aAAa,aAAa,UAAsC;EACpE,IACE,MAAM,iBACN,CAAC,MAAM,cAAc,SAAS,MAAM,aAAqB,GAEzD,WAAW,UAAU;CAEzB,GAAG,CAAC,CAAC;CAEL,OACE,oBAAC,OAAD;EAAK,gBAAgB;EAAa,eAAe;EAC/C,UAAA,oBAACC,MAAD;GACS;GACP,QAAO;GACP,UAAU,CAAC;GACX,KAAK;GACG;GACR,UAAU;GACV,gBAAgB;EACjB,CAAA;CACE,CAAA;AAET;AAEA,MAAM,oBAAoB,EAAE,OAAO,eAAsC;CACvE,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAIhD,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,mBAAmB,OAAO,KAAK;CAOrC,IAAI,UAAU,WAAW;EACvB,aAAa,KAAK;EAClB,aAAa,KAAK;CACpB;CAMA,gBAAgB;EACd,iBAAiB,UAAU;CAC7B,GAAG,CAAC,KAAK,CAAC;CAEV,MAAM,UAAU,SAAiB;EAC/B,IAAI,SAAS,iBAAiB,SAC5B;EAEF,iBAAiB,UAAU;EAC3B,SAAS,IAAI;CACf;CAEA,MAAM,kBAAkB,kBAAkB,OAAO,SAAS,GAAG;EAC3D,OAAO;EACP,YAAY;CACd,CAAC;CAED,OACE,oBAAC,aAAD;EACE,UAAA;EACA,OAAO;EACP,WAAU,SAAQ;GAChB,aAAa,IAAI;GACjB,gBAAgB;EAClB;EACA,eAAc,SAAQ;GAKpB,IAAI,CAAC,MACH,OAAO,SAAS;EAEpB;CACD,CAAA;AAEL;AAOA,MAAM,cAAc,EAAE,cACpB,UAAU,oBAAC,KAAD;CAAG,WAAU;CAAkC,UAAA;AAAW,CAAA,IAAI;AAE1E,MAAM,gBAAgB,EAAE,SAAS,mBAA+B;CAI9D,MAAM,EAAE,IAAI,OAAO,UAAU,aAAa;CAE1C,MAAM,CAAC,iBAAiB,sBAAsB,SAAwB,IAAI;CAY1E,MAAM,CAAC,MAAM,WAAW,SAAS,QAAQ;CACzC,MAAM,CAAC,cAAc,mBAAmB,SAAS,QAAQ;CAEzD,IAAI,aAAa,cAAc;EAC7B,gBAAgB,QAAQ;EACxB,QAAQ,QAAQ;CAClB;CAEA,MAAM,OAAO,aAAa,OAAO;CAEjC,IAAI,SAAS,YACX,OACE,qBAAC,OAAD;EACE,WAAU;EADZ,UAAA;GAIE,oBAAC,OAAD,EAAA,UAAK,yDAA2D,CAAA;GAChE,oBAAC,QAAD;IAAM,WAAU;IAAwC,UAAA;GAAe,CAAA;GACvE,oBAAC,OAAD,EAAA,UAAK,oCAAsC,CAAA;EACxC;;CAQT,MAAM,mBAAmB,SAAkB;EAGzC,IAAI,UAFY,OAAO,SAAS,WAAW,WAAW,QAGpD,SAAS,IAAI;CAEjB;CAEA,IAAI,SAAS,SACX,OACE,oBAAC,OAAD;EACE,OAAO;EACP,QAAQ,QAAQ;EACN;EACV,eAAe;CAChB,CAAA;CAIL,IAAI,SAAS,YACX,OACE,oBAAC,gBAAD;EACE,OAAO;EACP,SAAS;EACT,UAAU;CACX,CAAA;CAIL,IAAI,SAAS,UAAU,SAAS,OAC9B,OACE,oBAAC,gBAAD;EACE,OAAO;EACP,QAAQ,SAAS;EACjB,QAAQ;CACT,CAAA;CAIL,IAAI,SAAS,YACX,OACE,oBAACC,YAAD;EACS;EACG;EACI;CACf,CAAA;CAIL,IAAI,SAAS,UAAU;EACrB,MAAM,cAAc;EAEpB,OACE,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA,OAAO,QAAQ,WAAW,CAAC,CAAC,KAAK,CAAC,KAAK,SAAS;IAC/C,MAAM,SAAS,mBAAmB,QAAQ,QAAQ,GAAG;IAErD,OACE,qBAAC,OAAD;KAAe,WAAU;KAAzB,UAAA,CACE,oBAAC,SAAD;MAAO,WAAU;MACd,UAAA,OAAO;KACH,CAAA,GACP,oBAAC,OAAD;MACE,SAAS;OACP,GAAG,gBAAgB,MAAM;OACzB;OACA,OAAO;OACP,UACE,OAAO,QAAQ,YAAY,QAAQ,OAC/B,KAAK,UAAU,GAAG,IAClB,OAAO,GAAG;OAChB,WAAU,SAAQ;QAChB,SAAS;SAAE,GAAG;UAAc,MAAM;QAAK,CAAC;OAC1C;MACF;MACc;KACf,CAAA,CACE;IAnBK,GAAA,GAmBL;GAET,CAAC;EACE,CAAA;CAET;CAEA,IAAI,SAAS,WACX,OACE,oBAAC,UAAD;EACE,SAAS,UAAU,QAAQ,UAAU;EACrC,WAAU,YAAW;GACnB,SAAS,OAAO;EAClB;CACD,CAAA;CAIL,MAAM,cAAc;CAEpB,IAAI,SAAS,UACX,OACE,oBAAC,QAAD;EACE,OAAO;EACP,SAAS,QAAQ,WAAW,CAAC;EAC7B,UAAU;CACX,CAAA;CAIL,IAAI,SAAS,SACX,OACE,oBAAC,kBAAD;EACE,OAAO,eAAe,WAAW;EACjC,UAAU;CACX,CAAA;CAIL,IAAI,SAAS,QACX,OACE,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,YAAD;EACE,OAAO,eAAe,WAAW;EACjC,WAAU,SAAQ;GAChB,MAAM,OAAO,OAAO,gBAAgB,IAAI,IAAI;GAC5C,MAAM,SAAS,qBAAqB,SAAS,IAAI;GAEjD,IAAI,CAAC,OAAO,OAAO;IACjB,mBAAmB,OAAO,WAAW,gBAAgB;IACrD;GACF;GAEA,mBAAmB,IAAI;GAEvB,gBAAgB,IAAI;EACtB;CACD,CAAA,GACD,oBAAC,YAAD,EAAY,SAAS,gBAAkB,CAAA,CACpC,EAAA,CAAA;CAIT,IAAI,SAAS,OACX,OACE,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,OAAD;EACE,MAAK;EACL,OAAO;EACP,WAAU,MAAK,QAAQ,EAAE,OAAO,KAAK;EACrC,aAAY;EACZ,SAAQ,MAAK;GACX,MAAM,OAAO,EAAE,OAAO,MAAM,KAAK;GACjC,MAAM,SAAS,qBAAqB,SAAS,IAAI;GAEjD,IAAI,CAAC,OAAO,OAAO;IACjB,mBAAmB,OAAO,WAAW,gBAAgB;IACrD;GACF;GAEA,mBAAmB,IAAI;GAEvB,gBAAgB,IAAI;EACtB;CACD,CAAA,GACD,oBAAC,YAAD,EAAY,SAAS,gBAAkB,CAAA,CACpC,EAAA,CAAA;CAIT,IAAI,SAAS,UACX,OACE,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,OAAD;EACE,MAAK;EACL,OAAO;EACP,WAAU,MAAK,QAAQ,EAAE,OAAO,KAAK;EACrC,aAAY;EACZ,SAAQ,MAAK;GACX,MAAM,MAAM,EAAE,OAAO,MAAM,KAAK;GAMhC,MAAM,OACJ,QAAQ,MAAM,CAAC,OAAO,MAAM,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,IAAI;GAC3D,MAAM,SAAS,qBAAqB,SAAS,IAAI;GAEjD,IAAI,CAAC,OAAO,OAAO;IACjB,mBAAmB,OAAO,WAAW,gBAAgB;IACrD;GACF;GAEA,mBAAmB,IAAI;GAEvB,gBAAgB,IAAI;EACtB;CACD,CAAA,GACD,oBAAC,YAAD,EAAY,SAAS,gBAAkB,CAAA,CACpC,EAAA,CAAA;CAIT,OACE,qBAAC,OAAD,EAAA,UAAA,CACE,oBAAC,MAAM,UAAP;EACE,OAAO;EACP,WAAU,MAAK,QAAQ,EAAE,OAAO,KAAK;EACrC,aAAY;EACZ,SAAQ,MAAK;GACX,MAAM,MAAM,EAAE,OAAO,MAAM,KAAK;GAMhC,MAAM,OAAgB,QAAQ,OAAO,MAAM,WAAW,GAAG;GACzD,MAAM,SAAS,qBAAqB,SAAS,IAAI;GAEjD,IAAI,CAAC,OAAO,OAAO;IACjB,mBAAmB,OAAO,WAAW,gBAAgB;IACrD;GACF;GAEA,mBAAmB,IAAI;GAEvB,gBAAgB,IAAI;EACtB;CACD,CAAA,GACD,oBAAC,YAAD,EAAY,SAAS,gBAAkB,CAAA,CACpC,EAAA,CAAA;AAET;AAMA,MAAM,SAAS,UAAsB;CACnC,MAAM,EAAE,gBAAgB,kBAAkB;CAC1C,MAAM,UAAU,oBAAC,cAAD,EAAc,GAAI,MAAQ,CAAA;CAE1C,IAAI,CAAC,aACH,OAAO;CAGT,MAAM,SAAS,YAAY,OAAO,OAAO;CAEzC,OAAO,WAAW,KAAA,IAAY,UAAU,oBAAA,UAAA,EAAA,UAAG,OAAS,CAAA;AACtD;;;ACrgBA,MAAM,cAAc,EAAE,UAAU,mBAC9B,oBAAC,OAAD;CAAK,WAAU;CACb,UAAA,oBAAC,OAAD;EAAK,WAAU;EACZ,UAAA,SAAS,KAAI,YACZ,qBAAC,OAAD;GAAkD,WAAU;GAA5D,UAAA,CACE,qBAAC,SAAD;IAAO,WAAU;IAAjB,UAAA,CACG,QAAQ,OACT,qBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA;MAAqC;MAAE,QAAQ;MAAS;KAAO;IAC1D,CAAA,CAAA;GACP,CAAA,GAAA,oBAAC,OAAD;IAAgB;IAAuB;GAAe,CAAA,CACnD;EANK,GAAA,GAAG,QAAQ,SAAS,GAAG,QAAQ,OAMpC,CACN;CACE,CAAA;AACF,CAAA;;;AC6BP,MAAM,qBAAqB,aAA+C;CACxE,MAAM,yBAAS,IAAI,IAA4B;CAE/C,KAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,QAAQ,OAAO,IAAI,QAAQ,EAAE;EAEnC,IAAI,OACF,MAAM,KAAK,OAAO;OAElB,OAAO,IAAI,QAAQ,IAAI,CAAC,OAAO,CAAC;CAEpC;CAEA,OAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;AAEA,MAAMC,WAAS,EACb,MACA,UACA,UACA,YACA,YAAY,OACZ,cAAc,OACd,UACA,cACA,WAAW,YACK;CAChB,MAAM,SAAS,kBAAkB,QAAQ;CACzC,MAAM,UAAU,OAAuB,IAAI;CAI3C,MAAM,YADS,WAAW,mBAAmB,CAAC,EAAE,UAAU,KAAA,EACjC;CAMzB,gBAAgB;EACd,MAAM,OAAO,QAAQ;EAErB,IAAI,CAAC,QAAQ,CAAC,UACZ;EAGF,MAAM,SAAS,KAAK,cAClB,kBAAkB,IAAI,OAAO,QAAQ,EAAE,GACzC;EAEA,IAAI,CAAC,QACH;EAGF,OAAO,aAAa,eAAe,EAAE;EAKrC,MAAM,QAAQ,YAAY,IAAI,IAAI;EAClC,IAAI,QAAQ;EAEZ,MAAM,mBAAmB;GACvB,MAAM,MAAM,OAAO,sBAAsB;GACzC,MAAM,OAAO,KAAK,sBAAsB;GAExC,IAAI,IAAI,MAAM,KAAK,OAAO,IAAI,SAAS,KAAK,QAC1C,OAAO,iBAAiB,EAAE,OAAO,UAAU,CAAC;GAG9C,IAAI,YAAY,IAAI,IAAI,OACtB,QAAQ,sBAAsB,UAAU;EAE5C;EAEA,WAAW;EAEX,aAAa;GACX,qBAAqB,KAAK;GAC1B,OAAO,gBAAgB,aAAa;EACtC;CACF,GAAG,CAAC,UAAU,OAAO,MAAM,CAAC;CAE5B,IAAI,CAAC,MACH,OACE,oBAAC,WAAW,WAAZ;EACE,WAAW,GACT,2BAEF;EACD,UAAA;CAEqB,CAAA;CAI1B,OACE,qBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,wBACA,mCAEF;EANF,UAAA;GAQE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,WAAW,OAAZ;KAAkB,WAAU;KACzB,UAAA,KAAK;IACU,CAAA,GAClB,qBAAC,OAAD;KAAK,WAAU;KAAf,UAAA;MACG,YACC,oBAAC,QAAD;OACE,MAAM,oBAAC,WAAD,CAAY,CAAA;OAClB,UAAU,CAAC;OACX,SAAS;OACT,cAAW;MACZ,CAAA;MAEF,cACC,oBAAC,QAAD;OACE,MAAM,oBAAC,aAAD,CAAc,CAAA;OACpB,UAAU,CAAC;OACX,SAAS;OACT,cAAW;MACZ,CAAA;MAEF,YACC,oBAAC,QAAD;OACE,QAAA;OACA,MAAM,oBAAC,OAAD,CAAQ,CAAA;OACd,eAAe,SAAS,KAAK,EAAE;OAC/B,cAAW;MACZ,CAAA;KAEA;IACF,CAAA,CAAA;;GACJ,YACC,oBAAC,WAAW,MAAZ;IAAiB,MAAK;IAAS,WAAU;IAA+B,UAAA;GAGvD,CAAA;GAElB,CAAC,OAAO,UACP,oBAAC,WAAW,MAAZ;IAAiB,WAAU;IAAwB,UAAA;GAElC,CAAA;GAElB,OAAO,KAAI,UACV,oBAAC,OAAD;IAEE,gBAAc,MAAM,EAAE,CAAE;IACxB,WAAU;IAGV,UAAA,oBAAC,YAAD;KAAY,UAAU;KAAqB;IAAe,CAAA;GACvD,GANE,MAAM,EAAE,CAAE,EAMZ,CACN;EACE;;AAET;;;AChMA,MAAM,gBAAgB,EAAE,cAAmC;CACzD,MAAM,EACJ,SAAS,EAAE,OAAO,SAClB,aACE,cAAc,OAAO;CAEzB,OACE,oBAAC,OAAD;EAAO,aAAY;EAAW,OAAM;EACjC,UAAA,MAAM,KAAI,SACT,oBAAC,sBAAD;GAEQ;GACC;GACP,UAAU;EACX,GAJM,KAAK,EAIX,CACF;CACI,CAAA;AAEX;AAEA,MAAM,eAAe,EAAE,cAAmC;CACxD,MAAM,EACJ,OAAO,EACL,MACA,UACA,UACA,YACA,WACA,aACA,UACA,cACA,eAEA,cAAc,OAAO;CAEzB,OACE,oBAACC,SAAD;EACQ;EACI;EACA;EACE;EACD;EACE;EACH;EACI;EACJ;CACX,CAAA;AAEL;AAMA,MAAa,WAAW,EAAE,WAAW,GAAG,gBACtC,oBAAC,OAAD;CACE,WAAW,GACT,yCACA,SAEF;CACA,GAAI;CAEJ,UAAA,oBAAC,cAAD,EAAc,SAAQ,qBAAsB,CAAA;AACzC,CAAA;AAWP,MAAa,UAAU,EAAE,WAAW,OAAO,GAAG,gBAAgC;CAC5E,MAAM,EAAE,QAAQ,kBAAkB,cAAc,mBAAmB;CACnE,MAAM,YAAY,gBAAgB;CAElC,OACE,qBAAC,OAAD;EACE,WAAW,GACT,0CACA,SAEF;EACA,wBAAA;EACA,OAAO;GACL,WAAW;GACX,SAAS;GACT,WAAW;GACX,GAAG;EACL;EACA,GAAI;EAbN,UAAA,CAeG,QAIA,CAAC,iBACA,oBAAC,OAAD;GAAK,WAAU;GACb,UAAA,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,QAAD;KACE,MAAM,oBAAC,WAAD,CAAY,CAAA;KAClB,OAAM;KACN,SAAS,UAAU,SAAS,UAAU;KACtC,gBAAc,UAAU;KACxB,cAAW;KACX,OACE,UAAU,SACN,gDACA;KAEN,SAAS,UAAU;IACpB,CAAA;GACE,CAAA;EACF,CAAA,CAEJ;;AAET;AAKA,MAAa,SAAS,EAAE,WAAW,GAAG,gBACpC,oBAAC,OAAD;CACE,WAAW,GACT,UACA,SAEF;CACA,GAAI;CAEJ,UAAA,oBAAC,aAAD,EAAa,SAAQ,mBAAoB,CAAA;AACtC,CAAA;AAmBP,MAAa,UAAU,EAAE,SAAS,YAA4B;CAC5D,MAAM,EAAE,UAAU,YAAY,gBAAgB,aAAa,mBACzD,cAAc,mBAAmB;CAEnC,OACE,qBAAA,UAAA,EAAA,UAAA;EACG,WACC,oBAAC,QAAD,CAAS,CAAA,IAET,qBAAC,UAAD;GAAU,YAAA;GAAW,aAAY;GAAjC,UAAA;IACE,oBAAC,SAAS,OAAV;KACE,aAAY;KACZ,SAAQ;KACR,SAAQ;KACR,aAAA;KAEC,UAAA,WAAW,oBAAC,SAAD,CAAU,CAAA;IACR,CAAA;IAChB,oBAAC,SAAS,OAAV;KAAgB,aAAY;KAC1B,UAAA,oBAAC,QAAD,CAAS,CAAA;IACK,CAAA;IAChB,oBAAC,SAAS,OAAV;KACE,aAAY;KACZ,SAAQ;KACR,SAAQ;KACR,aAAA;KAEC,UAAA,SAAS,oBAAC,OAAD,CAAQ,CAAA;IACJ,CAAA;GACR;;EAEZ,oBAAC,QAAD;GACE,MAAK;GACL,OAAM;GACN,MAAM,oBAAC,YAAD,CAAa,CAAA;GACnB,cAAW;GACX,WAAU;GACV,eAAe,eAAe,IAAI;EACnC,CAAA;EAID,oBAAC,QAAD;GACE,MAAM,YAAY;GAClB,eAAe,eAAe,KAAK;GACnC,WAAU;GACV,MAAK;GACL,OAAM;GAEL,UAAA,WAAW,oBAAC,cAAD,EAAc,SAAQ,oBAAqB,CAAA;EACjD,CAAA;EACR,oBAAC,QAAD;GACE,MAAM,YAAY,QAAQ,UAAU;GACpC,SAAS;GACT,WAAU;GACV,MAAK;GACL,OAAM;GAEL,UAAA,SAAS,oBAAC,aAAD,EAAa,SAAQ,oBAAqB,CAAA;EAC9C,CAAA;CACR,EAAA,CAAA;AAEN;;;ACxNA,MAAa,yBAAyB,cAEpC,KAAA,CAAS;;;ACPX,MAAM,oBAAoB,EAAE,QAAQ,MAAM,cAAqC;CAC7E,MAAM,OAAO,OAAO,IAAI;CAExB,OAAO,SAAS,KAAA,IAAY,UAAU,oBAAA,UAAA,EAAA,UAAG,KAAO,CAAA;AAClD;AASA,MAAM,mBAAmB,EAAE,MAAM,cAAqB;CACpD,MAAM,SAAS,WAAW,sBAAsB;CAEhD,IAAI,CAAC,QACH,OAAO;CAKT,OACE,oBAAC,eAAD;EAAe,gBAAgB;EAC7B,UAAA,oBAAC,kBAAD;GAA0B;GAAc;GAAe;EAAU,CAAA;CACpD,CAAA;AAEnB;;;ACbA,MAAM,YAAY,EAChB,SACA,YAAY,IACZ,cAAc,IACd,cAAc,SACd,gBAAgB,OAChB,SACA,SACA,OACA,kBAAkB,OAClB,eACW;CAGX,MAAM,SAAS,kBAAkB,gBAAgB,KAAK,SAAS,OAAO;CACtE,MAAM,UAAU;EAAE,IAAI;EAAW,MAAM;EAAa,MAAM;CAAY;CAQtE,MAAM,EAAE,KAAK,YAAY,KAAK,eAAe,mBAC3C,SACA,mBAAmB,CAAC,aACtB;CAEA,MAAM,kBAAkB,cAA+B;EACrD,OAAO,WAAW,SAAS,SAAS,IAAI;CAC1C;CAMA,IAAI,eACF,OACE,oBAAC,iBAAD;EACE,MAAM;GAAE;GAAS,QAAQ;EAAS;EAClC,SACE,oBAACC,SAAD;GACE,SAAQ;GACR,OAAM;EACP,CAAA;CAEJ,CAAA;CAIL,IAAI,QAAQ,OACV,OACE,oBAAC,iBAAD;EACE,MAAM;GAAE;GAAS,QAAQ;GAAW,SAAS,OAAO;EAAM;EAC1D,SAAS,oBAACA,SAAD;GAAW,SAAS,OAAO;GAAO,OAAM;EAAiB,CAAA;CACnE,CAAA;CAIL,MAAM,YAAY,QAAQ,SAAS;CAEnC,IAAI,CAAC,WACH,OAAO;CAGT,OACE,oBAAC,OAAD;EAAO,GAAI;EAAO,YAAA;EACf,WAAA,cACC,oBAAC,OAAD;GACE,KAAK;GACL,WAAU;GACV,oBAAA;GA2BA,UAAA,oBAAC,eAAD;IACE,WAAW,CAAC,OAAO;IACnB,WAAW,SAAS,UAClB,oBAAC,iBAAD;KACE,MAAM;MAAE;MAAS,QAAQ;MAAW;KAAQ;KAC5C,SACE,oBAACA,SAAD;MACW;MACT,SAAS;MACT,OAAM;KACP,CAAA;IAEJ,CAAA;IAGF,UAAA,eACC,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,WAAD;KACW;KACE;IAEZ,CAAA,GACA,mBAAmB,cAAc,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAC5D,EAAA,CAAA,CACJ;GACa,CAAA;EACZ,CAAA;CAEF,CAAA;AAEX;AAQA,MAAM,aAAa,GAAY,MAAwB;CACrD,IAAI,OAAO,GAAG,GAAG,CAAC,GAChB,OAAO;CAGT,IAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,GACrC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,MAAM,MAAM,OAAO,GAAG,MAAM,EAAE,EAAE,CAAC;CAG5E,IACE,KACA,KACA,OAAO,MAAM,YACb,OAAO,MAAM,YACb,OAAO,eAAe,CAAC,MAAM,OAAO,aACpC,OAAO,eAAe,CAAC,MAAM,OAAO,WACpC;EACA,MAAM,QAAQ,OAAO,KAAK,CAAC;EAE3B,OACE,MAAM,WAAW,OAAO,KAAK,CAAC,CAAC,CAAC,UAChC,MAAM,OAAM,QACV,OAAO,GACJ,EAA8B,MAC9B,EAA8B,IACjC,CACF;CAEJ;CAEA,OAAO;AACT;AAEA,MAAM,aAAa,GAAgB,MAA4B;CAC7D,IAAI,MAAM,GACR,OAAO;CAGT,IAAI,CAAC,KAAK,CAAC,GACT,OAAO;CAKT,OAAO,CAAC,mBAAG,IAFM,IAAI,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC,CAE5C,CAAC,CAAC,CAAC,OAAM,QACrB,UAAU,EAAE,MAA0B,EAAE,IAAwB,CAClE;AACF;AAGA,MAAM,iBAAiB,MAAa,SAAyB;CAG3D,OAAO,CAAC,mBAAG,IAFM,IAAI,CAAC,GAAG,OAAO,KAAK,IAAI,GAAG,GAAG,OAAO,KAAK,IAAI,CAAC,CAElD,CAAC,CAAC,CAAC,OAAM,QACrB,QAAQ,UACJ,UAAU,KAAK,OAAO,KAAK,KAAK,IAChC,OAAO,GAAG,KAAK,MAAqB,KAAK,IAAmB,CAClE;AACF;AAEA,IAAA,mBAAe,KAAK,UAAU,aAAa;;;AC3L3C,MAAM,kBAAqD;CACzD,SAAS;CACT,WAAW;CACX,MAAM;CACN,KAAK;AACP;AAEA,MAAM,YAAY,EAChB,IACA,UACA,UACA,SACA,UAAU,WACV,QAAQ,SACR,SACA,YACA,aACA,aAAa,OACb,eACA,eACA,qBACW;CACX,MAAM,EACJ,YACA,WACA,YACA,qBACA,WACA,YACA,YACA,QACA,WACE,YAAY;EAAE;EAAI,UAAU;CAAW,CAAC;CAE5C,MAAM,QAAQ;EACZ,WAAWC,MAAI,UAAU,SAAS,SAAS;EAC3C;EACA,SAAS,aAAa,KAAM;EAC5B,QAAQ,aAAa,cAAc;CACrC;CAEA,MAAM,gBAAgB,UAAU,QAAQ,KAAK,SAAS,SAAS;CAS/D,MAAM,aAAa,MAA2C;EAC5D,WAAW,YAAY,CAAC;EAExB,IAAI,EAAE,WAAW,EAAE,iBAAiB,UAAU,EAAE,kBAC9C;EAGF,IAAI,EAAE,QAAQ,SAAS;GACrB,EAAE,eAAe;GACjB,UAAU;GAEV;EACF;EAEA,MAAM,KAAK,gBAAgB,EAAE;EAE7B,IAAI,MAAM,YAAY;GAEpB,EAAE,eAAe;GACjB,WAAW,EAAE;GAEb;EACF;EAEA,KAAK,EAAE,QAAQ,YAAY,EAAE,QAAQ,gBAAgB,aAAa;GAChE,EAAE,eAAe;GACjB,YAAY;EACd;CACF;CAIA,MAAM,WAAW,SAAgC;EAC/C,WAAW,IAAI;EACf,oBAAoB,IAAI;EACxB,UAAU,IAAI;CAChB;CAEA,MAAM,YAAY,MAAwB;EACxC,EAAE,gBAAgB;EAClB,YAAY,EAAE;CAChB;CAEA,MAAM,UAAU,MAAwB;EACtC,EAAE,gBAAgB;EAClB,UAAU,EAAE;CACd;CAEA,OACE,qBAAC,OAAD;EACE,KAAK;EACE;EACP,GAAI;EACJ,GAAI;EACO;EACF;EACT,WAAW,GACT,YACA,YAAY,oDACZ,iBAAiB,+BAEnB;EAZF,UAAA;GAcE,oBAAC,OAAD;IACE,WAAW,GACT,uBAEF;IACA,eACE,cACI,MACE,gBACE,EAAE,cAAc,eAChB,EAAE,eACF,EAAE,SACF,EAAE,OACJ,IACF,KAAA;IAEN,gBAAgB,aAAa,iBAAiB,KAAA;IAC9C,SACE,cACI,MAAK;KAEH,EAAE,gBAAgB;KAClB,gBACE,EAAE,cAAc,eAChB,EAAE,eACF,EAAE,SACF,EAAE,OACJ;IACF,IACA,KAAA;GAEP,CAAA;GACA;GACA,YACC,qBAAC,OAAD;IACE,WAAW,GACT,6BAEF;IAJF,UAAA,CAME,oBAAC,QAAD;KAAQ,MAAM,oBAAC,MAAD,CAAO,CAAA;KAAG,SAAS;IAAS,CAAA,GAC1C,oBAAC,QAAD;KAAQ,QAAA;KAAO,MAAM,oBAAC,OAAD,CAAQ,CAAA;KAAG,SAAS;IAAW,CAAA,CAC/C;;EAEN;;AAET;;;AClLA,MAAM,WAAW,EAAE,UAAU,UAAU,kBAAyB;CAC9D,MAAM,EAAE,WAAW,cAAc;CAEjC,IAAI,CAAC,QACH,OAAO;CAGT,IAAI,OAAO,KAAK,SAAS,SAAS,YAAY;EAC5C,MAAM,OAAO,OAAO,KAAK,QAAQ;EAEjC,OAAO,oBAAC,sBAAD,EAA4B,KAAO,CAAA;CAC5C;CAEA,MAAM,UAAU,SAAS,MAAK,MAAK,EAAE,OAAO,OAAO,EAAE;CAErD,IAAI,SAAS;EACX,MAAM,UAAU,gBAAgB,QAAQ,MAAM,YAAY,UAAU,EAClE,aAAa,YAAY,YAC3B,CAAC;EAED,OACE,oBAAC,UAAD;GAAU,IAAI,QAAQ;GAAI,MAAM,QAAQ;GACtC,UAAA,oBAACC,kBAAD;IACW;IACT,WAAW,QAAQ;IACnB,aAAa,QAAQ;IACrB,aAAa,QAAQ;IACrB,eAAe,WAAW,OAAO,KAAK;IACtC,SAAS,YAAY;IACrB,OAAO,YAAY;IACnB,iBAAiB,YAAY;GAC9B,CAAA;EACO,CAAA;CAEd;CAEA,OAAO;AACT;;;ACAA,MAAM,yBAAyB;CAC7B,IAAI,OAA0D;CAE9D,OAAO;EACL,OAAO,gBACL,QAAQ,KAAK,gBAAgB,cAAc,KAAK,WAAW,KAAA;EAC7D,QAAQ,aAAiC,aAAqB;GAC5D,OAAO;IAAE;IAAa;GAAS;EACjC;CACF;AACF;AASA,MAAa,sBACX,OACA,UACA,EACE,aACA,qBACA,kBAC0B,CAAC,MACT;CACpB,MAAM,EAAE,YAAY,WAAW;CAC/B,MAAM,CAAC,YAAY,iBAAiB,SAAwB,IAAI;CAIhE,MAAM,eAAe,aAClB,SACC,gBAAgB,MAAM;EAAE;EAAa;CAAoB,CAAC,GAC5D,CAAC,aAAa,mBAAmB,CACnC;CAWA,MAAM,WAAW,cACT,eAAe,OAAO,KAAA,GAAW,EAAE,YAAY,CAAC,GACtD,CAAC,aAAa,KAAK,CACrB;CAYA,MAAM,CAAC,cAAc,SAAS,gBAAgB;CAC9C,MAAM,OAAO,cAAc;EACzB,MAAM,aAAa,gBAAgB,UAAU,EAAE,YAAY,CAAC;EAE5D,IAAI,WAAW,IAAI;GACjB,WAAW,MAAM,aAAa,QAAQ;GAEtC,OAAO;IAAE;IAAU,SAAS;IAAM,OAAO;GAAM;EACjD;EAEA,MAAM,EAAE,IAAI,KAAK,GAAG,YAAY;EAChC,MAAM,OACJ,QAAQ,WAAW,gBACf,WAAW,KAAK,WAAW,IAC3B,KAAA;EAEN,OAAO;GAAE,UAAU,QAAQ;GAAU;GAAS,OAAO,SAAS,KAAA;EAAU;CAC1E,GAAG;EAAC;EAAa;EAAU;CAAU,CAAC;CAEtC,MAAM,WAAW,cACT,aAAa,KAAK,QAAQ,GAChC,CAAC,cAAc,KAAK,QAAQ,CAC9B;CASA,MAAM,CAAC,gBAAgB,eAAe,0BAA0B,CAAC;CACjE,MAAM,WAAW,cACT,aAAa,QAAQ,KAAK,UAAU,UAAU,EAAE,YAAY,CAAC,GACnE;EAAC;EAAa;EAAc;EAAU,KAAK;CAAQ,CACrD;CAEA,MAAM,gBAAgB,SAAS,WAAU,MAAK,EAAE,OAAO,UAAU;CACjE,MAAM,eAAe,iBAAiB,IAAI,SAAS,iBAAiB,KAAA;CAYpE,MAAM,aAAa,OAA8C,IAAI;CAErE,gBAAgB;EACd,WAAW,UAAU;CACvB,CAAC;CAED,MAAM,iBAAiB,kBAAkB;EACvC,MAAM,UAAU,WAAW;EAE3B,OAAO,SAAS,SAAS,WAAW,QAAQ,OAAO;CACrD,GAAG,CAAC,QAAQ,CAAC;CAIb,MAAM,iBAAiB,kBACf,aAAa,eAAe,CAAC,GACnC,CAAC,gBAAgB,YAAY,CAC/B;CAYA,MAAM,SAAS,aACZ,iBAAgD;EAC/C,MAAM,WAAW,eACf,gBACE,eAAe,GACf,aAAa,KAAI,MAAK,EAAE,IAAI,GAC5B,EAAE,YAAY,CAChB,GACA,KAAA,GACA,EAAE,YAAY,CAChB;EAEA,WAAW,UAAU;GAAE,MAAM;GAAU,MAAM;EAAS;EACtD,WAAW,QAAQ;EACnB,QAAQ,QAAQ;EAEhB,OAAO,aAAa,QAAQ;CAC9B,GACA;EAAC;EAAa;EAAU;EAAgB;EAAU;EAAc;CAAO,CACzE;CAEA,MAAM,sBAAsB,aACzB,OAAe;EACd,MAAM,UAAU,WAAW;EAE3B,IAAI,SAAS,SAAS,UACpB;EAGF,OAAO,aAAa,QAAQ,IAAI,CAAC,CAAC,MAAK,MAAK,EAAE,OAAO,EAAE;CACzD,GACA,CAAC,UAAU,YAAY,CACzB;CAMA,MAAM,EAAE,SAAS,UAAU;CAC3B,MAAM,SAAS,kBAAkB;EAC/B,IAAI,CAAC,SAAS,CAAC,SACb,OAAO;EAGT,gBAAgB,OAAO;EAEvB,OAAO;CACT,GAAG;EAAC;EAAe;EAAS;CAAK,CAAC;CAiJlC,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,QArJa,aAAa,OAAe;GACzC,eAAc,SAAS,SAAS,KAAK,OAAO,EAAG;EACjD,GAAG,CAAC,CAmJG;EACL,YAlJiB,aAAa,OAAe,cAAc,EAAE,GAAG,CAAC,CAkJxD;EACT,gBAjJqB,kBAAkB,cAAc,IAAI,GAAG,CAAC,CAiJhD;EACb,KAhJU,aACT,MAAsC,YAAqB;GAC1D,IAAI,OAAO,GACT;GAGF,MAAM,UAAU,eAAe;GAC/B,MAAM,OAAO,EAAE,MAAM,KAAK,KAAK;GAE/B,OACE,YAAY,KAAA,KAAa,UAAU,IAC/B,CAAC,GAAG,SAAS,IAAI,IACjB;IAAC,GAAG,QAAQ,MAAM,GAAG,OAAO;IAAG;IAAM,GAAG,QAAQ,MAAM,OAAO;GAAC,CACpE;EACF,GACA;GAAC;GAAQ;GAAQ;EAAc,CAiI7B;EACF,QA/Ha,aACZ,OAAe;GACd,IAAI,OAAO,GACT;GAGF,MAAM,UAAU,eAAe;GAM/B,MAAM,QAAQ,QAAQ,WAAU,MAAK,EAAE,OAAO,EAAE;GAEhD,IAAI,QAAQ,GACV;GAMF,IAAI,OAAO,YACT,cAAc,IAAI;GAGpB,OAAO,QAAQ,QAAQ,GAAG,MAAM,MAAM,KAAK,CAAC;EAC9C,GACA;GAAC;GAAQ;GAAQ;GAAgB;EAAU,CAoGtC;EACL,MAlGW,aACV,OAAe;GACd,IAAI,OAAO,GACT;GAGF,MAAM,UAAU,eAAe;GAE/B,MAAM,QAAQ,QAAQ,WAAU,MAAK,EAAE,OAAO,EAAE;GAChD,MAAM,SAAS,QAAQ;GAEvB,IAAI,CAAC,QACH;GAKF,MAAM,YAAY,OAAO;IACvB,GAAG,QAAQ,MAAM,GAAG,QAAQ,CAAC;IAC7B,EAAE,MAAM,WAAW,OAAO,IAAI,EAAE;IAChC,GAAG,QAAQ,MAAM,QAAQ,CAAC;GAC5B,CAAC;GAMD,cAAc,UAAU,QAAQ,EAAE,EAAE,MAAM,IAAI;EAChD,GACA;GAAC;GAAQ;GAAQ;EAAc,CAqE5B;EACH,MAnEW,aACV,IAAmB,cAA6B;GAC/C,IAAI,OAAO,GACT;GAGF,MAAM,UAAU,eAAe;GAE/B,MAAM,QAAQ,QAAQ,WAAU,MAAK,EAAE,OAAO,EAAE;GAChD,MAAM,cAAc,cAAc,OAAO,QAAQ,IAAI,QAAQ;GAE7D,IAAI,QAAQ,KAAK,cAAc,KAAK,eAAe,QAAQ,QACzD;GAKF,OAAO,UAAU,SAAS,OAAO,WAAW,CAAC;EAC/C,GACA;GAAC;GAAQ;GAAQ;EAAc,CAgD5B;EACH,SA9Cc,aACb,UAAkB,WAAmB;GACpC,IAAI,OAAO,GACT;GAGF,MAAM,UAAU,eAAe;GAE/B,MAAM,YAAY,QAAQ,WAAU,MAAK,EAAE,OAAO,QAAQ;GAC1D,MAAM,YAAY,QAAQ,WAAU,MAAK,EAAE,OAAO,MAAM;GAExD,IAAI,YAAY,KAAK,YAAY,KAAK,cAAc,WAClD;GAGF,OAAO,UAAU,SAAS,WAAW,SAAS,CAAC;EACjD,GACA;GAAC;GAAQ;GAAQ;EAAc,CA6BzB;EACN,OA3BY,aACX,SAA4C;GAC3C,IAAI,OAAO,GACT;GAGF,MAAM,UAAU,eAAe;GAE/B,OAAO,QAAQ,KAAI,MAAM,EAAE,OAAO,KAAK,KAAK;IAAE,GAAG;IAAG,GAAG;GAAK,IAAI,CAAE,CAAC;EACrE,GACA;GAAC;GAAQ;GAAQ;EAAc,CAiB3B;EACJ;EACA;EACA;CACF;AACF;;;ACnUA,MAAM,yBACJ,SACA,UAC4C;CAC5C,QAAQ,SAAS,QAAjB;EACE,KAAK,uBACH,OAAO;GACL,OAAO,qBAAqB,MAAM;GAClC,aAAa,wBAAwB,QAAQ,SAAS;EACxD;EACF,KAAK,wBACH,OAAO;GACL,OAAO,qBAAqB,MAAM;GAClC,aAAa,kBACX,QAAQ,WACJ,aAAa,QAAQ,SAAS,KAC9B,UAAU,MAAM,GACrB;EACH;EACF,KAAK,qBACH,OAAO;GACL,OAAO,qBAAqB,MAAM;GAClC,aAAa,GAAG,QAAQ,MAAM,kBAC5B,QAAQ,WACJ,aAAa,QAAQ,SAAS,KAC9B,UAAU,MAAM,GACrB;EACH;EACF,KAAK,qBACH,OAAO;GACL,OAAO,gBAAgB,MAAM;GAC7B,aAAa,IAAI,QAAQ,SAAS;EACpC;EACF,KAAK,qBACH,OAAO;GACL,OAAO,kBAAkB,MAAM;GAC/B,aAAa,IAAI,QAAQ,SAAS;EACpC;EACF,KAAK,cACH,OAAO;GACL,OAAO,qBAAqB,MAAM;GAClC,aAAa;EACf;EACF,KAAK,qBACH,OAAO;GACL,OAAO,qBAAqB,MAAM;GAClC,aAAa;EACf;EACF,KAAK,sBACH,OAAO;GACL,OAAO,gBAAgB,MAAM;GAC7B,aAAa,QAAQ,QAAQ,SAAS;EACxC;EACF,KAAK,eACH,OAAO;GACL,OAAO,qBAAqB,MAAM;GAClC,aACE,QAAQ,iBAAiB,QACrB,QAAQ,MAAM,UACd;EACR;EACF,SACE,OAAO,EAAE,OAAO,qBAAqB,MAAM,GAAG;CAClD;AACF;AAGA,MAAM,iBAAiB;CACrB,OAAO,CAAC,OAAO;CACf,QAAQ,CAAC,QAAQ;CACjB,KAAK,CAAC,SAAS,OAAO;AACxB;AAEA,MAAM,6BAAuD,EAC3D,WACE,wTACJ;AAKA,MAAM,2BAA2B;CAC/B,MAAM,wBAAQ,IAAI,IAAyB;CAC3C,MAAM,4BAAY,IAAI,IAAgD;CAEtE,OAAO;EACL,MAAM,OAAe,MAAM,IAAI,EAAE;EACjC,WAAW,OAAe;GACxB,IAAI,WAAW,UAAU,IAAI,EAAE;GAE/B,IAAI,CAAC,UAAU;IACb,YAAW,SAAQ;KACjB,IAAI,MACF,MAAM,IAAI,IAAI,IAAI;UACb;MAGL,MAAM,OAAO,EAAE;MACf,UAAU,OAAO,EAAE;KACrB;IACF;IACA,UAAU,IAAI,IAAI,QAAQ;GAC5B;GAEA,OAAO;EACT;CACF;AACF;AAGA,MAAM,oBAAoB,WAAkC;CAC1D,MAAM;CACN,QAAQ;CACR,QAAQ;CACR;CACA,OAAO;CACP,aACE;AACJ;AAuIA,MAAM,wBAAiC,SAAQ;CAC7C,MAAM,EAAE,WAAW;CAEnB,IAAI,QAAQ,KAAK,SAAS,SAAS,YACjC,OAAO,KAAK;CAGd,OAAO,uBAAuB,IAAI;AACpC;AAOA,MAAM,aAAsC,CAAC;AAE7C,MAAMC,SAAO,EACX,OAAO,QACP,OACA,SAAS,WAAW,YACpB,UAAU,WACV,WACA,QAAQ,CAAC,GACT,OACA,kBAAkB,OAClB,UACA,aACA,aACA,uBACA,4BACA,gBACA,qBACA,aACA,YACA,UACA,GAAG,gBACQ;CACX,MAAM,UAAU,iBAAiB,QAAQ;CACzC,MAAM,CAAC,mBAAmB,wBAAwB,SAAS,KAAK;CAEhE,MAAM,EAAE,eAAe,kBAAkB;CACzC,MAAM,WAAW,WAAW,YAAY,QAAQ,WAAW,YAAY;CAOvE,MAAM,EAAE,SAAS,WAAW;CAI5B,MAAM,YAAY,YAAqB;EACrC,IAAI;GACF,OAAO,6BAA6B,OAAO,MAAM;EACnD,SAAS,OAAO;GACd,QAAQ,MAAM,oCAAoC,KAAK;GAEvD,OAAO;EACT;CACF;CAOA,MAAM,UAAU,WACd,UAAU,eAAe,EACvB,sBAAsB,EACpB,UAAU,GACZ,EACF,CAAC,GACD,UAAU,gBAAgB;EACxB,kBAAkB;EAClB,eAAe;CACjB,CAAC,CACH;CAGA,MAAM,UAAU,IAAqB,SAAiC;EAGpE,QAFgB,MAAM,QAAA,EAGX,MAAM,QACf,SAAS,MAAK,YAAW,QAAQ,OAAO,EAAE,CAAC,EAAE,QAC7C;CAEJ;CAEA,MAAM,cAAc,OAClB,SAAS,WAAU,YAAW,QAAQ,OAAO,EAAE,IAAI;CAErD,MAAM,gBAA+B;EACnC,cAAc,EAAE,aAAa,aAAa,OAAO,OAAO,IAAI,OAAO,IAAI,EAAE;EACzE,aAAa,EAAE,QAAQ,WACrB,QAAQ,WAAW,KAAK,EAAE,IAAI,IAC1B,GAAG,OAAO,OAAO,IAAI,OAAO,IAAI,EAAE,qBAAqB,WAAW,KAAK,EAAE,EAAE,MAAM,SAAS,OAAO,KACjG,GAAG,OAAO,OAAO,IAAI,OAAO,IAAI,EAAE;EACxC,YAAY,EAAE,QAAQ,WACpB,QAAQ,WAAW,KAAK,EAAE,IAAI,IAC1B,GAAG,OAAO,OAAO,IAAI,OAAO,IAAI,EAAE,uBAAuB,WAAW,KAAK,EAAE,EAAE,MAAM,SAAS,OAAO,KACnG,GAAG,OAAO,OAAO,IAAI,OAAO,IAAI,EAAE;EACxC,eAAe,EAAE,aACf,UAAU,OAAO,OAAO,IAAI,OAAO,IAAI,EAAE;CAC7C;CAUA,MAAM,QAAQ,WAAW,KAAA,IAAY,OAAO;CAE5C,MAAM,cAAc,eAAe;CAInC,MAAM,iBAAiB,OAAO,WAAW;CAEzC,gBAAgB;EACd,eAAe,UAAU;CAC3B,CAAC;CAKD,MAAM,gBAAgB,aAAa,YAA6B;EAC9D,IAAI,QAAQ,WAAW,eACrB,eAAe,QAAQ,iBAAiB,QAAQ,KAAK,CAAC;CAE1D,GAAG,CAAC,CAAC;CAEL,MAAM,EACJ,UACA,UACA,YACA,cACA,eACA,QACA,YACA,gBACA,KAAK,SACL,QACA,MAAM,QACN,MAAM,aACN,SACA,OACA,qBACA,SACA,UACE,mBAAmB,OAAO,WAAW;EACvC;EACA;EACA;CACF,CAAC;CAGD,MAAM,mBACJ,SAAS,WAAW,wBAAwB,QAAQ,cAAc;CAEpE,MAAM,eAAe,MAAsB,CAAC;CAE5C,MAAM,cAAc,OAAsB,CAAC;CAE3C,MAAM,aAAa,UAAwB;EACzC,MAAM,EAAE,QAAQ,SAAS;EAEzB,IAAI,CAAC,MACH;EAGF,IAAI,OAAO,KAAK,SAAS,SAAS,YAAY;GAC5C,MAAM,OAAO,OAAO,KAAK,QAAQ;GACjC,MAAM,WACJ,KAAK,OAAO,mBAAmB,KAAK,OAAO;GAE7C,QACE,MACA,WAAW,KAAA,IAAY,SAAS,WAAU,MAAK,EAAE,OAAO,KAAK,EAAE,CACjE;GACA;EACF;EAEA,IAAI,OAAO,OAAO,KAAK,MAAM,SAAS,MAAK,MAAK,EAAE,OAAO,OAAO,EAAE,GAChE,QAAQ,OAAO,OAAO,EAAE,GAAG,OAAO,KAAK,EAAE,CAAC;CAE9C;CAEA,MAAM,YAAY,OAAe,OAAO,EAAE;CAI1C,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAClD,MAAM,CAAC,QAAQ,aAAa,SAA6B,IAAI;CAC7D,MAAM,CAAC,WAAW,gBAAgB,SAAyB,IAAI;CAE/D,IAAI,UAAU,OAAO,cAAc,YACjC,UAAU,IAAI;CAGhB,MAAM,iBAAiB,kBAAkB;EACvC,cAAc,KAAK;EACnB,aAAa,IAAI;CACnB,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,IAAI,CAAC,YACH;EAGF,MAAM,aAAa,MAAqB;GACtC,IAAI,EAAE,QAAQ,UACZ,eAAe;EAEnB;EAEA,OAAO,iBAAiB,WAAW,SAAS;EAE5C,aAAa,OAAO,oBAAoB,WAAW,SAAS;CAC9D,GAAG,CAAC,YAAY,cAAc,CAAC;CAE/B,MAAM,YAA0B;EAC9B,QAAQ;EACR,gBAAgB,cAAc,IAAI;EAClC,YAAY;EACZ,cAAe,aAAa,eAAe,IAAI,cAAc,IAAI;EACjE;CACF;CAEA,MAAM,iBACJ,SACA,SACA,GACA,MACG;EACH,MAAM,UAAU,YAAY,SAAS,SAAS,GAAG,CAAC;EAElD,aAAa,UAAU,aAAa,OAAO,IAAI,IAAI;CACrD;CAEA,MAAM,iBACJ,WACA,SACA,SACA,GACA,MACG;EACH,MAAM,KAAK,YAAY,SAAS,SAAS,GAAG,CAAC,CAAC,EAAE,aAAa,UAAU,EAAE;EAEzE,IAAI,CAAC,IACH;EAGF,MAAM,OAAO;GAAE;GAAI;EAAU;EAE7B,WAAW,SAAS;EACpB,UAAU,IAAI;EACd,eAAe;EACf,aAAa,IAAI;CACnB;CAKA,MAAM,YAAY,OAAO,MAAM;CAE/B,gBAAgB;EACd,UAAU,UAAU;CACtB,CAAC;CAID,MAAM,iBAAiB,IAAY,cAA2B;EAC5D,MAAM,UAAU,SAAS,MAAK,cAAa,UAAU,OAAO,EAAE;EAE9D,IAAI,CAAC,kBAAkB,CAAC,SAAS;GAC/B,OAAO,EAAE;GACT,YAAY;GAEZ;EACF;EAEA,MAAM,UAAU,YAAqB;GACnC,IAAI,SAAS;IACX,UAAU,QAAQ,EAAE;IACpB,YAAY;GACd;EACF;EAEA,IAAI;GACF,MAAM,SAAS,eAAe,OAAO;GAErC,IAAI,OAAO,WAAW,WAAW;IAC/B,OAAO,MAAM;IAEb;GACF;GAEA,OAAO,KAAK,SAAQ,UAAS;IAC3B,QAAQ,MAAM,iDAAiD,KAAK;GACtE,CAAC;EACH,SAAS,OAAO;GACd,QAAQ,MAAM,8CAA8C,KAAK;EACnE;CACF;CAEA,MAAM,YAAY,OAAe,cAAc,EAAE;CAIjD,MAAM,CAAC,gBAAgB,SAAS,kBAAkB;CAGlD,MAAM,gBAAgB,OAAe,aAAa,IAAI,EAAE,CAAC,EAAE,MAAM;CAIjE,MAAM,cAAc,QAAgB,OAA0B;EAC5D,MAAM,OAAO,SAAS,WAAU,YAAW,QAAQ,OAAO,MAAM;EAChE,MAAM,QACJ,OAAO,UACH,IACA,OAAO,SACL,SAAS,SAAS,IAClB,QAAQ,OAAO,SAAS,IAAI;EACpC,MAAM,SAAS,SAAS;EAExB,IAAI,OAAO,KAAK,CAAC,UAAU,OAAO,OAAO,QACvC;EAGF,WAAW,OAAO,EAAE;EACpB,aAAa,OAAO,EAAE;CACxB;CAKA,MAAM,eAAe,OAAe;EAClC,MAAM,QAAQ,SAAS,WAAU,YAAW,QAAQ,OAAO,EAAE;EAC7D,MAAM,WAAW,SAAS,QAAQ,MAAM,SAAS,QAAQ;EAEzD,cAAc,UAAU;GACtB,IAAI,UACF,aAAa,SAAS,EAAE;EAE5B,CAAC;CACH;CAKA,gBAAgB;EACd,IAAI,eAAe,MACjB;EAGF,MAAM,QAAQ,4BAA4B;GACxC,aAAa,IAAI,UAAU,CAAC,EAAE,iBAAiB,EAAE,OAAO,UAAU,CAAC;EACrE,CAAC;EAED,aAAa,qBAAqB,KAAK;CACzC,GAAG;EAAC;EAAc;EAAY;CAAa,CAAC;CAE5C,MAAM,YAAY,SAA2B;EAC3C,IAAI,CAAC,KAAK,IACR;EAGF,MAAM,IAAyC;CACjD;CAQA,MAAM,eAAe,cAAc;CACnC,MAAM,oBAAoB,cAAc;CACxC,MAAM,EAAE,QAAQ,aAAa,eAAe,cAAc;EACxD,IAAI,CAAC,cACH,OAAO;GACL,QAAQ,CAAC;GACT,aAAa;GACb,YAAY;EACd;EAGF,IAAI;GAGF,MAAM,UAAU,YAAY,cAAc,qBAAqB,EAAE;GAOjE,OAAO;IACL,QAHe,QAAQ,OAGR;IACf,aAAa,YAAY,eAAe,UAAU;IAClD,YAAY;GACd;EACF,SAAS,GAAG;GACV,QAAQ,KAAK,oBAAoB,CAAC;GAClC,OAAO;IACL,QAAQ,CAAC;IACT,aAAa;IACb,YAAY,EAAE,OAAO,EAAE;GACzB;EACF;CACF,GAAG,CAAC,cAAc,iBAAiB,CAAC;CAIpC,gBAAgB;EACd,IAAI,qBAAqB,MACvB,eAAe,QAAQ;GACrB,MAAM;GACN,QAAQ;GACR,QAAQ;GACR,aAAa;GACb,OAAO,OAAO,iBAAiB;GAC/B,aAAa,mEAAmE,iBAAiB;EACnG,CAAC;CAEL,GAAG,CAAC,gBAAgB,CAAC;CAErB,gBAAgB;EACd,IAAI,YACF,eAAe,QAAQ;GACrB,MAAM;GACN,QAAQ;GACR,OAAO,WAAW;GAClB,OAAO;GACP,aAAa;EACf,CAAC;CAEL,GAAG,CAAC,UAAU,CAAC;CAKf,MAAM,iBAAiB,YAA8C;EACnE,IAAI,QAAQ,WAAW,GACrB;EAKF,IAAI,SAAS,SAAS,WAAW,eAAe;GAC9C,YAAY,iBAAiB,QAAQ,KAAK,CAAC;GAC3C;EACF;EAQA,MAAM,YACJ,gBAAgB,oBAAoB,aAAa,EAAE,CAAC,EAAE;EAGxD,MAAM,SAAS,UADb,aAAa,cAAc,eAAe,YAAY,aAGtD,QAAQ,KAAK,EAAE,IAAI,OAAO,UAAU,OAAO,mBAAmB;GAC5D,QAAQ;GACR;GACA;GACA,OAAO;EACT,EAAE,CACJ;EAEA,IAAI,CAAC,OAAO,SAAS;GACnB,MAAM,EAAE,IAAI,OAAO,aAAa,QAAQ,OAAO;GAE/C,YAAY;IACV,MAAM;IACN;IACA;IACA;IACA,SAAS,OAAO;IAChB,GAAG,sBAAsB,OAAO,SAAS,KAAK;GAChD,CAAC;GACD;EACF;EAEA,IAAI,cACF,SAAS;GAAE,GAAG;GAAc,MAAM,OAAO;EAAK,CAAC;CAEnD;CAEA,MAAM,iBAAiC,WAAU,cAAc,CAAC,MAAM,CAAC;CAevE,MAAM,gBAAgB,cACd,OAAO,SAAQ,SAAQ,qBAAqB,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC,GACvE,CAAC,MAAM,CACT;CAWA,MAAM,WAA2B,gBAC/B,eACA,aACF;CAEA,gBAAgB;EACd,IAAI,OAAO,SAAS,QAClB,eAAe,MAAM,OAAO;CAEhC,GAAG,CAAC,OAAO,OAAO,CAAC;CAMnB,MAAM,UAAsB;EAC1B,OAAO,OAAO,SAAS,QAAQ;EAC/B,QAAQ,SAAkB;GACxB,QAAQ,IAAI;GACZ,qBAAqB,KAAK;EAC5B;CACF;CAEA,MAAM,QAAkB;EACtB,MAAM;EACN;EACA;EACA,gBAAgB,YAAY,YAAY,IAAI;EAC5C,kBAAkB,YAAY,YAAY,MAAM;EAChD,WAAW,gBAAgB;EAC3B,aAAa,iBAAiB,KAAK,gBAAgB,SAAS,SAAS;EACrE;EACA,cAAc;EACd,eAAe;EACf,UAAU;CACZ;CAKA,MAAM,SACJ,qBAAA,UAAA,EAAA,UAAA,CACG,SACC,oBAAC,OAAD;EACE,MAAK;EACL,WAAW,GACT,qBACA,mDACA,wBACF;EACD,UAAA;CAGI,CAAA,GAEP,oBAAC,WAAD;EACE,WAAW,GACT,CAAC,SAAS,UAAU,QAEtB;EAEC,UAAA,CAAC,SAAS,SACT,oBAAC,OAAD;GACE,WAAW,GACT,oCACA,UACA,eACF;GAEC,UAAA,SAAS,WAAW,gBACnB,qBAAC,OAAD;IAAO,aAAY;IAAW,OAAM;IAApC,UAAA,CACE,oBAAC,WAAW,WAAZ,EAAA,UAAsB,kCAEA,CAAA,GACtB,oBAAC,WAAW,MAAZ,EAAA,UAAiB,yCAEA,CAAA,CACZ;GACL,CAAA,IAAA,qBAAqB,OACvB,qBAAC,OAAD;IAAO,aAAY;IAAW,OAAM;IAApC,UAAA,CACE,qBAAC,WAAW,WAAZ,EAAA,UAAA;KAAsB;KACf;KAAiB;IACF,EAAA,CAAA,GACtB,qBAAC,WAAW,MAAZ,EAAA,UAAA;KAAiB;KAEd;KAAiB;IACH,EAAA,CAAA,CACZ;GAEP,CAAA,IAAA,qBAAC,OAAD;IAAO,aAAY;IAAW,OAAM;IAApC,UAAA,CACE,oBAAC,WAAW,WAAZ,EAAA,UAAsB,wBAEA,CAAA,GACtB,oBAAC,WAAW,MAAZ,EAAA,UACG,WACG,8BACA,2CACW,CAAA,CACZ;;EAEN,CAAA,IAEL,oBAAC,iBAAD;GACE,OAAO,SAAS,KAAI,MAAK,EAAE,EAAE;GAC7B,UAAU;GAET,UAAA,SAAS,KAAK,SAAS,UACtB,oBAAC,UAAD;IAEE,IAAI,QAAQ;IACZ,MAAM,QAAQ;IACd,UAAU,eAAe,QAAQ;IACjC,eAAe,SAAS,QAAQ,EAAE;IACxB;IACF;IACR,SAAS,aAAa,SAAS,QAAQ,EAAE;IACzC,aAAY,OAAM,WAAW,QAAQ,IAAI,EAAE;IAC3C,mBAAmB,YAAY,QAAQ,EAAE;IAC7B;IACG;IACf,gBAAgB,GAAG,SAAS,cAAc,QAAQ,IAAI,GAAG,IAAI;IAC7D,sBAAsB,aAAa,IAAI;IAEvC,UAAA,oBAACC,kBAAD;KACE,SAAS,SAAS;KAClB,WAAW,QAAQ;KACnB,aAAa,QAAQ;KACrB,aAAa,QAAQ;KACrB,eAAe,SAAS,OAAO;KACtB;KACF;KACU;KACP;KACV,GAAI;IACL,CAAA;GACO,GA3BH,QAAQ,EA2BL,CACX;EACc,CAAA;CAEV,CAAA,CACX,EAAA,CAAA;CAGJ,OACE,oBAAC,uBAAuB,UAAxB;EAAiC,OAAO;EACtC,UAAA,qBAAC,YAAD;GACW;GACT,oBAAoB;GACpB,eAAe;IACb;IACA,0BAA0B;GAC5B;GACA,WAAW,CACT,oBAEF;GACa;GACD;GACD;GAbb,UAAA,CAeE,oBAAC,OAAD;IACE,WAAW,GACT,+BACA,SAEF;IACA,GAAI;IAKJ,UAAA,qBAAC,sBAAsB,UAAvB;KAAgC,OAAO;MAAE;MAAa;KAAY;KAAlE,UAAA,CACE,oBAAC,iBAAiB,UAAlB;MACE,OAAO;OACL;OACA;OACA;OACA;OACA;OACA;OACA,aAAa;OACb,gBAAgB;OAChB,eAAe,SAAS,UAAU;MACpC;MAQA,UAAA,oBAAC,oBAAoB,UAArB;OAA8B,OAAO;OAClC,UAAA,SAAS,QAAQ,QAAQ,CAAC,CAAC,SAAS,WAAW,oBAAC,QAAD,CAAS,CAAA;MAC7B,CAAA;KACL,CAAA,GAC3B,oBAAC,oBAAD,EAAoB,MAAM,aAAa,YAAY,KAAO,CAAA,CAC5B;;GAC7B,CAAA,GACL,oBAAC,aAAD,EAAA,UACE,oBAAC,SAAD;IACY;IACA;IACV,aAAa;KACX,UAAU;KACV;KACA;KACA;KACA,GAAG;KAGH;IACF;GACD,CAAA,EACU,CAAA,CACH;;CACmB,CAAA;AAErC;;;AC3+BA,MAAM,MAAMC;AAEZ,IAAI,gBAAgB;AACpB,IAAI,QAAQ;AACZ,IAAI,UAAU;AACd,IAAI,SAAS;AACb,IAAI,QAAQ;AACZ,IAAI,SAAS;;AAyCb,MAAa,iBAAiB;;AAE9B,MAAa,oBAAoB"}