@jbpark/live-editor 3.2.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ast-CZwpVrJv.js +851 -0
- package/dist/ast-CZwpVrJv.js.map +1 -0
- package/dist/{boundary-BTP1nfG6.js → boundary-C90q3YsT.js} +8 -7
- package/dist/boundary-C90q3YsT.js.map +1 -0
- package/dist/{context-649REFsj.js → context-Y-M9fViD.js} +4 -8
- package/dist/context-Y-M9fViD.js.map +1 -0
- package/dist/{core-D3q5rpuz.js → core-Co8Nlq16.js} +2 -2
- package/dist/{core-D3q5rpuz.js.map → core-Co8Nlq16.js.map} +1 -1
- package/dist/dnd/index.d.ts +2 -2
- package/dist/dnd/index.js +2 -2
- package/dist/{dnd-D90jLjLH.js → dnd-ClnGRNaY.js} +353 -319
- package/dist/dnd-ClnGRNaY.js.map +1 -0
- package/dist/editor/index.js +2 -2
- package/dist/{editor-LzqHe_-F.js → editor-COKGtmfE.js} +3 -3
- package/dist/{editor-LzqHe_-F.js.map → editor-COKGtmfE.js.map} +1 -1
- package/dist/error/index.d.ts +1 -1
- package/dist/error/index.js +2 -2
- package/dist/{error-CO0EbMlA.js → error-o0SBwtTv.js} +2 -2
- package/dist/{error-CO0EbMlA.js.map → error-o0SBwtTv.js.map} +1 -1
- package/dist/{document-C6bNHl7l.js → extract-abHYmNsu.js} +927 -42
- package/dist/extract-abHYmNsu.js.map +1 -0
- package/dist/{index-DxbG789f.d.ts → index-B_p74BRM.d.ts} +29 -14
- package/dist/{index-CCynrS6c.d.ts → index-DNNj_0ba.d.ts} +3 -2
- package/dist/{index-lgHdCda5.d.ts → index-DQkL37eL.d.ts} +10 -2
- package/dist/{index-DswWDEXZ.d.ts → index-Doh4VTXr.d.ts} +65 -35
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/preview/index.d.ts +2 -2
- package/dist/preview/index.js +3 -2
- package/dist/{preview-CWT0lgwq.js → preview-DKyKKcu7.js} +4 -4
- package/dist/{preview-CWT0lgwq.js.map → preview-DKyKKcu7.js.map} +1 -1
- package/dist/provider/index.js +1 -1
- package/dist/{use-dynamic-tailwind-DAhKGsY4.js → use-dynamic-tailwind-BF8TQ3Yy.js} +83 -27
- package/dist/use-dynamic-tailwind-BF8TQ3Yy.js.map +1 -0
- package/dist/utils/ast/index.d.ts +2 -2
- package/dist/utils/ast/index.js +3 -3
- package/dist/utils/index.d.ts +4 -7
- package/dist/utils/index.js +3 -3
- package/dist/{utils-WyxPYZGh.js → utils-BQ7WL7Jh.js} +33 -16
- package/dist/{utils-WyxPYZGh.js.map → utils-BQ7WL7Jh.js.map} +1 -1
- package/package.json +3 -1
- package/dist/ast-Bx2Avo4d.js +0 -1530
- package/dist/ast-Bx2Avo4d.js.map +0 -1
- package/dist/boundary-BTP1nfG6.js.map +0 -1
- package/dist/context-649REFsj.js.map +0 -1
- package/dist/dnd-D90jLjLH.js.map +0 -1
- package/dist/document-C6bNHl7l.js.map +0 -1
- package/dist/use-dynamic-tailwind-DAhKGsY4.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-CZwpVrJv.js","names":["t","t","parseExpression","parseExpression","t","t","parseExpression","parse","t","parseExpression"],"sources":["../src/utils/selection.ts","../src/utils/ast/patch.ts","../src/utils/ast/array-source.ts","../src/utils/ast/items.ts","../src/utils/ast/children.ts","../src/utils/ast/update.ts","../src/utils/ast/tree.ts","../src/utils/ast/validate.ts"],"sourcesContent":["export const removeIndices = <T>(items: T[], indices: Set<number>): T[] => {\n return items.filter((_, index) => !indices.has(index));\n};\n\n/**\n * Shifts every selected index up/down by one step as a block, preserving\n * relative order — scattered selections stop moving individually once they\n * hit an unselected neighbor, so the whole group slides together instead of\n * items passing through each other.\n */\nexport const moveSelectedIndices = <T>(\n items: T[],\n indices: Set<number>,\n direction: 'up' | 'down',\n): { items: T[]; indices: Set<number> } => {\n const next = [...items];\n const nextIndices = new Set(indices);\n\n const ordered = [...indices].sort((a, b) =>\n direction === 'up' ? a - b : b - a,\n );\n\n for (const index of ordered) {\n const target = direction === 'up' ? index - 1 : index + 1;\n\n if (target < 0 || target >= next.length || nextIndices.has(target)) {\n continue;\n }\n\n [next[index], next[target]] = [next[target]!, next[index]!];\n nextIndices.delete(index);\n nextIndices.add(target);\n }\n\n return { items: next, indices: nextIndices };\n};\n","// Positional source patching: the write-side counterpart to `extract`'s\n// read-side `loc`. `update` records the exact byte spans it wants to change\n// and everything else is copied through verbatim, so an edit can no longer\n// reformat code it didn't touch. See #239.\n//\n// Deliberately not `magic-string`: it is the usual tool for this, but it is\n// only available here transitively (via Vite) and would have to become a\n// real runtime dependency shipped to consumers' browsers. Its value is\n// source maps and interleaved insert/move semantics — neither of which this\n// needs. Edits here are non-overlapping span replacements applied in one\n// forward pass, which is the whole implementation below.\nexport interface SourceEdit {\n start: number;\n end: number;\n content: string;\n // Re-indent `content`'s continuation lines to the indentation of the line\n // it lands on. Opt-in because it must apply to *generated* fragments only:\n // a generated fragment is printed from column zero and would otherwise\n // land ragged inside indented markup, whereas a raw user-authored value\n // (an innerHTML string, a hand-written JSX attribute) has to go in byte\n // for byte — re-indenting it would silently rewrite the value itself.\n //\n // Even within a generated fragment this is applied only when every\n // newline is provably layout; see `hasOnlyLayoutNewlines`.\n indent?: boolean;\n}\n\n// Whether every newline in generated code is layout rather than part of a\n// value. Babel escapes newlines inside ordinary string literals, so the only\n// newlines that carry meaning come from a template literal or from JSX text\n// — and both announce themselves with a backtick or a `<`.\n//\n// This matters because indenting a value-newline silently rewrites the\n// value, and the damage compounds: the built-in array editor re-serializes\n// its own output and feeds it back through `update`, so an `innerHTML` leaf\n// stored as a template literal would gain a level of indentation on every\n// single edit.\n//\n// The scan is deliberately conservative. Quotes, comments and regex\n// literals can all hide a backtick, and telling a regex from a division\n// needs real parsing — so anything ambiguous returns false. A false\n// \"unsafe\" only costs a fragment that isn't re-indented; a false \"safe\"\n// corrupts the value.\nconst hasOnlyLayoutNewlines = (content: string): boolean => {\n let index = 0;\n\n while (index < content.length) {\n const char = content[index];\n\n // `<` also matches comparison operators and TS generics. Refusing those\n // is harmless.\n if (char === '`' || char === '<') {\n return false;\n }\n\n if (char === '\"' || char === \"'\") {\n const next = skipStringLiteral(content, index);\n\n if (next === -1) {\n return false;\n }\n\n index = next;\n continue;\n }\n\n if (char === '/') {\n const following = content[index + 1];\n\n if (following === '/') {\n const lineEnd = content.indexOf('\\n', index + 2);\n index = lineEnd === -1 ? content.length : lineEnd;\n continue;\n }\n\n if (following === '*') {\n const commentEnd = content.indexOf('*/', index + 2);\n\n if (commentEnd === -1) {\n return false;\n }\n\n index = commentEnd + 2;\n continue;\n }\n\n // Division or a regex literal — indistinguishable without parsing.\n return false;\n }\n\n index++;\n }\n\n return true;\n};\n\n// Index just past the closing quote, or -1 if the literal doesn't terminate\n// before the end of its line. Valid generated JS never contains a bare\n// newline inside a string literal, so hitting one means the scan has lost\n// track of where it is and the caller should stop trusting it.\nconst skipStringLiteral = (content: string, start: number): number => {\n const quote = content[start];\n\n for (let index = start + 1; index < content.length; index++) {\n const char = content[index];\n\n if (char === '\\\\') {\n // A backslash immediately before a newline is a line continuation:\n // legal JS, and Babel re-emits it verbatim because it contributes\n // nothing to the value. The newline is then part of the literal's raw\n // text, so indenting it would rewrite the string — bail out instead\n // of treating the continuation as an ordinary escape.\n const escaped = content[index + 1];\n\n if (escaped === '\\n' || escaped === '\\r') {\n return -1;\n }\n\n index++;\n continue;\n }\n\n if (char === quote) {\n return index + 1;\n }\n\n if (char === '\\n') {\n return -1;\n }\n }\n\n return -1;\n};\n\n// Indentation of the line that `offset` falls on.\nconst lineIndentAt = (source: string, offset: number): string => {\n const lineStart = source.lastIndexOf('\\n', offset - 1) + 1;\n const match = /^[ \\t]*/.exec(source.slice(lineStart, offset));\n\n return match?.[0] ?? '';\n};\n\n// Babel always emits LF. Inserting that straight into a CRLF file leaves it\n// with mixed endings, so a generated fragment adopts whichever the file\n// already uses. Only ever applied alongside re-indentation, where the\n// newlines are known to be layout rather than part of a value.\nconst lineTerminatorOf = (source: string): string => {\n return source.includes('\\r\\n') ? '\\r\\n' : '\\n';\n};\n\n// Applies non-overlapping edits to `source` in a single forward pass.\n// An edit with `start === end` is an insertion at that offset.\n//\n// Throws on overlapping or out-of-bounds edits rather than silently\n// producing corrupt output: callers build spans from parsed node offsets,\n// so an overlap means the caller's model of the tree is wrong, and a\n// half-applied patch would be far harder to diagnose than a failure.\nexport const applyEdits = (source: string, edits: SourceEdit[]): string => {\n if (edits.length === 0) {\n return source;\n }\n\n const ordered = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);\n\n for (const edit of ordered) {\n if (\n !Number.isInteger(edit.start) ||\n !Number.isInteger(edit.end) ||\n edit.start < 0 ||\n edit.end > source.length ||\n edit.start > edit.end\n ) {\n throw new Error(\n `Invalid source edit [${edit.start}, ${edit.end}) for a source of length ${source.length}`,\n );\n }\n }\n\n for (let i = 1; i < ordered.length; i++) {\n const previous = ordered[i - 1]!;\n const current = ordered[i]!;\n\n if (current.start < previous.end) {\n throw new Error(\n `Overlapping source edits: [${previous.start}, ${previous.end}) and [${current.start}, ${current.end})`,\n );\n }\n }\n\n let result = '';\n let cursor = 0;\n const terminator = lineTerminatorOf(source);\n\n for (const edit of ordered) {\n const content =\n edit.indent &&\n edit.content.includes('\\n') &&\n hasOnlyLayoutNewlines(edit.content)\n ? edit.content.replace(\n /\\n/g,\n `${terminator}${lineIndentAt(source, edit.start)}`,\n )\n : edit.content;\n\n result += source.slice(cursor, edit.start) + content;\n cursor = edit.end;\n }\n\n return result + source.slice(cursor);\n};\n","import * as t from '@babel/types';\n\nimport { type SourceEdit, applyEdits } from './patch';\nimport { parseArrayExpression } from './value';\n\n// Gaps between dense elements contain only whitespace, comments and one\n// comma. Scan those gaps, never the expressions (which can contain JSX,\n// regexes, templates and nested commas).\nconst commaIn = (source: string, start: number, end: number): number | null => {\n let comma: number | null = null;\n\n for (let at = start; at < end; at++) {\n if (/\\s/.test(source[at]!)) {\n continue;\n }\n\n if (source.startsWith('/*', at)) {\n const close = source.indexOf('*/', at + 2);\n\n if (close < 0 || close + 2 > end) {\n return null;\n }\n\n at = close + 1;\n } else if (source.startsWith('//', at)) {\n const newline = source.indexOf('\\n', at + 2);\n at = newline < 0 ? end : newline;\n } else if (source[at] === ',' && comma === null) {\n comma = at;\n } else {\n return null;\n }\n }\n\n return comma;\n};\n\nexport const denseArraySource = (source: string) => {\n const array = parseArrayExpression(source);\n\n // Holes/spreads have source positions but no stable visible item count.\n // Value edits can preserve them; structural edits deliberately refuse.\n if (\n !array ||\n array.elements.some(\n node => !t.isExpression(node) || node.extra?.parenthesized,\n )\n ) {\n return null;\n }\n\n const elements = array.elements as t.Expression[];\n const commas = elements\n .slice(0, -1)\n .map((node, index) =>\n commaIn(source, node.end!, elements[index + 1]!.start!),\n );\n\n if (commas.some(comma => comma === null)) {\n return null;\n }\n\n const last = elements.at(-1);\n const trailing = last ? commaIn(source, last.end!, array.end! - 1) : null;\n\n return { array, elements, commas: commas as number[], trailing };\n};\n\n// Keep presentation and mutation on the same syntax boundary. Consumers can\n// use this before offering structural controls, while every write still calls\n// denseArraySource() again so stale source is refused at commit time.\nexport const canStructurallyEditArray = (source: string) =>\n denseArraySource(source) !== null;\n\nexport const validArrayIndices = (indices: Iterable<number>, length: number) =>\n [...indices].every(\n index => Number.isInteger(index) && index >= 0 && index < length,\n );\n\nexport const reorderArraySource = (\n source: string,\n elements: t.Expression[],\n next: t.Expression[],\n): string =>\n applyEdits(\n source,\n elements.map((node, index) => ({\n start: node.start!,\n end: node.end!,\n content: source.slice(next[index]!.start!, next[index]!.end!),\n })),\n );\n\nexport const removeArraySource = (\n source: string,\n data: NonNullable<ReturnType<typeof denseArraySource>>,\n indices: Set<number>,\n): string => {\n const edits: SourceEdit[] = [];\n const removedCommas = new Set<number>();\n const { elements, commas, trailing } = data;\n\n // Each consecutive removed run consumes its following commas. A run\n // ending at the last element consumes the preceding separator instead;\n // a trailing comma, when present, stays a trailing comma.\n for (let index = 0; index < elements.length; index++) {\n if (!indices.has(index)) {\n continue;\n }\n\n const start = index;\n\n while (index + 1 < elements.length && indices.has(index + 1)) {\n index++;\n }\n\n for (let current = start; current <= index; current++) {\n const node = elements[current]!;\n edits.push({ start: node.start!, end: node.end!, content: '' });\n\n if (current < elements.length - 1) {\n removedCommas.add(commas[current]!);\n }\n }\n\n if (index === elements.length - 1) {\n if (trailing !== null) {\n removedCommas.add(trailing);\n } else if (start > 0) {\n removedCommas.add(commas[start - 1]!);\n }\n }\n }\n\n for (const comma of removedCommas) {\n edits.push({ start: comma, end: comma + 1, content: '' });\n }\n\n return applyEdits(source, edits);\n};\n\nexport const appendArraySource = (\n source: string,\n data: NonNullable<ReturnType<typeof denseArraySource>>,\n copies: string[],\n): string => {\n const last = data.elements.at(-1);\n\n if (!last || copies.length === 0) {\n return source;\n }\n\n // Insert before the old trailing gap so line comments cannot swallow a\n // new item, and keep an existing trailing comma in its original role.\n return applyEdits(source, [\n {\n start: last.end!,\n end: last.end!,\n content: `, ${copies.join(', ')}`,\n },\n ]);\n};\n","import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { nanoid } from 'nanoid';\n\nimport { BINDING_PROP } from '../../constants';\nimport { moveSelectedIndices, removeIndices } from '../selection';\nimport {\n appendArraySource,\n denseArraySource,\n removeArraySource,\n reorderArraySource,\n validArrayIndices,\n} from './array-source';\nimport { generateCode } from './helpers';\nimport { type SourceEdit, applyEdits } from './patch';\nimport type {\n BindingRenderLeaf,\n BindingRenderMap,\n NodeValueType,\n} from './types';\nimport {\n createNodeFromValue,\n extractNodeValue,\n extractObjectProperties,\n isLosslesslyEvaluable,\n parseArrayExpression,\n parseValue,\n valueToExpression,\n} from './value';\n\n// Array edits are source patches. Parsing locates the requested value or\n// element; unrelated expressions, comments and formatting are not printed\n// again. Structural edits require dense arrays; value edits preserve holes\n// and spreads at their existing source positions. `null` means refusal.\n\nexport type ItemKind = 'object' | 'primitive';\n\nexport interface ArrayItem {\n // Position in the array's elements, which is what every function here\n // indexes by. Items of one kind are not renumbered, so a mixed array\n // stays addressable.\n index: number;\n kind: ItemKind;\n node: t.Expression;\n}\n\nconst elementsOf = (code: string) =>\n parseArrayExpression(code)?.elements ?? null;\n\nconst kindOf = (element: t.Expression): ItemKind =>\n t.isObjectExpression(element) ? 'object' : 'primitive';\n\n// Omit holes and spreads from the visible list without renumbering source\n// positions. A spread is not one runtime value that the panel can edit.\nexport const parseItems = (code: string): ArrayItem[] | null => {\n const elements = elementsOf(code);\n\n return (\n elements?.flatMap((node, index) =>\n t.isExpression(node) ? [{ index, kind: kindOf(node), node }] : [],\n ) ?? null\n );\n};\n\nconst resolveRenderLeaf = (\n render: BindingRenderMap | undefined,\n key: string,\n): BindingRenderLeaf | null => {\n const leaf = render?.[key];\n\n return leaf && 'type' in leaf ? (leaf as BindingRenderLeaf) : null;\n};\n\n// Escapes text for a template literal's raw slot. `@babel/types` rejects a\n// raw containing an unescaped backtick or `${`, a lone backslash would\n// otherwise be read back as an escape sequence, and a carriage return is\n// normalized to a newline by the spec's raw-value rules — so raw markup\n// pasted into an innerHTML field used to throw straight out of the edit\n// handler, and CRLF would not survive a round trip.\nconst toTemplateRaw = (value: string): string => {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/`/g, '\\\\`')\n .replace(/\\$\\{/g, '\\\\${')\n .replace(/\\r/g, '\\\\r');\n};\n\n// Builds the node a property should hold, from the value the panel produced.\n// Returns `undefined` when the value can't be represented, which callers\n// treat as \"leave the source alone\".\nconst buildPropertyValue = (\n value: unknown,\n declaredType: NodeValueType,\n renderLeaf: BindingRenderLeaf | null,\n current: t.Expression,\n): t.Expression | undefined => {\n // innerHTML carries raw markup, which has to survive as written — a\n // template literal keeps it verbatim without escaping.\n if (renderLeaf?.property === BINDING_PROP.INNER_HTML) {\n const raw = String(value);\n\n return t.templateLiteral(\n [t.templateElement({ raw: toTemplateRaw(raw), cooked: raw }, true)],\n [],\n );\n }\n\n // A declared `render[key].type === 'jsx'` covers a schema-declared JSX\n // property; a property whose *current* value is already JSX (e.g. the\n // items panel's fallback editor for a JSX-valued property with no\n // extractable bindings, see #298) needs the same treatment even without\n // that declaration, so it round-trips as JSX rather than as a string.\n if (\n renderLeaf?.type === 'jsx' ||\n t.isJSXElement(current) ||\n t.isJSXFragment(current)\n ) {\n const trimmed = String(value).trim();\n\n // Anything that isn't markup is a plain string for this property.\n if (!trimmed.startsWith('<')) {\n return t.stringLiteral(trimmed);\n }\n\n try {\n return parseExpression(trimmed, { plugins: ['jsx', 'typescript'] });\n } catch {\n return undefined;\n }\n }\n\n if (declaredType === 'array' || declaredType === 'object') {\n // The nested Items editor commits serialized source text, while the\n // object editor and the fallback TextArea commit a real JS value.\n // Parsing the former directly avoids evaluating it and `String()`-ing\n // it back to `1,2` (a sequence expression).\n if (typeof value === 'string') {\n try {\n return parseExpression(value, { plugins: ['jsx', 'typescript'] });\n } catch {\n return undefined;\n }\n }\n\n // The latter has already been through `evaluateLiteral`, so it can only\n // be rebuilt faithfully when the property held nothing but literals to\n // begin with. Otherwise the edit is refused and the source is left\n // alone, which is the safe half of what this path used to do.\n if (!isLosslesslyEvaluable(current)) {\n return undefined;\n }\n\n return valueToExpression(value) ?? undefined;\n }\n\n // Scalars arrive as the text typed into the field, so coerce before\n // building the literal — `createNodeFromValue('boolean', 'true')` would\n // otherwise compare the string against `true` and yield `false`.\n return createNodeFromValue(declaredType, parseValue(value)) ?? undefined;\n};\n\nexport const updateArrayItemProperty = (\n code: string,\n index: number,\n key: string,\n value: unknown,\n render?: BindingRenderMap,\n): string | null => {\n const elements = elementsOf(code);\n const element = elements?.[index];\n\n if (!elements || !t.isObjectExpression(element)) {\n return null;\n }\n\n const target = element.properties.find(\n (property): property is t.ObjectProperty =>\n t.isObjectProperty(property) &&\n t.isIdentifier(property.key) &&\n property.key.name === key,\n );\n\n if (!target) {\n return null;\n }\n\n const declaredType = extractObjectProperties(element)[key]?.type ?? 'string';\n const nextValue = buildPropertyValue(\n value,\n declaredType,\n resolveRenderLeaf(render, key),\n target.value as t.Expression,\n );\n\n if (!nextValue) {\n return null;\n }\n\n let serialized =\n typeof value === 'string' &&\n (declaredType === 'array' ||\n declaredType === 'object' ||\n t.isJSXElement(nextValue) ||\n t.isJSXFragment(nextValue))\n ? value.trim()\n : generateCode(nextValue);\n\n if (\n nextValue.trailingComments?.some(comment => comment.type === 'CommentLine')\n ) {\n serialized += '\\n';\n }\n\n // A shorthand property shares the key/value span: expand it explicitly.\n const content = target.shorthand ? `${key}: ${serialized}` : serialized;\n\n return applyEdits(code, [\n { start: target.value.start!, end: target.value.end!, content },\n ]);\n};\n\nexport const updateArrayItemValue = (\n code: string,\n index: number,\n value: unknown,\n): string | null => {\n const elements = elementsOf(code);\n const element = elements?.[index];\n\n if (!elements || !t.isExpression(element)) {\n return null;\n }\n\n const nextValue = createNodeFromValue(\n extractNodeValue(element).type,\n parseValue(value),\n );\n\n if (!nextValue) {\n return null;\n }\n\n return applyEdits(code, [\n {\n start: element.start!,\n end: element.end!,\n content: generateCode(nextValue),\n },\n ]);\n};\n\nexport const moveArrayItem = (\n code: string,\n from: number,\n to: number,\n): string | null => {\n const data = denseArraySource(code);\n\n if (\n !data ||\n !validArrayIndices([from], data.elements.length) ||\n !Number.isInteger(to)\n ) {\n return null;\n }\n\n // Preserve the existing splice destination semantics (including append).\n const next = [...data.elements];\n const [moved] = next.splice(from, 1);\n next.splice(to, 0, moved!);\n\n return reorderArraySource(code, data.elements, next);\n};\n\nexport const moveArrayItems = (\n code: string,\n indices: Set<number>,\n direction: 'up' | 'down',\n): { code: string; indices: Set<number> } | null => {\n const data = denseArraySource(code);\n\n if (\n !data ||\n !validArrayIndices(indices, data.elements.length) ||\n !['up', 'down'].includes(direction)\n ) {\n return null;\n }\n\n const next = moveSelectedIndices(data.elements, indices, direction);\n\n return {\n code: reorderArraySource(code, data.elements, next.items),\n indices: next.indices,\n };\n};\n\n// Keep the last-item guard until the empty-array creation contract (#316)\n// is implemented. It must count the visible kind in a mixed array.\nexport const removeArrayItems = (\n code: string,\n indices: Set<number>,\n kind?: ItemKind,\n): string | null => {\n const data = denseArraySource(code);\n\n if (!data || !validArrayIndices(indices, data.elements.length)) {\n return null;\n }\n\n const remaining = removeIndices(data.elements, indices);\n const survivors =\n kind === undefined\n ? remaining\n : remaining.filter(node => kindOf(node) === kind);\n\n if (!survivors.length) {\n return null;\n }\n\n return removeArraySource(code, data, indices);\n};\n\n// Copy exact source; only static object keys / JSX identities get changed.\n// Re-evaluating modeled property values here would erase expressions.\nconst copyItem = (\n code: string,\n element: t.Expression,\n generateId: () => string,\n usedIds: Set<string>,\n): string | null => {\n const edits: SourceEdit[] = [];\n let unsupported = false;\n const reserveId = (id: string) => {\n if (usedIds.has(id)) {\n unsupported = true;\n }\n\n usedIds.add(id);\n\n return JSON.stringify(id);\n };\n\n t.traverseFast(element, node => {\n if (!t.isJSXOpeningElement(node)) {\n return;\n }\n\n const ids = node.attributes.filter(\n (attr): attr is t.JSXAttribute =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name, { name: 'data-id' }),\n );\n const attr = ids[0];\n\n if (\n ids.length > 1 ||\n (attr &&\n (!t.isStringLiteral(attr.value) ||\n node.attributes\n .slice(node.attributes.indexOf(attr) + 1)\n .some(a => t.isJSXSpreadAttribute(a))))\n ) {\n unsupported = true;\n return;\n }\n\n if (attr && t.isStringLiteral(attr.value)) {\n edits.push({\n start: attr.value.start!,\n end: attr.value.end!,\n content: reserveId(generateId()),\n });\n }\n });\n\n if (t.isObjectExpression(element)) {\n const keys = element.properties.filter(\n (prop): prop is t.ObjectProperty =>\n t.isObjectProperty(prop) &&\n !prop.computed &&\n (t.isIdentifier(prop.key, { name: 'key' }) ||\n t.isStringLiteral(prop.key, { value: 'key' })),\n );\n const key = keys[0];\n\n if (\n keys.length > 1 ||\n (key &&\n (!t.isStringLiteral(key.value) ||\n element.properties\n .slice(element.properties.indexOf(key) + 1)\n .some(\n prop =>\n t.isSpreadElement(prop) ||\n ('computed' in prop && prop.computed),\n )))\n ) {\n return null;\n }\n\n if (key && t.isStringLiteral(key.value)) {\n edits.push({\n start: key.value.start!,\n end: key.value.end!,\n content: reserveId(`${key.value.value}-${generateId()}`),\n });\n }\n }\n\n if (unsupported) {\n return null;\n }\n\n return applyEdits(\n code.slice(element.start!, element.end!),\n edits.map(edit => ({\n ...edit,\n start: edit.start - element.start!,\n end: edit.end - element.start!,\n })),\n );\n};\n\nexport const duplicateArrayItems = (\n code: string,\n indices: Set<number>,\n generateId: () => string = () => nanoid(6),\n): string | null => {\n const data = denseArraySource(code);\n\n if (\n !data ||\n !indices.size ||\n !validArrayIndices(indices, data.elements.length)\n ) {\n return null;\n }\n\n const usedIds = new Set<string>();\n\n t.traverseFast(data.array, node => {\n if (\n t.isJSXAttribute(node) &&\n t.isJSXIdentifier(node.name, { name: 'data-id' }) &&\n t.isStringLiteral(node.value)\n ) {\n usedIds.add(node.value.value);\n } else if (\n t.isObjectProperty(node) &&\n !node.computed &&\n (t.isIdentifier(node.key, { name: 'key' }) ||\n t.isStringLiteral(node.key, { value: 'key' })) &&\n t.isStringLiteral(node.value)\n ) {\n usedIds.add(node.value.value);\n }\n });\n\n const copies = [...indices]\n .sort((a, b) => a - b)\n .map(index => copyItem(code, data.elements[index]!, generateId, usedIds));\n\n return copies.every((copy): copy is string => copy !== null)\n ? appendArraySource(code, data, copies)\n : null;\n};\n\n// Appends a copy of the first item of `kind`. There is deliberately no\n// \"create from scratch\" path: the shape of an item is defined by its\n// siblings, and inventing one (`{}`, or a guess from the render map) would\n// either be uneditable or silently impose a shape the consumer never\n// declared. An array binding is therefore editable only while it holds at\n// least one item — the same invariant `removeArrayItems` maintains by\n// refusing any edit that would empty the array. `null` here means the array\n// has no item of `kind` to copy; the first one belongs in the source (#316).\nexport const appendArrayItem = (\n code: string,\n kind: ItemKind,\n generateId: () => string = () => nanoid(6),\n): string | null => {\n const data = denseArraySource(code);\n const index = data?.elements.findIndex(node => kindOf(node) === kind) ?? -1;\n\n return index < 0\n ? null\n : duplicateArrayItems(code, new Set([index]), generateId);\n};\n","import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { nanoid } from 'nanoid';\n\nimport { moveSelectedIndices } from '../selection';\nimport { extract, nodeToJSX } from './extract';\nimport { generateCode } from './helpers';\nimport { type SourceEdit, applyEdits } from './patch';\nimport type { DataAttrNode } from './types';\n\nexport type ChildrenAction =\n | { type: 'move'; from: number; to: number }\n | { type: 'move-selected'; indices: number[]; direction: 'up' | 'down' }\n | { type: 'remove' | 'duplicate'; indices: number[] }\n | { type: 'append' };\n\nexport interface ChildrenEdit {\n kind: 'children-edit';\n expected: string[];\n action: ChildrenAction;\n}\n\n// Signatures address the extracted list, not synthetic wrapper IDs. The\n// source editor checks them against the latest parent before using indices.\nconst modeledSignatures = (nodes: DataAttrNode[]): string[] =>\n nodes.map(node => {\n const jsx = nodeToJSX(node);\n\n if (!jsx) {\n throw new Error('Invalid child node');\n }\n\n return generateCode(jsx);\n });\n\nexport const getChildrenSignatures = (nodes: DataAttrNode[]): string[] => {\n const modeled = modeledSignatures(nodes);\n\n return nodes.map((node, index) =>\n JSON.stringify([node.source ?? null, modeled[index]]),\n );\n};\n\nconst indicesAreValid = (\n indices: unknown,\n count: number,\n): indices is number[] =>\n Array.isArray(indices) &&\n new Set(indices).size === indices.length &&\n indices.every(\n index => Number.isInteger(index) && index >= 0 && index < count,\n );\n\n// Only ID attributes are replaced: expressions, spreads, comments and text\n// in a copied subtree retain their exact source. Dynamic IDs are ambiguous.\nconst copySource = (source: string, usedIds: Set<string>): string => {\n const node = parseExpression(source, { plugins: ['jsx', 'typescript'] });\n const edits: SourceEdit[] = [];\n const newId = () => {\n let id = nanoid(12);\n\n while (usedIds.has(id)) {\n id = nanoid(12);\n }\n\n usedIds.add(id);\n\n return id;\n };\n\n t.traverseFast(node, child => {\n if (!t.isJSXOpeningElement(child)) {\n return;\n }\n\n const ids = child.attributes.filter(\n (attr): attr is t.JSXAttribute =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name, { name: 'data-id' }),\n );\n\n if (ids.length > 1) {\n throw new Error('Duplicate data-id attributes');\n }\n\n const attr = ids[0];\n\n if (\n attr &&\n child.attributes\n .slice(child.attributes.indexOf(attr) + 1)\n .some(attribute => t.isJSXSpreadAttribute(attribute))\n ) {\n throw new Error('A spread may override the copied data-id');\n }\n\n if (attr) {\n const value = attr.value;\n\n if (\n !t.isStringLiteral(value) ||\n value.start == null ||\n value.end == null\n ) {\n throw new Error('Cannot copy a dynamic data-id');\n }\n\n edits.push({\n start: value.start,\n end: value.end,\n content: JSON.stringify(newId()),\n });\n } else {\n const at = child.attributes.at(-1)?.end ?? child.name.end;\n\n if (at == null) {\n throw new Error('Missing opening element span');\n }\n\n edits.push({\n start: at,\n end: at,\n content: ` data-id=\"${newId()}\"`,\n });\n }\n });\n\n return applyEdits(source, edits);\n};\n\n// Coordinates refer to the caller's wrapped source, just like other update\n// editors. Non-element gaps stay at their original positions; moving a JSX\n// child moves its entire subtree but never regenerates intervening content.\nexport const editChildrenSource = (\n source: string,\n parent: t.JSXElement,\n input: unknown,\n): SourceEdit[] | null => {\n try {\n if (!parent.closingElement || parent.start == null || parent.end == null) {\n return null;\n }\n\n const value = typeof input === 'string' ? JSON.parse(input) : input;\n const children = parent.children.filter(\n (child): child is t.JSXElement | t.JSXFragment =>\n t.isJSXElement(child) || t.isJSXFragment(child),\n );\n const raw = children.map(child => source.slice(child.start!, child.end!));\n const models =\n extract(source.slice(parent.start, parent.end))[0]?.children ?? [];\n\n // The extractor currently omits some empty/expression-only fragments.\n // Never interpret its visible indices as different source children.\n if (models.length !== children.length) {\n return null;\n }\n\n const signatures = modeledSignatures(models);\n const replaceSlots = (next: string[]): SourceEdit[] => {\n const edits = children.map((child, index) => ({\n start: child.start!,\n end: child.end!,\n content: next[index] ?? '',\n }));\n\n if (next.length > children.length) {\n const at = parent.closingElement!.start!;\n edits.push({\n start: at,\n end: at,\n content: next.slice(children.length).join(''),\n });\n }\n\n return edits;\n };\n\n if (Array.isArray(value)) {\n // Preserve the existing JSON API. Unchanged modeled children reuse\n // their full original source; arbitrary replacements are allowed only\n // when every original child can be represented without information loss.\n const desired = modeledSignatures(value);\n const lossless = raw.every(\n (text, index) =>\n generateCode(\n parseExpression(text, { plugins: ['jsx', 'typescript'] }),\n ) === signatures[index],\n );\n const consumed = new Set<number>();\n const next = desired.map((signature, position) => {\n const index = signatures.findIndex(\n (candidate, i) =>\n candidate === signature &&\n !consumed.has(i) &&\n (value[position].source === undefined ||\n value[position].source === raw[i]),\n );\n\n if (index >= 0) {\n consumed.add(index);\n\n return raw[index]!;\n }\n\n if (\n !lossless ||\n (value[position].source !== undefined &&\n !raw.includes(value[position].source))\n ) {\n throw new Error(\n 'Use children commands to copy or edit unsupported source',\n );\n }\n\n return signature;\n });\n\n // Legacy callers may supply entirely new modeled children. Do not\n // accept a duplicated identity that would make later edits ambiguous.\n const countIds = (text: string) => {\n const counts = new Map<string, number>();\n t.traverseFast(\n parseExpression(text, { plugins: ['jsx', 'typescript'] }),\n node => {\n if (\n t.isJSXAttribute(node) &&\n t.isJSXIdentifier(node.name, { name: 'data-id' }) &&\n t.isStringLiteral(node.value)\n ) {\n counts.set(\n node.value.value,\n (counts.get(node.value.value) ?? 0) + 1,\n );\n }\n },\n );\n\n return counts;\n };\n const previousIds = countIds(source);\n const updatedParent = applyEdits(source, replaceSlots(next));\n const nextIds = countIds(updatedParent);\n\n if (\n [...nextIds].some(\n ([id, count]) => count > 1 && count > (previousIds.get(id) ?? 0),\n )\n ) {\n return null;\n }\n\n return replaceSlots(next);\n }\n\n const request = value as ChildrenEdit | null;\n\n if (\n request?.kind !== 'children-edit' ||\n !Array.isArray(request.expected) ||\n request.expected.length !== signatures.length ||\n !getChildrenSignatures(models).every(\n (signature, index) => signature === request.expected[index],\n ) ||\n !request.action\n ) {\n return null;\n }\n\n const { action } = request;\n const usedIds = new Set<string>();\n\n t.traverseFast(parent, node => {\n if (\n t.isJSXAttribute(node) &&\n t.isJSXIdentifier(node.name, { name: 'data-id' }) &&\n t.isStringLiteral(node.value)\n ) {\n usedIds.add(node.value.value);\n }\n });\n\n switch (action.type) {\n case 'move': {\n if (\n !indicesAreValid([action.from], raw.length) ||\n !indicesAreValid([action.to], raw.length)\n ) {\n return null;\n }\n\n const next = [...raw];\n const [moved] = next.splice(action.from, 1);\n next.splice(action.to, 0, moved!);\n\n return replaceSlots(next);\n }\n case 'move-selected': {\n if (\n !indicesAreValid(action.indices, raw.length) ||\n !['up', 'down'].includes(action.direction)\n ) {\n return null;\n }\n\n return replaceSlots(\n moveSelectedIndices(raw, new Set(action.indices), action.direction)\n .items,\n );\n }\n case 'remove': {\n if (!indicesAreValid(action.indices, raw.length)) {\n return null;\n }\n\n return action.indices.map(index => ({\n start: children[index]!.start!,\n end: children[index]!.end!,\n content: '',\n }));\n }\n case 'duplicate': {\n if (!indicesAreValid(action.indices, raw.length)) {\n return null;\n }\n\n const content = [...action.indices]\n .sort((a, b) => a - b)\n .map(index => copySource(raw[index]!, usedIds))\n .join('');\n const at = parent.closingElement.start!;\n\n return [{ start: at, end: at, content }];\n }\n case 'append': {\n const content = copySource(raw[0] ?? '<div></div>', usedIds);\n const at = parent.closingElement.start!;\n\n return [{ start: at, end: at, content }];\n }\n default:\n return null;\n }\n } catch {\n return null;\n }\n};\n","import { parse, parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\n\nimport { BINDING_PROP, DATA_ATTR } from '../../constants';\nimport { STRING_VALUED_TYPES, parseBinding } from './binding';\nimport { editChildrenSource } from './children';\nimport { traverse } from './document';\nimport { generateCode, unwrap, wrap } from './helpers';\nimport { type SourceEdit, applyEdits } from './patch';\nimport type { BindingType } from './types';\nimport {\n isLosslesslyEvaluable,\n unwrapExpression,\n valueToExpression,\n} from './value';\n\n// Every editor below returns the source spans it wants to change rather\n// than mutating the tree, so `update` can patch the original text and leave\n// untouched bytes byte-identical. An empty array means \"nothing to write,\n// but this counts as handled\"; `null` means the edit failed. See #239.\ntype EditResult = SourceEdit[] | null;\n\n// The span between `>` and `</`, i.e. everything the element encloses.\n// `null` for a self-closing element, which has nowhere to put children.\nconst childrenRange = (\n element: t.JSXElement,\n): { start: number; end: number } | null => {\n const { openingElement, closingElement } = element;\n\n if (\n !closingElement ||\n openingElement.end == null ||\n closingElement.start == null\n ) {\n return null;\n }\n\n return { start: openingElement.end, end: closingElement.start };\n};\n\nconst findAttribute = (\n opening: t.JSXOpeningElement,\n propertyName: string,\n): t.JSXAttribute | undefined => {\n return opening.attributes.find(\n (attr): attr is t.JSXAttribute =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === propertyName,\n );\n};\n\n// Where a brand-new attribute should be inserted: after the last existing\n// attribute, or straight after the element name when there are none.\nconst attributeInsertPoint = (opening: t.JSXOpeningElement): number | null => {\n const last = opening.attributes[opening.attributes.length - 1];\n\n return last?.end ?? opening.name.end ?? null;\n};\n\n// Drops the element's JSXText children and writes `value` just before the\n// closing tag — the positional equivalent of the previous \"splice out every\n// JSXText, then push a new one\" mutation, including its handling of mixed\n// children (a nested element stays, the text around it doesn't).\n//\n// The common case — a single text child — is narrowed further: only the\n// text's *trimmed* span is replaced, so the author's line breaks and\n// indentation around it survive. Rewriting the whole children region would\n// collapse\n//\n// >\n// Old Title\n// </h1>\n//\n// down to `>New Title</h1>`, which is exactly the formatting loss #239 is\n// about, just at a smaller scale.\n//\n// A self-closing element yields no edits: there is no children region to\n// write into. That matches the old behaviour, which pushed onto a `children`\n// array the generator then ignored — a silent no-op still reported as\n// success. Left as-is here deliberately; it is a reporting bug, tracked\n// with the rest of that class in #270.\nconst editInnerText = (\n source: string,\n element: t.JSXElement,\n value: string,\n): EditResult => {\n const range = childrenRange(element);\n\n if (!range) {\n return [];\n }\n\n const [only] = element.children;\n\n if (\n element.children.length === 1 &&\n t.isJSXText(only) &&\n only.start != null &&\n only.end != null\n ) {\n // Measured on the raw source slice, never on `only.value`: the latter is\n // Babel's *cooked* text, with HTML entities decoded and CRLF collapsed\n // to LF, so its character counts don't line up with the raw offsets the\n // span is built from. ` Old ` would put the span six bytes\n // inside the entity (yielding `&New;`), and a CRLF file would lose a\n // byte off each end of every innerText edit.\n const raw = source.slice(only.start, only.end);\n\n if (raw.trim() !== '') {\n const leading = raw.length - raw.trimStart().length;\n const trailing = raw.length - raw.trimEnd().length;\n\n return [\n {\n start: only.start + leading,\n end: only.end - trailing,\n content: value,\n },\n ];\n }\n }\n\n const edits: SourceEdit[] = [];\n\n for (const child of element.children) {\n if (t.isJSXText(child) && child.start != null && child.end != null) {\n edits.push({ start: child.start, end: child.end, content: '' });\n }\n }\n\n edits.push({ start: range.end, end: range.end, content: value });\n\n return edits;\n};\n\n// Raw HTML replaces the children region verbatim. This is what the old\n// `__HTML_<id>__` placeholder existed to achieve: the value can't be\n// represented as an AST literal, so it had to be smuggled past the\n// generator and string-substituted back in afterwards. Writing directly\n// into the source removes that round-trip — and with it the `$&`/`$$`\n// substitution hazard that the replacement step had to guard against.\nconst editInnerHTML = (element: t.JSXElement, value: string): EditResult => {\n const range = childrenRange(element);\n\n if (!range) {\n return [];\n }\n\n return [{ start: range.start, end: range.end, content: value }];\n};\n\nconst editRichtext = (element: t.JSXElement, value: string): EditResult => {\n const edits: SourceEdit[] = [];\n const range = childrenRange(element);\n\n // richtext owns the element's content, so any prior markup goes.\n if (range && range.start !== range.end) {\n edits.push({ start: range.start, end: range.end, content: '' });\n }\n\n const opening = element.openingElement;\n const attribute = t.jsxAttribute(\n t.jsxIdentifier('dangerouslySetInnerHTML'),\n t.jsxExpressionContainer(\n t.objectExpression([\n t.objectProperty(t.identifier('__html'), t.stringLiteral(value)),\n ]),\n ),\n );\n const content = generateCode(attribute);\n const existing = findAttribute(opening, 'dangerouslySetInnerHTML');\n\n if (existing && existing.start != null && existing.end != null) {\n edits.push({\n start: existing.start,\n end: existing.end,\n content,\n indent: true,\n });\n\n return edits;\n }\n\n const insertAt = attributeInsertPoint(opening);\n\n if (insertAt == null) {\n return null;\n }\n\n edits.push({\n start: insertAt,\n end: insertAt,\n content: ` ${content}`,\n indent: true,\n });\n\n return edits;\n};\n\n// A `type: 'jsx'` value is arbitrary user-authored JSX, so it goes in as\n// written rather than being parsed into nodes and printed back out.\nconst editJsxAttribute = (\n opening: t.JSXOpeningElement,\n propertyName: string,\n value: unknown,\n): EditResult => {\n const attribute = findAttribute(opening, propertyName);\n\n if (!attribute) {\n return null;\n }\n\n const content = `{${String(value).trim()}}`;\n\n if (attribute.value?.start != null && attribute.value.end != null) {\n return [\n {\n start: attribute.value.start,\n end: attribute.value.end,\n content,\n },\n ];\n }\n\n // Valueless shorthand (`<Icon icon />`): there is no value span to\n // overwrite, so append one after the attribute name.\n const insertAt = attribute.name.end;\n\n if (insertAt == null) {\n return null;\n }\n\n return [{ start: insertAt, end: insertAt, content: `=${content}` }];\n};\n\n// Whether the attribute being replaced was authored as an array or object\n// literal inside a JSX expression container. Narrower than \"is an\n// expression\" on purpose: `className={cn(...)}` and `items={rows}` are\n// expressions too, but their value doesn't round-trip through the panel as\n// source text, so a string committed against them stays a string.\nconst holdsStructuralExpression = (value?: t.JSXAttribute['value']): boolean =>\n t.isJSXExpressionContainer(value) &&\n (t.isArrayExpression(unwrapExpression(value.expression)) ||\n t.isObjectExpression(unwrapExpression(value.expression)));\n\n// Parses committed text back into the array/object literal it claims to be.\n// Requiring that exact shape is what keeps a plain string from silently\n// becoming something else: `\"hello\"` parses fine as an identifier, and\n// writing `items={hello}` would turn a value into a variable reference.\nconst structuralSource = (value: string): t.Expression | null => {\n try {\n const expression = parseExpression(value.trim(), {\n plugins: ['jsx', 'typescript'],\n });\n\n return t.isArrayExpression(unwrapExpression(expression)) ||\n t.isObjectExpression(unwrapExpression(expression))\n ? expression\n : null;\n } catch {\n return null;\n }\n};\n\n// Serialize a structured value into a JSX attribute value, once, at the AST\n// boundary — the single point where the declared `type` is known. Replaces\n// the old first-character heuristic (`startsWith('{')` ...) that guessed\n// string-vs-expression and then let `attrValue` guess again. See #238.\n//\n// `current` is the attribute value being replaced. The declared `type` is\n// authoritative when there is one, but most shipped `items` bindings declare\n// none (`{ label: 'FAQ Items', property: 'items' }`), so the source is the\n// only remaining evidence of what the attribute holds — the same evidence\n// `getStructuredValue` reads on the way out via `attr.isStringLiteral`.\nconst buildAttributeValue = (\n value: unknown,\n type?: BindingType,\n current?: t.JSXAttribute['value'],\n): t.JSXAttribute['value'] => {\n // Declared object/array bindings: an expression container. A string here\n // is already-serialized source text (from the built-in Items/flatten\n // editor, which re-emits the whole array/object as code) — parse it back\n // to an expression rather than quoting it as a literal.\n if (type === 'array' || type === 'object') {\n if (typeof value === 'string') {\n try {\n return t.jsxExpressionContainer(\n parseExpression(value.trim(), { plugins: ['jsx', 'typescript'] }),\n );\n } catch {\n return t.stringLiteral(value);\n }\n }\n\n const expr = valueToExpression(value);\n return expr ? t.jsxExpressionContainer(expr) : t.stringLiteral('');\n }\n\n // Everything else maps one JS type to one literal kind — no guessing. A\n // string stays a string literal whatever it contains, so a genuine\n // `\"{not an expression}\"` no longer becomes a JSX expression container.\n if (typeof value === 'string') {\n // ...except when the attribute being replaced is itself an array/object\n // literal expression. Those hand the panel their *source text* as\n // `rawValue`, and the array editors commit that same source text back,\n // so quoting it would rewrite `items={[...]}` into an `items=\"[{\\n ...\"`\n // string literal and leave the document unparseable. Undeclared-type\n // `items`/`data` bindings only reach here, which is why they broke.\n if (\n holdsStructuralExpression(current) &&\n !(type && STRING_VALUED_TYPES.has(type))\n ) {\n const structural = structuralSource(value);\n\n if (structural) {\n return t.jsxExpressionContainer(structural);\n }\n }\n\n return t.stringLiteral(value);\n }\n\n const expr = valueToExpression(value);\n return expr ? t.jsxExpressionContainer(expr) : t.stringLiteral(String(value));\n};\n\nconst editAttribute = (\n opening: t.JSXOpeningElement,\n propertyName: string,\n value: unknown,\n type?: BindingType,\n): EditResult => {\n const attribute = findAttribute(opening, propertyName);\n\n if (!attribute || attribute.start == null || attribute.end == null) {\n return null;\n }\n\n // Serialized array/object edits already carry preserved source. Validate\n // their shape, then replace only the expression value instead of printing\n // the attribute (which would reformat every untouched array sibling).\n if (\n typeof value === 'string' &&\n (type === 'array' ||\n type === 'object' ||\n (holdsStructuralExpression(attribute.value) &&\n !(type && STRING_VALUED_TYPES.has(type))))\n ) {\n const expression = structuralSource(value);\n\n if (expression && t.isJSXExpressionContainer(attribute.value)) {\n const text = value.trim();\n const lineComment = expression.trailingComments?.some(\n comment => comment.type === 'CommentLine',\n );\n\n return [\n {\n start: attribute.value.expression.start!,\n end: attribute.value.expression.end!,\n content: `${text}${lineComment ? '\\n' : ''}`,\n },\n ];\n }\n }\n\n // Generate the whole attribute rather than just its value, so Babel's\n // JSX-attribute printing path decides the quoting and escaping — the same\n // path that produced this text before, when the enclosing tree was\n // regenerated. Reuses the parsed name node instead of building a fresh\n // identifier so namespaced/dashed names survive untouched.\n const content = generateCode(\n t.jsxAttribute(\n attribute.name,\n buildAttributeValue(value, type, attribute.value),\n ),\n );\n\n return [\n { start: attribute.start, end: attribute.end, content, indent: true },\n ];\n};\n\nconst canEditAttributeValue = (\n attribute: t.JSXAttribute,\n value: unknown,\n type?: BindingType,\n) => {\n if (\n !t.isJSXExpressionContainer(attribute.value) ||\n t.isJSXEmptyExpression(attribute.value.expression) ||\n isLosslesslyEvaluable(attribute.value.expression)\n ) {\n return true;\n }\n\n // Array/object editors commit validated source strings rather than a\n // partially evaluated JS value. Their own patch engines preserve every\n // expression, so accept that raw-source handoff here.\n return (\n typeof value === 'string' &&\n holdsStructuralExpression(attribute.value) &&\n !(type && STRING_VALUED_TYPES.has(type)) &&\n structuralSource(value) !== null\n );\n};\n\n// Why an edit failed. Before #270 every one of these collapsed into a bare\n// `success: false`, so the panel showed one generic \"Failed to update this\n// field / check the console\" toast for structurally different problems — and\n// nothing was ever logged, so the console it pointed at was empty. Each\n// variant carries the identifiers a caller needs to name the real fault\n// (usually a wrong `property`/`label` in the element's `data-binding`, not\n// the value the author just typed).\nexport type UpdateFailure =\n | { reason: 'element-not-found'; dataId: string }\n | { reason: 'no-binding'; dataId: string }\n | {\n reason: 'binding-not-declared';\n dataId: string;\n label: string;\n property?: string;\n }\n | {\n reason: 'duplicate-binding';\n dataId: string;\n label: string;\n property?: string;\n count: number;\n }\n | { reason: 'attribute-not-found'; dataId: string; property: string }\n | { reason: 'unsupported-syntax'; dataId: string; property: string }\n | { reason: 'parse-error'; error: unknown };\n\nexport interface UpdateResult {\n code: string;\n success: boolean;\n // Present iff `success === false`. `bulkUpdate` reports per-entry failures\n // via `failures` instead, since one boolean can't say how many of several\n // entries failed or which ones.\n failure?: UpdateFailure;\n failures?: UpdateFailure[];\n}\n\n// `label` is a display string — reworded, duplicated, or translated at\n// authors' whim — so it identifies a binding only as a fallback. `property`\n// (an actual key, unique per element) is the real identity; pass it\n// whenever the caller has it (every internal caller does, via\n// PanelBinding.property). See #240: two bindings sharing a label used to\n// resolve to whichever `.find()` hit first, silently dropping the other's\n// edit while still reporting success.\nexport const update = (\n code: string,\n dataId: string,\n label: string,\n value: unknown,\n property?: string,\n): UpdateResult => {\n try {\n const wrapped = wrap(code);\n const ast = parse(wrapped, {\n sourceType: 'module',\n plugins: ['jsx', 'typescript'],\n });\n\n let changed = false;\n let failure: UpdateFailure | undefined;\n const edits: SourceEdit[] = [];\n\n // Records an editor's outcome. `null` is a failure — the caller passes\n // the reason so it isn't discarded; anything else counts as handled,\n // even when it produces no edits.\n const collect = (result: EditResult, onNull: () => UpdateFailure) => {\n if (!result) {\n failure = onNull();\n return;\n }\n\n edits.push(...result);\n changed = true;\n };\n\n traverse(ast, {\n JSXElement(path) {\n const opening = path.node.openingElement;\n\n const idAttr = opening.attributes.find(attr => {\n return (\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === DATA_ATTR.ID &&\n attr.value &&\n t.isStringLiteral(attr.value) &&\n attr.value.value === dataId\n );\n });\n\n if (!idAttr) {\n return;\n }\n\n const bindingAttr = opening.attributes.find(\n (attr): attr is t.JSXAttribute =>\n t.isJSXAttribute(attr) &&\n t.isJSXIdentifier(attr.name) &&\n attr.name.name === DATA_ATTR.BINDING,\n );\n\n if (!bindingAttr?.value) {\n failure = { reason: 'no-binding', dataId };\n return;\n }\n\n let bindingValue = '';\n\n if (t.isStringLiteral(bindingAttr.value)) {\n bindingValue = bindingAttr.value.value;\n } else if (t.isJSXExpressionContainer(bindingAttr.value)) {\n try {\n bindingValue = generateCode(bindingAttr.value.expression);\n } catch (error) {\n failure = { reason: 'parse-error', error };\n return;\n }\n }\n\n const bindings = parseBinding(bindingValue);\n\n // Prefer `property` (an actual key) over `label` (a display\n // string) — see the module-level comment on `update`. Either way,\n // more than one match on this element is an authoring ambiguity\n // (duplicate labels, or a genuine property collision), not a case\n // to silently resolve by picking the first — see #240.\n const matches = bindings.filter(binding =>\n property !== undefined\n ? binding.property === property\n : binding.label === label,\n );\n\n if (matches.length === 0) {\n failure = { reason: 'binding-not-declared', dataId, label, property };\n return;\n }\n\n if (matches.length > 1) {\n failure = {\n reason: 'duplicate-binding',\n dataId,\n label,\n property,\n count: matches.length,\n };\n return;\n }\n\n const propertyBinding = matches[0]!;\n const prop = propertyBinding.property;\n\n switch (prop) {\n case BINDING_PROP.INNER_TEXT: {\n collect(editInnerText(wrapped, path.node, String(value)), () => ({\n reason: 'parse-error',\n error: new Error(`could not update \"${prop}\"`),\n }));\n break;\n }\n\n case BINDING_PROP.INNER_HTML: {\n collect(\n propertyBinding.type === 'richtext'\n ? editRichtext(path.node, String(value))\n : editInnerHTML(path.node, String(value)),\n () => ({\n reason: 'parse-error',\n error: new Error(`could not update \"${prop}\"`),\n }),\n );\n break;\n }\n\n case BINDING_PROP.CHILDREN: {\n collect(editChildrenSource(wrapped, path.node, value), () => ({\n reason: 'parse-error',\n error: new Error(\n 'Unsupported or stale children edit; source was preserved',\n ),\n }));\n break;\n }\n\n default: {\n // The declared `property` names a JSX attribute that isn't on\n // this element — the binding declaration is wrong, not the value.\n const attribute = findAttribute(opening, prop);\n\n if (\n attribute &&\n propertyBinding.type !== 'jsx' &&\n !canEditAttributeValue(attribute, value, propertyBinding.type)\n ) {\n failure = {\n reason: 'unsupported-syntax',\n dataId,\n property: prop,\n };\n break;\n }\n\n collect(\n propertyBinding.type === 'jsx'\n ? editJsxAttribute(opening, prop, value)\n : editAttribute(opening, prop, value, propertyBinding.type),\n () => ({ reason: 'attribute-not-found', dataId, property: prop }),\n );\n break;\n }\n }\n },\n });\n\n if (!changed) {\n return {\n code,\n success: false,\n // No specific reason recorded means the traversal never reached the\n // target element at all.\n failure: failure ?? { reason: 'element-not-found', dataId },\n };\n }\n\n // Patch the original source instead of re-emitting the tree: every byte\n // outside a recorded span is copied through unchanged, so an edit to\n // one field can no longer reflow the author's formatting elsewhere in\n // the section — including the `data-binding` array itself, which is now\n // authored as a JSX expression. See #239.\n return { code: unwrap(applyEdits(wrapped, edits)), success: true };\n } catch (error) {\n console.error('❌ Code update error:', error);\n return { code, success: false, failure: { reason: 'parse-error', error } };\n }\n};\n\nexport const bulkUpdate = (\n raw: string,\n entries: {\n dataId: string;\n label: string;\n value: unknown;\n property?: string;\n }[],\n): UpdateResult => {\n let current = raw;\n const failures: UpdateFailure[] = [];\n\n for (const entry of entries) {\n const result = update(\n current,\n entry.dataId,\n entry.label,\n entry.value,\n entry.property,\n );\n current = result.code;\n if (!result.success && result.failure) {\n failures.push(result.failure);\n }\n }\n\n return failures.length > 0\n ? { code: current, success: false, failures }\n : { code: current, success: true };\n};\n","import { parseExpression } from '@babel/parser';\nimport * as t from '@babel/types';\nimport { nanoid } from 'nanoid';\n\nimport { DATA_ATTR } from '../../constants';\nimport { generateCode } from './helpers';\n\nexport const replaceIds = (\n code: string,\n generateId: () => string = () => nanoid(6),\n): string => {\n return code.replace(new RegExp(`${DATA_ATTR.ID}=\"[^\"]*\"`, 'g'), () => {\n return `${DATA_ATTR.ID}=\"${generateId()}\"`;\n });\n};\n\nexport const fillIds = (\n code: string,\n generateId: () => string = () => nanoid(6),\n): string => {\n return code.replace(new RegExp(`${DATA_ATTR.ID}=\"\"`, 'g'), () => {\n return `${DATA_ATTR.ID}=\"${generateId()}\"`;\n });\n};\n\nexport const clone = (\n element: t.Node,\n generateId: () => string = () => nanoid(6),\n) => {\n const cloned = t.cloneNode(element, true);\n const generatedCode = generateCode(cloned);\n const code = replaceIds(generatedCode, generateId);\n\n return parseExpression(code, {\n plugins: ['jsx', 'typescript'],\n });\n};\n","import type { BindingItem } from './types';\n\nexport interface ValidationResult {\n valid: boolean;\n message?: string;\n}\n\nconst VALID: ValidationResult = { valid: true };\n\nexport const validateBindingValue = (\n binding: BindingItem,\n value: unknown,\n): ValidationResult => {\n const isEmpty = value === '' || value === null || value === undefined;\n\n if (isEmpty) {\n if (binding.required) {\n return { valid: false, message: 'This field is required.' };\n }\n return VALID;\n }\n\n // `min`/`max` compare against a real number. Since #238, a `type:\n // 'number'` binding delivers an actual number across the panel boundary,\n // so callers pass one here directly — no string coercion to re-derive the\n // type. A non-number value simply isn't range-checked.\n if (typeof value === 'number') {\n if (binding.min !== undefined && value < binding.min) {\n return { valid: false, message: `Must be at least ${binding.min}.` };\n }\n if (binding.max !== undefined && value > binding.max) {\n return { valid: false, message: `Must be at most ${binding.max}.` };\n }\n }\n\n if (typeof value === 'string' && binding.pattern) {\n let regex: RegExp;\n\n try {\n regex = new RegExp(binding.pattern);\n } catch {\n // Malformed pattern authored on the binding itself — don't block the\n // user's input for an authoring mistake that isn't theirs to fix.\n return VALID;\n }\n\n if (!regex.test(value)) {\n return {\n valid: false,\n message: 'Value does not match the required format.',\n };\n }\n }\n\n if (typeof value === 'string' && binding.type === 'url') {\n try {\n new URL(value);\n } catch {\n return { valid: false, message: 'Must be a valid URL.' };\n }\n }\n\n if (typeof value === 'string' && binding.type === 'date') {\n if (Number.isNaN(Date.parse(value))) {\n return { valid: false, message: 'Must be a valid date.' };\n }\n }\n\n return VALID;\n};\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as cn } from "./utils-BQ7WL7Jh.js";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/error/error.tsx
|
|
@@ -74,13 +74,14 @@ var ErrorBoundary = class extends React.Component {
|
|
|
74
74
|
error: void 0
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
|
+
reset = () => this.setState({
|
|
78
|
+
hasError: false,
|
|
79
|
+
error: void 0
|
|
80
|
+
});
|
|
77
81
|
render() {
|
|
78
|
-
if (this.state.hasError) return this.props.fallback ? /* @__PURE__ */ jsx(Fragment, { children: this.props.fallback(this.state.error?.message) }) : /* @__PURE__ */ jsx(Error, {
|
|
82
|
+
if (this.state.hasError) return this.props.fallback ? /* @__PURE__ */ jsx(Fragment, { children: this.props.fallback(this.state.error?.message, this.reset) }) : /* @__PURE__ */ jsx(Error, {
|
|
79
83
|
message: this.state.error?.message,
|
|
80
|
-
onReset:
|
|
81
|
-
hasError: false,
|
|
82
|
-
error: void 0
|
|
83
|
-
}),
|
|
84
|
+
onReset: this.reset,
|
|
84
85
|
title: "Rendering Error"
|
|
85
86
|
});
|
|
86
87
|
return this.props.children;
|
|
@@ -89,4 +90,4 @@ var ErrorBoundary = class extends React.Component {
|
|
|
89
90
|
//#endregion
|
|
90
91
|
export { Error as n, ErrorBoundary as t };
|
|
91
92
|
|
|
92
|
-
//# sourceMappingURL=boundary-
|
|
93
|
+
//# sourceMappingURL=boundary-C90q3YsT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundary-C90q3YsT.js","names":[],"sources":["../src/components/error/error.tsx","../src/components/error/boundary.tsx"],"sourcesContent":["import { cn } from '~/utils';\n\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n message?: string | null;\n title?: string;\n onReset?: () => void;\n}\n\nconst Error = ({\n message,\n title = 'An error occurred',\n className,\n onReset,\n}: Props) => {\n if (!message) {\n return null;\n }\n\n return (\n <div\n className={cn(className)}\n style={{\n padding: '16px',\n backgroundColor: '#fee2e2',\n border: '1px solid #fca5a5',\n borderRadius: '6px',\n color: '#7f1d1d',\n }}\n >\n <h3 style={{ fontSize: '14px', fontWeight: 'bold', margin: 0 }}>\n {title}\n </h3>\n <pre\n style={{\n marginTop: '8px',\n fontSize: '12px',\n whiteSpace: 'pre-wrap',\n margin: '8px 0 0 0',\n }}\n >\n {message}\n </pre>\n {onReset && (\n <button\n style={{\n marginTop: '8px',\n padding: '4px 12px',\n fontSize: '12px',\n color: 'white',\n backgroundColor: '#dc2626',\n border: 'none',\n borderRadius: '4px',\n cursor: 'pointer',\n }}\n onClick={onReset}\n >\n Try Again\n </button>\n )}\n </div>\n );\n};\n\nexport default Error;\n","import React from 'react';\n\nimport Error from './error';\n\ninterface Props {\n children: React.ReactNode;\n // `reset` clears the caught error and renders `children` again, the same\n // thing the built-in error's reset button does.\n fallback?: (message?: string, reset?: () => void) => React.ReactNode;\n onError?: (e: Error, info: React.ErrorInfo) => void;\n // Values whose identity changing (typically the code/module that produced\n // `children`) should auto-recover a caught error without needing a\n // remount — compared shallowly, one entry at a time, same idea as\n // react-error-boundary's resetKeys. Without this, once tripped, render()\n // never even attempts `children` again (see below), so a fix to the\n // underlying code has no way to reach the screen until this array changes\n // or something remounts the boundary via `key`.\n resetKeys?: readonly unknown[];\n}\n\ninterface State {\n hasError: boolean;\n error?: Error;\n}\n\nclass ErrorBoundary extends React.Component<Props, State> {\n constructor(props: Props) {\n super(props);\n this.state = { hasError: false };\n }\n\n static getDerivedStateFromError(error: Error): State {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {\n console.error('🚨 [Boundary] Rendering error:', error, errorInfo);\n this.props.onError?.(error, errorInfo);\n }\n\n // Safe to reset unconditionally here (no race with a freshly-thrown\n // error): while hasError is true, render() below never attempts\n // `children` at all, so resetting just schedules a follow-up render where\n // `children` gets its first real chance to run with the new resetKeys —\n // if that throws too, getDerivedStateFromError catches it fresh in that\n // later, separate commit.\n componentDidUpdate(prevProps: Props) {\n if (!this.state.hasError) {\n return;\n }\n\n const prevKeys = prevProps.resetKeys ?? [];\n const nextKeys = this.props.resetKeys ?? [];\n const changed =\n prevKeys.length !== nextKeys.length ||\n nextKeys.some((key, i) => key !== prevKeys[i]);\n\n if (changed) {\n this.setState({ hasError: false, error: undefined });\n }\n }\n\n reset = () => this.setState({ hasError: false, error: undefined });\n\n render() {\n if (this.state.hasError) {\n return this.props.fallback ? (\n <>{this.props.fallback(this.state.error?.message, this.reset)}</>\n ) : (\n <Error\n message={this.state.error?.message}\n onReset={this.reset}\n title=\"Rendering Error\"\n />\n );\n }\n\n return this.props.children;\n }\n}\n\nexport default ErrorBoundary;\n"],"mappings":";;;;AAQA,MAAM,SAAS,EACb,SACA,QAAQ,qBACR,WACA,cACW;CACX,IAAI,CAAC,SACH,OAAO;CAGT,OACE,qBAAC,OAAD;EACE,WAAW,GAAG,SAAS;EACvB,OAAO;GACL,SAAS;GACT,iBAAiB;GACjB,QAAQ;GACR,cAAc;GACd,OAAO;EACT;EARF,UAAA;GAUE,oBAAC,MAAD;IAAI,OAAO;KAAE,UAAU;KAAQ,YAAY;KAAQ,QAAQ;IAAE;IAC1D,UAAA;GACC,CAAA;GACJ,oBAAC,OAAD;IACE,OAAO;KACL,WAAW;KACX,UAAU;KACV,YAAY;KACZ,QAAQ;IACV;IAEC,UAAA;GACE,CAAA;GACJ,WACC,oBAAC,UAAD;IACE,OAAO;KACL,WAAW;KACX,SAAS;KACT,UAAU;KACV,OAAO;KACP,iBAAiB;KACjB,QAAQ;KACR,cAAc;KACd,QAAQ;IACV;IACA,SAAS;IACV,UAAA;GAEO,CAAA;EAEP;;AAET;;;ACpCA,IAAM,gBAAN,cAA4B,MAAM,UAAwB;CACxD,YAAY,OAAc;EACxB,MAAM,KAAK;EACX,KAAK,QAAQ,EAAE,UAAU,MAAM;CACjC;CAEA,OAAO,yBAAyB,OAAqB;EACnD,OAAO;GAAE,UAAU;GAAM;EAAM;CACjC;CAEA,kBAAkB,OAAc,WAA4B;EAC1D,QAAQ,MAAM,kCAAkC,OAAO,SAAS;EAChE,KAAK,MAAM,UAAU,OAAO,SAAS;CACvC;CAQA,mBAAmB,WAAkB;EACnC,IAAI,CAAC,KAAK,MAAM,UACd;EAGF,MAAM,WAAW,UAAU,aAAa,CAAC;EACzC,MAAM,WAAW,KAAK,MAAM,aAAa,CAAC;EAK1C,IAHE,SAAS,WAAW,SAAS,UAC7B,SAAS,MAAM,KAAK,MAAM,QAAQ,SAAS,EAAE,GAG7C,KAAK,SAAS;GAAE,UAAU;GAAO,OAAO,KAAA;EAAU,CAAC;CAEvD;CAEA,cAAc,KAAK,SAAS;EAAE,UAAU;EAAO,OAAO,KAAA;CAAU,CAAC;CAEjE,SAAS;EACP,IAAI,KAAK,MAAM,UACb,OAAO,KAAK,MAAM,WAChB,oBAAA,UAAA,EAAA,UAAG,KAAK,MAAM,SAAS,KAAK,MAAM,OAAO,SAAS,KAAK,KAAK,EAAI,CAAA,IAEhE,oBAAC,OAAD;GACE,SAAS,KAAK,MAAM,OAAO;GAC3B,SAAS,KAAK;GACd,OAAM;EACP,CAAA;EAIL,OAAO,KAAK,MAAM;CACpB;AACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { H as DEFAULT_TEMPLATE } from "./extract-abHYmNsu.js";
|
|
2
|
+
import { f as registerEditorSession } from "./utils-BQ7WL7Jh.js";
|
|
3
3
|
import { n as PreviewContext, t as ErrorContext } from "./states-Ci1AvoQ9.js";
|
|
4
4
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
5
5
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -11,11 +11,7 @@ const ContextProvider = ({ children }) => {
|
|
|
11
11
|
setError(null);
|
|
12
12
|
setCodeState(next);
|
|
13
13
|
}, []);
|
|
14
|
-
useEffect(() =>
|
|
15
|
-
return () => {
|
|
16
|
-
clearCompilationCache();
|
|
17
|
-
};
|
|
18
|
-
}, []);
|
|
14
|
+
useEffect(() => registerEditorSession(), []);
|
|
19
15
|
const previewValue = useMemo(() => ({
|
|
20
16
|
code,
|
|
21
17
|
setCode
|
|
@@ -35,4 +31,4 @@ const ContextProvider = ({ children }) => {
|
|
|
35
31
|
//#endregion
|
|
36
32
|
export { ContextProvider as t };
|
|
37
33
|
|
|
38
|
-
//# sourceMappingURL=context-
|
|
34
|
+
//# sourceMappingURL=context-Y-M9fViD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-Y-M9fViD.js","names":[],"sources":["../src/components/context/context.tsx"],"sourcesContent":["'use client';\n\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { DEFAULT_TEMPLATE } from '~/constants';\nimport { registerEditorSession } from '~/utils';\n\nimport type { ErrorContextType, PreviewContextType } from './states';\nimport { ErrorContext, PreviewContext } from './states';\n\nconst ContextProvider = ({ children }: { children?: React.ReactNode }) => {\n const [code, setCodeState] = useState(DEFAULT_TEMPLATE);\n const [error, setError] = useState<ErrorContextType['error']>(null);\n\n // Clears any stale runtime/compile error in the same update batch that\n // changes `code`, rather than in a separate useEffect — a useEffect here\n // would race with componentDidCatch/Guard's onError firing for the *new*\n // code's own errors within the same commit (layout effects run before\n // passive effects, so a passive-effect reset could wipe out an error the\n // new code just threw). Batching setError(null) into the same update as\n // setCode guarantees stale errors are gone by the time the new code even\n // renders, with nothing left afterward that could clobber a fresh one.\n const setCode = useCallback<PreviewContextType['setCode']>(next => {\n setError(null);\n setCodeState(next);\n }, []);\n\n // The provider is the ownership boundary for every editor-owned cache, not\n // just the compilation one it used to clear here: parsed documents,\n // extracted bindings and the blob URLs generated for external scripts all\n // outlive an editing session otherwise, released only when the LRU happens\n // to evict them. registerEditorSession both counts this session and hands\n // back the release, so the caches go when the last provider does.\n useEffect(() => registerEditorSession(), []);\n\n // Without this, a new object identity on every ContextProvider render\n // (even ones that don't touch code/error at all, e.g. a parent\n // re-rendering) meant every usePreview()/useError() consumer re-rendered\n // too, regardless of whether the values they care about actually changed.\n const previewValue = useMemo<PreviewContextType>(\n () => ({ code, setCode }),\n [code, setCode],\n );\n\n const errorValue = useMemo<ErrorContextType>(\n () => ({ error, setError }),\n [error, setError],\n );\n\n return (\n <PreviewContext.Provider value={previewValue}>\n <ErrorContext.Provider value={errorValue}>\n {children}\n </ErrorContext.Provider>\n </PreviewContext.Provider>\n );\n};\n\nexport default ContextProvider;\n"],"mappings":";;;;;;AAUA,MAAM,mBAAmB,EAAE,eAA+C;CACxE,MAAM,CAAC,MAAM,gBAAgB,SAAS,gBAAgB;CACtD,MAAM,CAAC,OAAO,YAAY,SAAoC,IAAI;CAUlE,MAAM,UAAU,aAA2C,SAAQ;EACjE,SAAS,IAAI;EACb,aAAa,IAAI;CACnB,GAAG,CAAC,CAAC;CAQL,gBAAgB,sBAAsB,GAAG,CAAC,CAAC;CAM3C,MAAM,eAAe,eACZ;EAAE;EAAM;CAAQ,IACvB,CAAC,MAAM,OAAO,CAChB;CAEA,MAAM,aAAa,eACV;EAAE;EAAO;CAAS,IACzB,CAAC,OAAO,QAAQ,CAClB;CAEA,OACE,oBAAC,eAAe,UAAhB;EAAyB,OAAO;EAC9B,UAAA,oBAAC,aAAa,UAAd;GAAuB,OAAO;GAC3B;EACoB,CAAA;CACA,CAAA;AAE7B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as cn, o as detectTypeScript } from "./utils-BQ7WL7Jh.js";
|
|
2
2
|
import { useCallback, useMemo } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
import CodeEditor from "@jbpark/ui-kit/CodeEditor";
|
|
@@ -74,4 +74,4 @@ const Core = ({ value, theme, height, className, prettierOptions, fragment, raw,
|
|
|
74
74
|
//#endregion
|
|
75
75
|
export { useFormatCode as n, Core as t };
|
|
76
76
|
|
|
77
|
-
//# sourceMappingURL=core-
|
|
77
|
+
//# sourceMappingURL=core-Co8Nlq16.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core-
|
|
1
|
+
{"version":3,"file":"core-Co8Nlq16.js","names":[],"sources":["../src/components/editor/use-format-code.ts","../src/components/editor/core.tsx"],"sourcesContent":["import { useCallback, useMemo } from 'react';\n\nimport { detectTypeScript } from '~/utils';\n\n// prettier is an optional peer dependency (#282): the editor subpath is the\n// only thing that needs it, so consumers who don't use format-on-save\n// shouldn't have to install ~9.6 MB. It's loaded lazily below and its absence\n// degrades gracefully (the code is returned unformatted) instead of throwing.\nconst loadPrettier = async () => {\n const [prettier, babel, estree, typescript] = await Promise.all([\n import('prettier'),\n import('prettier/plugins/babel'),\n import('prettier/plugins/estree'),\n import('prettier/plugins/typescript'),\n ]);\n\n return {\n format: prettier.format,\n plugins: [babel.default, estree.default, typescript.default],\n };\n};\n\nconst DEFAULT_PRETTIER_OPTIONS: Record<string, unknown> = {\n tabWidth: 2,\n singleQuote: true,\n trailingComma: 'all',\n htmlWhitespaceSensitivity: 'ignore',\n arrowParens: 'avoid',\n printWidth: 60,\n};\n\nexport interface UseFormatCodeOptions {\n fragment?: boolean;\n prettierOptions?: Record<string, unknown>;\n}\n\n// Extracted out of Core so a custom renderEditor (see editor.tsx's\n// renderEditor prop) can reuse the exact same formatting behavior instead\n// of reimplementing prettier wiring from scratch.\nexport const useFormatCode = ({\n fragment,\n prettierOptions,\n}: UseFormatCodeOptions = {}) => {\n const prettierConfig = useMemo(\n () => ({\n ...DEFAULT_PRETTIER_OPTIONS,\n ...prettierOptions,\n }),\n [prettierOptions],\n );\n\n return useCallback(\n async (code: string) => {\n const isTypeScript = detectTypeScript(code);\n const source = fragment ? `<>${code}</>` : code;\n\n // Only a missing prettier is swallowed here; a genuine format error\n // (prettier present, but the code is unparseable) still propagates so\n // the editor's Cmd+S path can surface it via onError.\n let prettier: Awaited<ReturnType<typeof loadPrettier>>;\n try {\n prettier = await loadPrettier();\n } catch {\n return code;\n }\n\n const formatted = await prettier.format(source, {\n parser: isTypeScript ? 'typescript' : 'babel',\n plugins: prettier.plugins,\n ...prettierConfig,\n });\n\n if (fragment) {\n return formatted\n .replace(/^<>\\n?/, '')\n .replace(/\\n?<\\/>;?\\s*$/, '')\n .replace(/^ {2}/gm, '')\n .trim();\n }\n\n return formatted;\n },\n [prettierConfig, fragment],\n );\n};\n","import type { ComponentProps } from 'react';\n\nimport CodeEditor from '@jbpark/ui-kit/CodeEditor';\nimport { vscodeLight } from '@uiw/codemirror-theme-vscode';\nimport { type Extension } from '@uiw/react-codemirror';\n\nimport { cn } from '~/utils';\n\nimport { useFormatCode } from './use-format-code';\n\nexport interface Props {\n value: string;\n height?: string;\n theme?: Extension | 'light' | 'dark' | 'none';\n prettierOptions?: Record<string, unknown>;\n fragment?: boolean;\n raw?: boolean;\n className?: string;\n onChange?: (value: string) => void;\n onSave?: (value: string) => void;\n onError?: (error: string | null) => void;\n onCreateEditor?: ComponentProps<typeof CodeEditor>['onCreateEditor'];\n onUpdate?: ComponentProps<typeof CodeEditor>['onUpdate'];\n}\n\n// The CodeMirror surface, the Cmd+S save transaction and the JS/TS + line-wrap\n// extensions now live in `@jbpark/ui-kit`'s CodeEditor (#346/#309). This stays\n// only to keep live-editor's own vocabulary: `raw`/`fragment`/`prettierOptions`\n// shape the injected prettier formatter, and `onError` maps to the component's\n// `onFormatError`.\nconst Core = ({\n value,\n theme,\n height,\n className,\n prettierOptions,\n fragment,\n raw,\n onChange,\n onSave,\n onError,\n ...props\n}: Props) => {\n const formatCode = useFormatCode({ fragment, prettierOptions });\n\n return (\n <CodeEditor\n value={value}\n theme={theme ?? vscodeLight}\n height={height || '100%'}\n className={cn(className)}\n // `raw` (e.g. innerHTML) skips prettier; otherwise reuse the shared\n // prettier wiring as the Cmd+S formatter rather than reimplementing it.\n formatCode={raw ? undefined : formatCode}\n onChange={onChange}\n onSave={onSave}\n onFormatError={onError}\n {...props}\n />\n );\n};\n\nexport default Core;\n"],"mappings":";;;;;;;AAQA,MAAM,eAAe,YAAY;CAC/B,MAAM,CAAC,UAAU,OAAO,QAAQ,cAAc,MAAM,QAAQ,IAAI;EAC9D,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;CACT,CAAC;CAED,OAAO;EACL,QAAQ,SAAS;EACjB,SAAS;GAAC,MAAM;GAAS,OAAO;GAAS,WAAW;EAAO;CAC7D;AACF;AAEA,MAAM,2BAAoD;CACxD,UAAU;CACV,aAAa;CACb,eAAe;CACf,2BAA2B;CAC3B,aAAa;CACb,YAAY;AACd;AAUA,MAAa,iBAAiB,EAC5B,UACA,oBACwB,CAAC,MAAM;CAC/B,MAAM,iBAAiB,eACd;EACL,GAAG;EACH,GAAG;CACL,IACA,CAAC,eAAe,CAClB;CAEA,OAAO,YACL,OAAO,SAAiB;EACtB,MAAM,eAAe,iBAAiB,IAAI;EAC1C,MAAM,SAAS,WAAW,KAAK,KAAK,OAAO;EAK3C,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,aAAa;EAChC,QAAQ;GACN,OAAO;EACT;EAEA,MAAM,YAAY,MAAM,SAAS,OAAO,QAAQ;GAC9C,QAAQ,eAAe,eAAe;GACtC,SAAS,SAAS;GAClB,GAAG;EACL,CAAC;EAED,IAAI,UACF,OAAO,UACJ,QAAQ,UAAU,EAAE,CAAC,CACrB,QAAQ,iBAAiB,EAAE,CAAC,CAC5B,QAAQ,WAAW,EAAE,CAAC,CACtB,KAAK;EAGV,OAAO;CACT,GACA,CAAC,gBAAgB,QAAQ,CAC3B;AACF;;;ACtDA,MAAM,QAAQ,EACZ,OACA,OACA,QACA,WACA,iBACA,UACA,KACA,UACA,QACA,SACA,GAAG,YACQ;CACX,MAAM,aAAa,cAAc;EAAE;EAAU;CAAgB,CAAC;CAE9D,OACE,oBAAC,YAAD;EACS;EACP,OAAO,SAAS;EAChB,QAAQ,UAAU;EAClB,WAAW,GAAG,SAAS;EAGvB,YAAY,MAAM,KAAA,IAAY;EACpB;EACF;EACR,eAAe;EACf,GAAI;CACL,CAAA;AAEL"}
|
package/dist/dnd/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { Canvas, type ChildrenEditor, type ChildrenEditorOptions, type DndLayout, type DndLayoutProps, type DndPalette, type DndPanel, type DndRegionProps, DraggableItem, type DraggableItemDragState, type DraggableItemProps, Field, type FieldProps,
|
|
1
|
+
import { A as PanelBinding, C as DraggableItemDragState, D as Props, E as DndPanel, F as FieldProps, M as DndEditError, N as DndRenderField, O as DndRenderSectionFallback, P as Field, S as DraggableItem, T as DndPalette, _ as DndLayoutProps, a as ItemsEditor, b as Palette, c as ItemsEditorNestedElement, d as useItemsEditor, f as DndLayout, g as Canvas, h as useDndPanel, i as useChildrenEditor, j as PanelNodeChange, k as DndSectionFallbackArgs, l as ItemsEditorNestedGroup, m as useDndPalette, n as ChildrenEditor, o as ItemsEditorActions, p as useDndLayout, r as ChildrenEditorOptions, s as ItemsEditorItem, t as Dnd, u as ItemsEditorOptions, v as DndRegionProps, w as DraggableItemProps, x as Panel, y as Layout } from "../index-Doh4VTXr.js";
|
|
2
|
+
export { Canvas, type ChildrenEditor, type ChildrenEditorOptions, type DndEditError, type DndLayout, type DndLayoutProps, type DndPalette, type DndPanel, type DndRegionProps, type DndRenderField, type DndRenderSectionFallback, type DndSectionFallbackArgs, DraggableItem, type DraggableItemDragState, type DraggableItemProps, Field, type FieldProps, type ItemsEditor, type ItemsEditorActions, type ItemsEditorItem, type ItemsEditorNestedElement, type ItemsEditorNestedGroup, type ItemsEditorOptions, Layout, Palette, Panel, type PanelBinding, type PanelNodeChange, type Props, Dnd as default, useChildrenEditor, useDndLayout, useDndPalette, useDndPanel, useItemsEditor };
|
package/dist/dnd/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as Panel, c as
|
|
2
|
-
export { Canvas, DraggableItem, Field,
|
|
1
|
+
import { a as Panel, c as useChildrenEditor, d as useDndPanel, f as DraggableItem, i as Palette, l as useDndLayout, n as Canvas, o as Field, r as Layout, s as useItemsEditor, t as Dnd, u as useDndPalette } from "../dnd-ClnGRNaY.js";
|
|
2
|
+
export { Canvas, DraggableItem, Field, Layout, Palette, Panel, Dnd as default, useChildrenEditor, useDndLayout, useDndPalette, useDndPanel, useItemsEditor };
|