@improba/page-builder 0.1.3 → 0.2.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.
Files changed (66) hide show
  1. package/dist/core.cjs +2 -0
  2. package/dist/core.cjs.map +1 -0
  3. package/dist/core.js +29 -0
  4. package/dist/core.js.map +1 -0
  5. package/dist/index-D79WbFRY.cjs +2 -0
  6. package/dist/index-D79WbFRY.cjs.map +1 -0
  7. package/dist/index-c6HOrx9r.js +523 -0
  8. package/dist/index-c6HOrx9r.js.map +1 -0
  9. package/dist/index.cjs +10 -5
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.js +1757 -2185
  12. package/dist/index.js.map +1 -1
  13. package/dist/{index.css → style.css} +1 -1
  14. package/dist/types/built-in/PbColumn.vue.d.ts +41 -0
  15. package/dist/types/built-in/PbContainer.vue.d.ts +32 -0
  16. package/dist/types/built-in/PbImage.vue.d.ts +42 -0
  17. package/dist/types/built-in/PbRow.vue.d.ts +41 -0
  18. package/dist/types/built-in/PbSection.vue.d.ts +50 -0
  19. package/dist/types/built-in/PbText.vue.d.ts +25 -0
  20. package/dist/types/built-in/PbVideo.vue.d.ts +27 -0
  21. package/dist/types/built-in/index.d.ts +10 -0
  22. package/dist/types/components/PageBuilder.vue.d.ts +50 -0
  23. package/dist/types/components/editor/EditorCanvas.vue.d.ts +67 -0
  24. package/dist/types/components/editor/EditorToolbar.vue.d.ts +97 -0
  25. package/dist/types/components/editor/IframeCanvas.vue.d.ts +102 -0
  26. package/dist/types/components/editor/LeftDrawer.vue.d.ts +46 -0
  27. package/dist/types/components/editor/NodeContextMenu.vue.d.ts +66 -0
  28. package/dist/types/components/editor/PageEditor.vue.d.ts +20 -0
  29. package/dist/types/components/editor/RightDrawer.vue.d.ts +43 -0
  30. package/dist/types/components/editor/TreePanel.vue.d.ts +28 -0
  31. package/dist/types/components/editor/prop-editors/MediaPicker.vue.d.ts +20 -0
  32. package/dist/types/components/editor/prop-editors/PropBooleanEditor.vue.d.ts +18 -0
  33. package/dist/types/components/editor/prop-editors/PropColorEditor.vue.d.ts +18 -0
  34. package/dist/types/components/editor/prop-editors/PropNumberEditor.vue.d.ts +36 -0
  35. package/dist/types/components/editor/prop-editors/PropSelectEditor.vue.d.ts +31 -0
  36. package/dist/types/components/editor/prop-editors/PropTextEditor.vue.d.ts +27 -0
  37. package/dist/types/components/editor/prop-editors/RichTextEditor.vue.d.ts +27 -0
  38. package/dist/types/components/editor/prop-editors/index.d.ts +29 -0
  39. package/dist/types/components/reader/NodeRenderer.vue.d.ts +33 -0
  40. package/dist/types/components/reader/PageReader.vue.d.ts +14 -0
  41. package/dist/types/components/shared/ErrorBoundary.vue.d.ts +21 -0
  42. package/dist/types/composables/use-drag-drop.d.ts +23 -0
  43. package/dist/types/composables/use-editor.d.ts +40 -0
  44. package/dist/types/composables/use-node-tree.d.ts +23 -0
  45. package/dist/types/composables/use-page-builder.d.ts +28 -0
  46. package/dist/types/core/drop-slot.d.ts +12 -0
  47. package/dist/types/core/errors.d.ts +14 -0
  48. package/dist/types/core/iframe-bridge.d.ts +85 -0
  49. package/dist/types/core/index.d.ts +18 -0
  50. package/dist/types/core/registry.d.ts +43 -0
  51. package/dist/types/core/sanitize.d.ts +3 -0
  52. package/dist/types/core/tree.d.ts +56 -0
  53. package/dist/types/core/validation.d.ts +10 -0
  54. package/dist/types/core/virtual-tree.d.ts +44 -0
  55. package/dist/types/i18n/context.d.ts +13 -0
  56. package/dist/types/i18n/index.d.ts +3 -0
  57. package/dist/types/i18n/messages.d.ts +3 -0
  58. package/dist/types/i18n/translator.d.ts +14 -0
  59. package/dist/types/index.d.ts +27 -0
  60. package/dist/types/plugin.d.ts +18 -0
  61. package/dist/types/types/component.d.ts +68 -0
  62. package/dist/types/types/editor.d.ts +54 -0
  63. package/dist/types/types/index.d.ts +6 -0
  64. package/dist/types/types/keys.d.ts +13 -0
  65. package/dist/types/types/node.d.ts +54 -0
  66. package/package.json +7 -2
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/core/errors.ts","../src/core/registry.ts","../src/built-in/PbColumn.vue","../src/built-in/PbRow.vue","../src/core/sanitize.ts","../src/built-in/PbText.vue","../src/built-in/PbImage.vue","../src/built-in/PbVideo.vue","../src/built-in/PbSection.vue","../src/built-in/PbContainer.vue","../src/built-in/index.ts","../src/core/validation.ts","../src/i18n/messages.ts","../src/i18n/translator.ts","../src/i18n/context.ts","../src/core/tree.ts","../src/components/shared/ErrorBoundary.vue","../src/components/reader/NodeRenderer.vue","../src/components/reader/PageReader.vue","../src/types/editor.ts","../src/types/keys.ts","../src/composables/use-page-builder.ts","../src/composables/use-editor.ts","../src/composables/use-node-tree.ts","../src/composables/use-drag-drop.ts","../src/components/editor/EditorToolbar.vue","../src/core/drop-slot.ts","../src/core/virtual-tree.ts","../src/components/editor/TreePanel.vue","../src/components/editor/LeftDrawer.vue","../src/components/editor/prop-editors/PropTextEditor.vue","../src/components/editor/prop-editors/PropNumberEditor.vue","../src/components/editor/prop-editors/PropBooleanEditor.vue","../src/components/editor/prop-editors/PropSelectEditor.vue","../src/components/editor/prop-editors/PropColorEditor.vue","../src/components/editor/prop-editors/RichTextEditor.vue","../src/components/editor/prop-editors/MediaPicker.vue","../src/components/editor/prop-editors/index.ts","../src/components/editor/RightDrawer.vue","../src/core/iframe-bridge.ts","../src/components/editor/NodeContextMenu.vue","../src/components/editor/IframeCanvas.vue","../src/components/editor/PageEditor.vue","../src/components/PageBuilder.vue","../src/plugin.ts","../src/types/component.ts"],"sourcesContent":["export type PageBuilderErrorCode =\n | 'INVALID_PAGE_DATA'\n | 'INVALID_NODE'\n | 'INVALID_SNAPSHOT'\n | 'MISSING_COMPONENT'\n | 'DUPLICATE_COMPONENT'\n | 'RENDER_FAILURE'\n | 'UNKNOWN';\n\nexport interface PageBuilderErrorOptions {\n details?: Record<string, unknown>;\n cause?: unknown;\n}\n\nexport class PageBuilderError extends Error {\n readonly code: PageBuilderErrorCode;\n readonly details: Record<string, unknown>;\n\n constructor(code: PageBuilderErrorCode, message: string, options: PageBuilderErrorOptions = {}) {\n super(message);\n this.name = 'PageBuilderError';\n this.code = code;\n this.details = options.details ?? {};\n this.cause = options.cause;\n }\n}\n\nexport function isPageBuilderError(error: unknown): error is PageBuilderError {\n return error instanceof PageBuilderError;\n}\n\nexport function createPageBuilderError(\n code: PageBuilderErrorCode,\n message: string,\n options: PageBuilderErrorOptions = {},\n): PageBuilderError {\n return new PageBuilderError(code, message, options);\n}\n\nexport function toErrorMessage(error: unknown): string {\n if (error instanceof Error) return error.message;\n return String(error);\n}\n\nexport function reportDevDiagnostic(\n context: string,\n error: unknown,\n details?: Record<string, unknown>,\n): void {\n if (!import.meta.env.DEV) return;\n const normalized = isPageBuilderError(error)\n ? error\n : createPageBuilderError('UNKNOWN', toErrorMessage(error), {\n cause: error,\n details,\n });\n\n const mergedDetails = details\n ? {\n ...normalized.details,\n ...details,\n }\n : normalized.details;\n\n console.error(`[PageBuilder][${context}] ${normalized.message}`, {\n code: normalized.code,\n details: mergedDetails,\n cause: normalized.cause,\n });\n}\n","import type { Component } from 'vue';\nimport type { IComponentDefinition } from '@/types/component';\nimport { createPageBuilderError } from '@/core/errors';\n\n// Core registry intentionally uses a plain Map to preserve reference identity\n// and avoid coupling core logic to Vue reactivity internals.\nconst _registry = new Map<string, IComponentDefinition>();\n\nfunction getRegistrySnapshot(): string {\n const names = [..._registry.keys()];\n return names.length > 0 ? names.join(', ') : '(none)';\n}\n\nfunction normalizeComponentName(name: string): string {\n return name.trim();\n}\n\nfunction createDuplicateComponentError(name: string, message: string) {\n return createPageBuilderError(\n 'DUPLICATE_COMPONENT',\n message,\n {\n details: {\n componentName: name,\n },\n },\n );\n}\n\nfunction normalizeAndValidateDefinition(\n definition: IComponentDefinition,\n action: 'register' | 'replace',\n): IComponentDefinition {\n const normalizedName = normalizeComponentName(definition.name);\n const normalizedDefinition =\n normalizedName === definition.name ? definition : { ...definition, name: normalizedName };\n if (!normalizedName) {\n throw createPageBuilderError(\n 'INVALID_PAGE_DATA',\n `[PageBuilder] Cannot ${action} a component without a name.`,\n );\n }\n\n if (!normalizedDefinition.component) {\n throw createPageBuilderError(\n 'INVALID_PAGE_DATA',\n `[PageBuilder] Component \"${normalizedName}\" is missing a Vue component instance.`,\n );\n }\n\n return normalizedDefinition;\n}\n\n/**\n * Register a component for use in the page builder.\n * Throws if a component with the same name is already registered.\n */\nexport function registerComponent(definition: IComponentDefinition): void {\n const normalizedDefinition = normalizeAndValidateDefinition(definition, 'register');\n const normalizedName = normalizedDefinition.name;\n\n if (_registry.has(normalizedName)) {\n throw createDuplicateComponentError(\n normalizedName,\n `[PageBuilder] Component \"${normalizedName}\" is already registered. Use replaceComponent() to override.`,\n );\n }\n\n _registry.set(normalizedName, normalizedDefinition);\n}\n\n/**\n * Register multiple components at once.\n */\nexport function registerComponents(definitions: IComponentDefinition[]): void {\n const normalizedDefinitions = definitions.map((definition) =>\n normalizeAndValidateDefinition(definition, 'register'),\n );\n const batchNames = new Set<string>();\n\n for (const definition of normalizedDefinitions) {\n if (batchNames.has(definition.name)) {\n throw createDuplicateComponentError(\n definition.name,\n `[PageBuilder] Component \"${definition.name}\" appears multiple times in the registration batch.`,\n );\n }\n batchNames.add(definition.name);\n\n if (_registry.has(definition.name)) {\n throw createDuplicateComponentError(\n definition.name,\n `[PageBuilder] Component \"${definition.name}\" is already registered. Use replaceComponent() to override.`,\n );\n }\n }\n\n for (const definition of normalizedDefinitions) {\n _registry.set(definition.name, definition);\n }\n}\n\n/**\n * Replace an existing component registration.\n */\nexport function replaceComponent(definition: IComponentDefinition): void {\n const normalizedDefinition = normalizeAndValidateDefinition(definition, 'replace');\n const normalizedName = normalizedDefinition.name;\n\n _registry.set(normalizedName, normalizedDefinition);\n}\n\n/**\n * Unregister a component by name.\n */\nexport function unregisterComponent(name: string): boolean {\n return _registry.delete(normalizeComponentName(name));\n}\n\n/**\n * Retrieve a component definition by name. Returns undefined if not found.\n */\nexport function getComponent(name: string): IComponentDefinition | undefined {\n return _registry.get(normalizeComponentName(name));\n}\n\n/**\n * Retrieve the Vue component for rendering. Throws if not found.\n */\nexport function resolveComponent(name: string): Component {\n const normalizedName = normalizeComponentName(name);\n const def = _registry.get(normalizedName);\n if (!def) {\n throw createPageBuilderError(\n 'MISSING_COMPONENT',\n `[PageBuilder] Component \"${normalizedName}\" is not registered. Available: ${getRegistrySnapshot()}`,\n {\n details: {\n componentName: normalizedName,\n availableComponents: [..._registry.keys()],\n },\n },\n );\n }\n return def.component;\n}\n\n/**\n * Get all registered component definitions.\n */\nexport function getRegisteredComponents(): IComponentDefinition[] {\n return [..._registry.values()];\n}\n\n/**\n * Get all registered component definitions grouped by category.\n */\nexport function getComponentsByCategory(): Map<string, IComponentDefinition[]> {\n const grouped = new Map<string, IComponentDefinition[]>();\n for (const def of _registry.values()) {\n if (def.hidden) continue;\n const list = grouped.get(def.category) ?? [];\n list.push(def);\n grouped.set(def.category, list);\n }\n return grouped;\n}\n\n/**\n * Check if a component is registered.\n */\nexport function hasComponent(name: string): boolean {\n return _registry.has(normalizeComponentName(name));\n}\n\n/**\n * Clear all registered components. Mainly useful for testing.\n */\nexport function clearRegistry(): void {\n _registry.clear();\n}\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbColumn',\n label: 'Column',\n description: 'Vertical flex container for stacking components.',\n category: 'layout',\n icon: '⬜',\n component: {} as any, // self-reference set at registration\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'gap', label: 'Gap', type: 'text', defaultValue: '16px' },\n { key: 'padding', label: 'Padding', type: 'text', defaultValue: '0' },\n { key: 'align', label: 'Align Items', type: 'select', defaultValue: 'stretch', options: [\n { label: 'Stretch', value: 'stretch' },\n { label: 'Start', value: 'flex-start' },\n { label: 'Center', value: 'center' },\n { label: 'End', value: 'flex-end' },\n ]},\n ],\n defaultProps: { gap: '16px', padding: '0', align: 'stretch' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n gap: { type: String, default: '16px' },\n padding: { type: String, default: '0' },\n align: { type: String, default: 'stretch' },\n });\n\n const style = computed(() => ({\n display: 'flex',\n flexDirection: 'column' as const,\n gap: props.gap,\n padding: props.padding,\n alignItems: props.align,\n width: '100%',\n }));\n</script>\n\n<template>\n <div :style=\"style\">\n <slot />\n </div>\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbRow',\n label: 'Row',\n description: 'Horizontal flex container for side-by-side components.',\n category: 'layout',\n icon: '⬛',\n component: {} as any,\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'gap', label: 'Gap', type: 'text', defaultValue: '16px' },\n { key: 'wrap', label: 'Wrap', type: 'boolean', defaultValue: true },\n { key: 'justify', label: 'Justify', type: 'select', defaultValue: 'flex-start', options: [\n { label: 'Start', value: 'flex-start' },\n { label: 'Center', value: 'center' },\n { label: 'End', value: 'flex-end' },\n { label: 'Space Between', value: 'space-between' },\n { label: 'Space Around', value: 'space-around' },\n ]},\n ],\n defaultProps: { gap: '16px', wrap: true, justify: 'flex-start' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n gap: { type: String, default: '16px' },\n wrap: { type: Boolean, default: true },\n justify: { type: String, default: 'flex-start' },\n });\n\n const style = computed(() => ({\n display: 'flex',\n flexDirection: 'row' as const,\n gap: props.gap,\n flexWrap: props.wrap ? ('wrap' as const) : ('nowrap' as const),\n justifyContent: props.justify,\n width: '100%',\n }));\n</script>\n\n<template>\n <div :style=\"style\">\n <slot />\n </div>\n</template>\n","const SAFE_TEXT_CONTAINER_TAGS = new Set([\n 'div',\n 'p',\n 'span',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'section',\n 'article',\n 'blockquote',\n]);\n\nconst SAFE_RICH_TEXT_TAGS = new Set([\n 'a',\n 'b',\n 'blockquote',\n 'br',\n 'code',\n 'div',\n 'em',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'i',\n 'li',\n 'ol',\n 'p',\n 'pre',\n 's',\n 'span',\n 'strong',\n 'u',\n 'ul',\n]);\n\nconst DROP_ENTIRELY_TAGS = new Set([\n 'base',\n 'embed',\n 'form',\n 'iframe',\n 'input',\n 'link',\n 'math',\n 'meta',\n 'noscript',\n 'object',\n 'script',\n 'style',\n 'svg',\n 'template',\n 'textarea',\n]);\n\nconst SAFE_LINK_TARGETS = new Set(['_blank', '_parent', '_self', '_top']);\nconst SAFE_LINK_REL_TOKENS = new Set(['nofollow', 'noopener', 'noreferrer', 'sponsored', 'ugc']);\nconst SAFE_DATA_IMAGE_URL_PATTERN = /^data:image\\/(?:avif|bmp|gif|jpe?g|png|webp);base64,[a-z0-9+/=\\s]+$/i;\n\nfunction stripControlCharacters(value: string): string {\n return value.replace(/[\\u0000-\\u001F\\u007F]/g, '');\n}\n\nfunction normalizeProtocolProbe(value: string): string {\n return stripControlCharacters(value).replace(/\\s+/g, '');\n}\n\nfunction sanitizeLinkRel(rel: string): string {\n const safeTokens = rel\n .toLowerCase()\n .split(/\\s+/)\n .filter(Boolean)\n .filter((token) => SAFE_LINK_REL_TOKENS.has(token));\n return Array.from(new Set(safeTokens)).join(' ');\n}\n\nfunction withSafeBlankTargetRel(existingRel: string | null): string {\n const safeRel = sanitizeLinkRel(existingRel ?? '');\n const relTokens = new Set(safeRel.split(/\\s+/).filter(Boolean));\n relTokens.add('noopener');\n relTokens.add('noreferrer');\n return Array.from(relTokens).join(' ');\n}\n\nfunction createSanitizationDocument(): Document | null {\n if (\n typeof document !== 'undefined'\n && typeof document.implementation?.createHTMLDocument === 'function'\n ) {\n return document.implementation.createHTMLDocument('');\n }\n\n if (typeof DOMParser !== 'undefined') {\n const parsed = new DOMParser().parseFromString('<!doctype html><html><body></body></html>', 'text/html');\n if (parsed?.body) return parsed;\n }\n\n return null;\n}\n\nfunction escapeHtml(rawHtml: string): string {\n return rawHtml\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;');\n}\n\nfunction sanitizeRichTextAttributes(source: Element, target: HTMLElement): void {\n const tagName = target.tagName.toLowerCase();\n\n for (const attribute of Array.from(source.attributes)) {\n const attrName = attribute.name.toLowerCase();\n const attrValue = stripControlCharacters(attribute.value).trim();\n\n if (attrValue.length === 0 || attrName.startsWith('on')) continue;\n\n if (attrName === 'title') {\n target.setAttribute('title', attrValue);\n continue;\n }\n\n if (tagName !== 'a') continue;\n\n if (attrName === 'href') {\n const sanitizedHref = sanitizeUrlByKind(attrValue, 'link');\n if (sanitizedHref.length > 0) target.setAttribute('href', sanitizedHref);\n continue;\n }\n\n if (attrName === 'target') {\n const normalizedTarget = attrValue.toLowerCase();\n if (SAFE_LINK_TARGETS.has(normalizedTarget)) {\n target.setAttribute('target', normalizedTarget);\n }\n continue;\n }\n\n if (attrName === 'rel') {\n const sanitizedRel = sanitizeLinkRel(attrValue);\n if (sanitizedRel.length > 0) target.setAttribute('rel', sanitizedRel);\n }\n }\n\n if (tagName === 'a' && target.getAttribute('target') === '_blank') {\n target.setAttribute('rel', withSafeBlankTargetRel(target.getAttribute('rel')));\n }\n}\n\nfunction sanitizeRichTextChildren(source: ParentNode, target: ParentNode, doc: Document): void {\n for (const node of Array.from(source.childNodes)) {\n if (node.nodeType === 3) {\n target.appendChild(doc.createTextNode(node.textContent ?? ''));\n continue;\n }\n\n if (node.nodeType !== 1) continue;\n\n const sourceElement = node as Element;\n const sourceTagName = sourceElement.tagName.toLowerCase();\n\n if (DROP_ENTIRELY_TAGS.has(sourceTagName)) continue;\n\n if (!SAFE_RICH_TEXT_TAGS.has(sourceTagName)) {\n const unwrappedChildren = doc.createDocumentFragment();\n sanitizeRichTextChildren(sourceElement, unwrappedChildren, doc);\n target.appendChild(unwrappedChildren);\n continue;\n }\n\n const sanitizedElement = doc.createElement(sourceTagName);\n sanitizeRichTextAttributes(sourceElement, sanitizedElement);\n sanitizeRichTextChildren(sourceElement, sanitizedElement, doc);\n\n if (sourceTagName === 'a' && !sanitizedElement.getAttribute('href')) {\n const safeChildren = doc.createDocumentFragment();\n while (sanitizedElement.firstChild) {\n safeChildren.appendChild(sanitizedElement.firstChild);\n }\n target.appendChild(safeChildren);\n continue;\n }\n\n target.appendChild(sanitizedElement);\n }\n}\n\nexport function sanitizeRichTextHtml(html: string): string {\n const rawHtml = typeof html === 'string' ? html : '';\n if (rawHtml.length === 0) return '';\n\n const doc = createSanitizationDocument();\n if (!doc) return escapeHtml(rawHtml);\n\n const source = doc.createElement('div');\n source.innerHTML = rawHtml;\n\n const output = doc.createElement('div');\n sanitizeRichTextChildren(source, output, doc);\n return output.innerHTML;\n}\n\nexport function normalizeSafeHtmlTag(tag: unknown, fallback = 'div'): string {\n const normalizedFallback = typeof fallback === 'string' ? fallback.trim().toLowerCase() : 'div';\n const safeFallback = SAFE_TEXT_CONTAINER_TAGS.has(normalizedFallback) ? normalizedFallback : 'div';\n if (typeof tag !== 'string') return safeFallback;\n\n const normalizedTag = tag.trim().toLowerCase();\n if (!SAFE_TEXT_CONTAINER_TAGS.has(normalizedTag)) return safeFallback;\n return normalizedTag;\n}\n\nexport function sanitizeUrlByKind(url: string, kind: 'link' | 'media' | 'background'): string {\n const sanitizedInput = stripControlCharacters(url).trim();\n if (sanitizedInput.length === 0) return '';\n\n const protocolProbe = normalizeProtocolProbe(sanitizedInput).toLowerCase();\n const schemeMatch = protocolProbe.match(/^([a-z][a-z0-9+.-]*):/i);\n const scheme = schemeMatch?.[1];\n\n if (!scheme) return sanitizedInput;\n\n if (scheme === 'http' || scheme === 'https') return sanitizedInput;\n\n if (kind === 'link' && (scheme === 'mailto' || scheme === 'tel')) {\n return sanitizedInput;\n }\n\n if (kind === 'media' && scheme === 'blob') {\n return sanitizedInput;\n }\n\n if ((kind === 'media' || kind === 'background') && scheme === 'data') {\n return SAFE_DATA_IMAGE_URL_PATTERN.test(protocolProbe) ? sanitizedInput : '';\n }\n\n return '';\n}\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbText',\n label: 'Text',\n description: 'A text block with HTML support.',\n category: 'content',\n icon: 'T',\n component: {} as any,\n slots: [],\n editableProps: [\n { key: 'content', label: 'Content', type: 'richtext', defaultValue: '<p>Enter text here</p>' },\n { key: 'tag', label: 'HTML Tag', type: 'select', defaultValue: 'div', options: [\n { label: 'div', value: 'div' },\n { label: 'p', value: 'p' },\n { label: 'span', value: 'span' },\n { label: 'h1', value: 'h1' },\n { label: 'h2', value: 'h2' },\n { label: 'h3', value: 'h3' },\n ]},\n ],\n defaultProps: { content: '<p>Enter text here</p>', tag: 'div' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { normalizeSafeHtmlTag, sanitizeRichTextHtml } from '@/core/sanitize';\n\n const props = defineProps({\n content: { type: String, default: '' },\n tag: { type: String, default: 'div' },\n });\n\n const safeTag = computed(() => normalizeSafeHtmlTag(props.tag));\n const safeHtmlContent = computed(() => sanitizeRichTextHtml(props.content));\n</script>\n\n<template>\n <component :is=\"safeTag\" v-html=\"safeHtmlContent\" />\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbImage',\n label: 'Image',\n description: 'Displays an image with optional alt text.',\n category: 'media',\n icon: '🖼',\n component: {} as any,\n slots: [],\n editableProps: [\n { key: 'src', label: 'Image URL', type: 'image', required: true },\n { key: 'alt', label: 'Alt Text', type: 'text', defaultValue: '' },\n { key: 'width', label: 'Width', type: 'text', defaultValue: '100%' },\n { key: 'objectFit', label: 'Object Fit', type: 'select', defaultValue: 'cover', options: [\n { label: 'Cover', value: 'cover' },\n { label: 'Contain', value: 'contain' },\n { label: 'Fill', value: 'fill' },\n { label: 'None', value: 'none' },\n ]},\n ],\n defaultProps: { src: '', alt: '', width: '100%', objectFit: 'cover' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n\n const props = defineProps({\n src: { type: String, required: true },\n alt: { type: String, default: '' },\n width: { type: String, default: '100%' },\n objectFit: { type: String, default: 'cover' },\n });\n\n const style = computed(() => ({\n width: props.width,\n objectFit: props.objectFit as any,\n display: 'block',\n maxWidth: '100%',\n }));\n\n const safeSrc = computed(() => sanitizeUrlByKind(props.src, 'media'));\n</script>\n\n<template>\n <img v-if=\"safeSrc\" :src=\"safeSrc\" :alt=\"alt\" :style=\"style\" loading=\"lazy\" />\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbVideo',\n label: 'Vidéo',\n description: 'Affiche une vidéo avec URL, poster optionnel et options de lecture.',\n category: 'media',\n icon: '🎬',\n component: {} as any,\n slots: [],\n editableProps: [\n { key: 'src', label: 'URL de la vidéo', type: 'url', required: true },\n { key: 'poster', label: 'Image de couverture (poster)', type: 'image' },\n { key: 'width', label: 'Largeur', type: 'text', defaultValue: '100%' },\n { key: 'controls', label: 'Afficher les contrôles', type: 'boolean', defaultValue: true },\n { key: 'autoplay', label: 'Lecture automatique', type: 'boolean', defaultValue: false },\n { key: 'muted', label: 'Muet', type: 'boolean', defaultValue: false },\n { key: 'loop', label: 'Boucle', type: 'boolean', defaultValue: false },\n ],\n defaultProps: {\n src: '',\n poster: '',\n width: '100%',\n controls: true,\n autoplay: false,\n muted: false,\n loop: false,\n },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n\n const props = withDefaults(\n defineProps<{\n src: string;\n poster?: string;\n width?: string;\n controls?: boolean;\n autoplay?: boolean;\n muted?: boolean;\n loop?: boolean;\n }>(),\n {\n poster: '',\n width: '100%',\n controls: true,\n autoplay: false,\n muted: false,\n loop: false,\n },\n );\n\n const style = computed(() => ({\n width: props.width,\n maxWidth: '100%',\n display: 'block',\n }));\n\n const safeSrc = computed(() => sanitizeUrlByKind(props.src, 'media'));\n const safePoster = computed(() =>\n props.poster?.trim() ? sanitizeUrlByKind(props.poster, 'media') : undefined,\n );\n</script>\n\n<template>\n <video\n v-if=\"safeSrc\"\n :src=\"safeSrc\"\n :poster=\"safePoster\"\n :controls=\"controls\"\n :autoplay=\"autoplay\"\n :muted=\"muted\"\n :loop=\"loop\"\n :style=\"style\"\n playsinline\n />\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbSection',\n label: 'Section',\n description: 'A full-width section with optional background.',\n category: 'layout',\n icon: '▬',\n component: {} as any,\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'backgroundColor', label: 'Background Color', type: 'color', defaultValue: 'transparent' },\n { key: 'backgroundImage', label: 'Background Image', type: 'image' },\n { key: 'padding', label: 'Padding', type: 'text', defaultValue: '48px 24px' },\n { key: 'maxWidth', label: 'Max Content Width', type: 'text', defaultValue: '1200px' },\n ],\n defaultProps: { backgroundColor: 'transparent', padding: '48px 24px', maxWidth: '1200px' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n\n const props = defineProps({\n backgroundColor: { type: String, default: 'transparent' },\n backgroundImage: { type: String, default: '' },\n padding: { type: String, default: '48px 24px' },\n maxWidth: { type: String, default: '1200px' },\n });\n\n const safeBackgroundImage = computed(() => sanitizeUrlByKind(props.backgroundImage, 'background'));\n const cssBackgroundImage = computed(() => {\n if (!safeBackgroundImage.value) return undefined;\n const escapedUrl = safeBackgroundImage.value.replace(/[\"\\\\]/g, '\\\\$&');\n return `url(\"${escapedUrl}\")`;\n });\n\n const outerStyle = computed(() => ({\n width: '100%',\n backgroundColor: props.backgroundColor,\n backgroundImage: cssBackgroundImage.value,\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n padding: props.padding,\n }));\n\n const innerStyle = computed(() => ({\n maxWidth: props.maxWidth,\n margin: '0 auto',\n width: '100%',\n }));\n</script>\n\n<template>\n <section :style=\"outerStyle\">\n <div :style=\"innerStyle\">\n <slot />\n </div>\n </section>\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbContainer',\n label: 'Container',\n description: 'A centered container with max width.',\n category: 'layout',\n icon: '☐',\n component: {} as any,\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'maxWidth', label: 'Max Width', type: 'text', defaultValue: '100%' },\n { key: 'padding', label: 'Padding', type: 'text', defaultValue: '0 24px' },\n ],\n defaultProps: { maxWidth: '100%', padding: '0 24px' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n maxWidth: { type: String, default: '100%' },\n padding: { type: String, default: '0 24px' },\n });\n\n const style = computed(() => ({\n maxWidth: props.maxWidth,\n margin: '0 auto',\n padding: props.padding,\n width: '100%',\n boxSizing: 'border-box' as const,\n }));\n</script>\n\n<template>\n <div :style=\"style\">\n <slot />\n </div>\n</template>\n","import type { IComponentDefinition } from '@/types/component';\n\nimport PbColumn, { builderOptions as pbColumnOptions } from './PbColumn.vue';\nimport PbRow, { builderOptions as pbRowOptions } from './PbRow.vue';\nimport PbText, { builderOptions as pbTextOptions } from './PbText.vue';\nimport PbImage, { builderOptions as pbImageOptions } from './PbImage.vue';\nimport PbVideo, { builderOptions as pbVideoOptions } from './PbVideo.vue';\nimport PbSection, { builderOptions as pbSectionOptions } from './PbSection.vue';\nimport PbContainer, { builderOptions as pbContainerOptions } from './PbContainer.vue';\n\nfunction withComponent(options: IComponentDefinition, component: any): IComponentDefinition {\n return { ...options, component };\n}\n\nexport const builtInComponents: IComponentDefinition[] = [\n withComponent(pbColumnOptions, PbColumn),\n withComponent(pbRowOptions, PbRow),\n withComponent(pbTextOptions, PbText),\n withComponent(pbImageOptions, PbImage),\n withComponent(pbVideoOptions, PbVideo),\n withComponent(pbSectionOptions, PbSection),\n withComponent(pbContainerOptions, PbContainer),\n];\n\nexport {\n PbColumn,\n PbRow,\n PbText,\n PbImage,\n PbVideo,\n PbSection,\n PbContainer,\n};\n","import type { INode, IPageData, IPageMeta } from '@/types/node';\nimport { normalizeSafeHtmlTag, sanitizeUrlByKind } from '@/core/sanitize';\n\nexport interface IValidationError {\n path: string;\n message: string;\n}\n\nexport interface IValidationResult {\n isValid: boolean;\n errors: IValidationError[];\n}\n\ninterface IValidationContext {\n errors: IValidationError[];\n seenIds: Set<number>;\n seenNodes: WeakSet<object>;\n maxObservedId: number;\n visitedNodeCount: number;\n depthGuardTriggered: boolean;\n sizeGuardTriggered: boolean;\n}\n\nconst PAGE_STATUSES = new Set<IPageMeta['status']>(['draft', 'published', 'archived']);\nconst MAX_VALIDATION_DEPTH = 200;\nconst MAX_VALIDATION_NODE_COUNT = 5000;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction addError(context: IValidationContext, path: string, message: string): void {\n context.errors.push({ path, message });\n}\n\nfunction validatePbTextProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (props.tag === undefined) return;\n\n if (typeof props.tag !== 'string' || props.tag.trim() === '') {\n addError(context, `${path}.tag`, 'PbText props.tag must be a non-empty string.');\n return;\n }\n\n const normalizedTag = props.tag.trim().toLowerCase();\n if (normalizeSafeHtmlTag(props.tag) !== normalizedTag) {\n addError(\n context,\n `${path}.tag`,\n 'PbText props.tag must be one of: div, p, span, h1, h2, h3, h4, h5, h6, section, article, blockquote.',\n );\n }\n}\n\nfunction validatePbImageProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (typeof props.src !== 'string' || props.src.trim() === '') {\n addError(context, `${path}.src`, 'PbImage props.src must be a non-empty string.');\n return;\n }\n\n if (sanitizeUrlByKind(props.src, 'media') === '') {\n addError(context, `${path}.src`, 'PbImage props.src contains an unsafe URL.');\n }\n}\n\nfunction validatePbVideoProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (typeof props.src !== 'string' || props.src.trim() === '') {\n addError(context, `${path}.src`, 'PbVideo props.src must be a non-empty string.');\n return;\n }\n\n if (sanitizeUrlByKind(props.src, 'media') === '') {\n addError(context, `${path}.src`, 'PbVideo props.src contains an unsafe URL.');\n }\n\n const poster = props.poster;\n if (poster !== undefined && poster !== null && poster !== '') {\n if (typeof poster !== 'string') {\n addError(context, `${path}.poster`, 'PbVideo props.poster must be a string.');\n } else if (poster.trim() !== '' && sanitizeUrlByKind(poster, 'media') === '') {\n addError(context, `${path}.poster`, 'PbVideo props.poster contains an unsafe URL.');\n }\n }\n}\n\nfunction validatePbSectionProps(\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n const backgroundImage = props.backgroundImage;\n if (backgroundImage === undefined || backgroundImage === null || backgroundImage === '') return;\n\n if (typeof backgroundImage !== 'string') {\n addError(context, `${path}.backgroundImage`, 'PbSection props.backgroundImage must be a string.');\n return;\n }\n\n if (backgroundImage.trim() !== '' && sanitizeUrlByKind(backgroundImage, 'background') === '') {\n addError(context, `${path}.backgroundImage`, 'PbSection props.backgroundImage contains an unsafe URL.');\n }\n}\n\nfunction validateKnownComponentPropsInto(\n name: string,\n props: Record<string, unknown>,\n path: string,\n context: IValidationContext,\n): void {\n if (name === 'PbText') {\n validatePbTextProps(props, path, context);\n return;\n }\n\n if (name === 'PbImage') {\n validatePbImageProps(props, path, context);\n return;\n }\n\n if (name === 'PbVideo') {\n validatePbVideoProps(props, path, context);\n return;\n }\n\n if (name === 'PbSection') {\n validatePbSectionProps(props, path, context);\n }\n}\n\nfunction validateNodeInto(node: unknown, path: string, context: IValidationContext, depth = 0): void {\n if (depth > MAX_VALIDATION_DEPTH) {\n if (!context.depthGuardTriggered) {\n addError(\n context,\n path,\n `Maximum node depth (${String(MAX_VALIDATION_DEPTH)}) exceeded during validation.`,\n );\n context.depthGuardTriggered = true;\n }\n return;\n }\n\n if (context.visitedNodeCount >= MAX_VALIDATION_NODE_COUNT) {\n if (!context.sizeGuardTriggered) {\n addError(\n context,\n path,\n `Maximum node count (${String(MAX_VALIDATION_NODE_COUNT)}) exceeded during validation.`,\n );\n context.sizeGuardTriggered = true;\n }\n return;\n }\n\n if (!isRecord(node)) {\n addError(context, path, 'Node must be an object.');\n return;\n }\n\n if (context.seenNodes.has(node)) {\n addError(context, path, 'Cycle detected in node tree.');\n return;\n }\n context.seenNodes.add(node);\n context.visitedNodeCount++;\n\n const id = node.id;\n const name = node.name;\n const slot = node.slot;\n const props = node.props;\n const children = node.children;\n const readonly = node.readonly;\n\n if (!(typeof id === 'number' && Number.isInteger(id)) || id <= 0) {\n addError(context, `${path}.id`, 'id must be a positive integer.');\n } else {\n if (context.seenIds.has(id)) {\n addError(context, `${path}.id`, `Duplicate node id \"${id}\" found.`);\n }\n context.seenIds.add(id);\n if (id > context.maxObservedId) context.maxObservedId = id;\n }\n\n if (typeof name !== 'string' || name.trim() === '') {\n addError(context, `${path}.name`, 'name must be a non-empty string.');\n }\n\n if (!(slot === null || typeof slot === 'string')) {\n addError(context, `${path}.slot`, 'slot must be a string or null.');\n }\n\n if (!isRecord(props)) {\n addError(context, `${path}.props`, 'props must be an object.');\n } else if (typeof name === 'string') {\n validateKnownComponentPropsInto(name, props, `${path}.props`, context);\n }\n\n if (!Array.isArray(children)) {\n addError(context, `${path}.children`, 'children must be an array.');\n return;\n }\n\n if (!(readonly === undefined || typeof readonly === 'boolean')) {\n addError(context, `${path}.readonly`, 'readonly must be a boolean when provided.');\n }\n\n for (let index = 0; index < children.length; index++) {\n if (context.sizeGuardTriggered) break;\n validateNodeInto(children[index], `${path}.children[${index}]`, context, depth + 1);\n }\n}\n\nexport function validateNode(node: unknown, path = 'node'): IValidationResult {\n const context: IValidationContext = {\n errors: [],\n seenIds: new Set<number>(),\n seenNodes: new WeakSet<object>(),\n maxObservedId: 0,\n visitedNodeCount: 0,\n depthGuardTriggered: false,\n sizeGuardTriggered: false,\n };\n\n validateNodeInto(node, path, context);\n\n return {\n isValid: context.errors.length === 0,\n errors: context.errors,\n };\n}\n\nexport function validatePageData(pageData: unknown): IValidationResult {\n const context: IValidationContext = {\n errors: [],\n seenIds: new Set<number>(),\n seenNodes: new WeakSet<object>(),\n maxObservedId: 0,\n visitedNodeCount: 0,\n depthGuardTriggered: false,\n sizeGuardTriggered: false,\n };\n\n if (!isRecord(pageData)) {\n addError(context, 'pageData', 'pageData must be an object.');\n return {\n isValid: false,\n errors: context.errors,\n };\n }\n\n const { meta, content, layout, maxId, variables } = pageData;\n\n if (!isRecord(meta)) {\n addError(context, 'meta', 'meta must be an object.');\n } else {\n if (typeof meta.id !== 'string' || meta.id.trim() === '') {\n addError(context, 'meta.id', 'meta.id must be a non-empty string.');\n }\n if (typeof meta.name !== 'string' || meta.name.trim() === '') {\n addError(context, 'meta.name', 'meta.name must be a non-empty string.');\n }\n if (typeof meta.url !== 'string' || meta.url.trim() === '') {\n addError(context, 'meta.url', 'meta.url must be a non-empty string.');\n } else if (sanitizeUrlByKind(meta.url, 'link') === '') {\n addError(context, 'meta.url', 'meta.url contains an unsafe URL.');\n }\n if (typeof meta.status !== 'string' || !PAGE_STATUSES.has(meta.status as IPageMeta['status'])) {\n addError(\n context,\n 'meta.status',\n 'meta.status must be one of: draft, published, archived.',\n );\n }\n if (!(meta.updatedAt === undefined || typeof meta.updatedAt === 'string')) {\n addError(context, 'meta.updatedAt', 'meta.updatedAt must be a string when provided.');\n }\n if (!(meta.createdAt === undefined || typeof meta.createdAt === 'string')) {\n addError(context, 'meta.createdAt', 'meta.createdAt must be a string when provided.');\n }\n }\n\n validateNodeInto(content, 'content', context);\n validateNodeInto(layout, 'layout', context);\n\n if (!(typeof maxId === 'number' && Number.isInteger(maxId)) || maxId < 0) {\n addError(context, 'maxId', 'maxId must be a non-negative integer.');\n } else if (maxId < context.maxObservedId) {\n addError(\n context,\n 'maxId',\n `maxId (${String(maxId)}) must be greater than or equal to the maximum node id (${String(context.maxObservedId)}).`,\n );\n }\n\n if (!isRecord(variables)) {\n addError(context, 'variables', 'variables must be an object.');\n } else {\n for (const [key, value] of Object.entries(variables)) {\n if (typeof value !== 'string') {\n addError(context, `variables.${key}`, 'Variable values must be strings.');\n }\n }\n }\n\n return {\n isValid: context.errors.length === 0,\n errors: context.errors,\n };\n}\n","import type { TranslationDictionary } from './translator';\n\nexport const DEFAULT_LOCALE = 'en';\n\nexport const defaultTranslations: TranslationDictionary = {\n en: {\n 'toolbar.undo.title': 'Undo (Ctrl/Cmd+Z)',\n 'toolbar.undo.ariaLabel': 'Undo',\n 'toolbar.redo.title': 'Redo (Ctrl/Cmd+Y or Shift+Ctrl/Cmd+Z)',\n 'toolbar.redo.ariaLabel': 'Redo',\n 'toolbar.save': 'Save',\n 'toolbar.save.title': 'Save (Ctrl/Cmd+S)',\n 'toolbar.save.ariaLabel': 'Save page',\n 'toolbar.aria.toolbar': 'Editor toolbar',\n 'toolbar.aria.historyControls': 'History controls',\n 'toolbar.aria.viewportControls': 'Viewport controls',\n 'toolbar.aria.saveControls': 'Save controls',\n 'toolbar.aria.unsavedChanges': 'Unsaved changes',\n 'toolbar.viewport.desktop': 'Desktop',\n 'toolbar.viewport.tablet': 'Tablet',\n 'toolbar.viewport.mobile': 'Mobile',\n 'toolbar.viewport.custom': 'Custom',\n 'toolbar.viewport.switchAriaLabel': 'Switch viewport to {viewport}',\n 'toolbar.viewport.width.short': 'W',\n 'toolbar.viewport.height.short': 'H',\n 'toolbar.viewport.width.ariaLabel': 'Custom viewport width',\n 'toolbar.viewport.height.ariaLabel': 'Custom viewport height',\n 'leftDrawer.title': 'Components',\n 'leftDrawer.aria.componentPalette': 'Component palette',\n 'leftDrawer.toggle.ariaLabel': 'Toggle component drawer',\n 'leftDrawer.section.components': 'Components',\n 'leftDrawer.search.placeholder': 'Search components...',\n 'leftDrawer.search.ariaLabel': 'Search components',\n 'leftDrawer.category.ariaLabel': '{category} components',\n 'leftDrawer.component.dragAriaLabel': 'Add or drag {label}',\n 'leftDrawer.empty': 'No matching components',\n 'leftDrawer.section.tree': 'Tree',\n 'leftDrawer.tree.toggle.ariaLabel': 'Toggle node tree',\n 'rightDrawer.title': 'Properties',\n 'rightDrawer.aria.componentProperties': 'Component properties',\n 'rightDrawer.toggle.ariaLabel': 'Toggle properties drawer',\n 'rightDrawer.section.properties': 'Properties',\n 'rightDrawer.actions.duplicate': 'Duplicate',\n 'rightDrawer.actions.duplicate.ariaLabel': 'Duplicate selected component',\n 'rightDrawer.actions.delete': 'Delete',\n 'rightDrawer.actions.delete.ariaLabel': 'Delete selected component',\n 'rightDrawer.empty': 'Select a component to edit its properties.',\n 'treePanel.ariaLabel': 'Node tree',\n 'treePanel.readonly': 'readonly',\n 'contextMenu.ariaLabel': 'Node context menu',\n 'contextMenu.duplicate': 'Duplicate',\n 'contextMenu.moveUp': 'Move up',\n 'contextMenu.moveDown': 'Move down',\n 'contextMenu.delete': 'Delete',\n 'iframeCanvas.title': 'Editor canvas',\n 'propBoolean.enabled': 'Enabled',\n 'propBoolean.disabled': 'Disabled',\n 'propSelect.noOptions': 'No options',\n 'mediaPicker.input.placeholder': 'https://example.com/image.jpg',\n 'mediaPicker.clear': 'Clear',\n 'mediaPicker.upload': 'Upload',\n 'mediaPicker.preview.alt': 'Media preview',\n 'mediaPicker.empty': 'Paste an image URL to preview.',\n 'richText.action.link': 'Link',\n 'richText.action.bold': 'Bold',\n 'richText.action.italic': 'Italic',\n 'richText.action.unorderedList': 'Bulleted list',\n 'richText.action.orderedList': 'Numbered list',\n 'richText.aria.toolbar': 'Rich text formatting toolbar',\n 'richText.aria.editor': 'Rich text editor',\n 'richText.prompt.enterUrl': 'Enter URL',\n 'richText.prompt.defaultUrl': 'https://',\n 'pageBuilder.warning.invalidEditMode': 'Invalid `pageData` for edit mode. Rendering in read mode.',\n },\n};\n","export type TranslationParams = Record<string, string | number>;\nexport type TranslationDictionary = Record<string, Record<string, string>>;\nexport type Translator = (key: string, params?: TranslationParams) => string;\n\ninterface TranslateOptions {\n locale: string;\n dictionary: TranslationDictionary;\n key: string;\n params?: TranslationParams;\n fallbackLocale?: string;\n}\n\nfunction interpolate(message: string, params?: TranslationParams): string {\n if (!params) return message;\n\n return message.replace(/\\{(\\w+)\\}/g, (match, paramName: string) => {\n const value = params[paramName];\n return value === undefined ? match : String(value);\n });\n}\n\nexport function mergeTranslations(\n ...dictionaries: Array<TranslationDictionary | undefined | null>\n): TranslationDictionary {\n const merged: TranslationDictionary = {};\n\n for (const dictionary of dictionaries) {\n if (!dictionary) continue;\n\n for (const [locale, messages] of Object.entries(dictionary)) {\n merged[locale] = {\n ...(merged[locale] ?? {}),\n ...messages,\n };\n }\n }\n\n return merged;\n}\n\nexport function translate(options: TranslateOptions): string {\n const fallbackLocale = options.fallbackLocale ?? 'en';\n const localeMessages = options.dictionary[options.locale] ?? {};\n const fallbackMessages = options.dictionary[fallbackLocale] ?? {};\n const message = localeMessages[options.key] ?? fallbackMessages[options.key] ?? options.key;\n return interpolate(message, options.params);\n}\n\nexport function createTranslator(\n localeSource: string | (() => string),\n dictionarySource: TranslationDictionary | (() => TranslationDictionary),\n fallbackLocale = 'en',\n): Translator {\n const getLocale = typeof localeSource === 'function' ? localeSource : () => localeSource;\n const getDictionary = typeof dictionarySource === 'function' ? dictionarySource : () => dictionarySource;\n\n return (key, params) =>\n translate({\n locale: getLocale(),\n dictionary: getDictionary(),\n key,\n params,\n fallbackLocale,\n });\n}\n","import { computed, inject, type ComputedRef, type InjectionKey } from 'vue';\nimport { DEFAULT_LOCALE, defaultTranslations } from './messages';\nimport { createTranslator, type TranslationDictionary, type Translator } from './translator';\n\nexport interface PageBuilderI18nOptions {\n locale?: string;\n messages?: TranslationDictionary;\n}\n\nexport interface PageBuilderI18nContext {\n locale: ComputedRef<string>;\n t: Translator;\n}\n\nexport const PAGE_BUILDER_I18N_OPTIONS_KEY: InjectionKey<PageBuilderI18nOptions> = Symbol('pageBuilderI18nOptions');\nexport const PAGE_BUILDER_I18N_KEY: InjectionKey<PageBuilderI18nContext> = Symbol('pageBuilderI18n');\n\nconst fallbackI18nContext: PageBuilderI18nContext = {\n locale: computed(() => DEFAULT_LOCALE),\n t: createTranslator(DEFAULT_LOCALE, defaultTranslations),\n};\n\nexport function usePageBuilderI18n(): PageBuilderI18nContext {\n return inject(PAGE_BUILDER_I18N_KEY, fallbackI18nContext);\n}\n","import type { INode } from '@/types/node';\nimport { createPageBuilderError } from '@/core/errors';\n\nfunction getChildren(node: INode): INode[] {\n return Array.isArray(node.children) ? node.children : [];\n}\n\nfunction clampIndex(index: number, length: number): number {\n const normalized = Number.isFinite(index) ? Math.trunc(index) : 0;\n return Math.max(0, Math.min(normalized, length));\n}\n\n/**\n * Deep clone a node tree using structured clone.\n */\nexport function cloneTree(node: INode): INode {\n try {\n return structuredClone(node);\n } catch (error) {\n throw createPageBuilderError(\n 'INVALID_NODE',\n '[PageBuilder] Failed to clone node tree. Ensure the tree is serializable and acyclic.',\n {\n cause: error,\n },\n );\n }\n}\n\n/**\n * Find a node by ID in the tree. Returns undefined if not found.\n */\nexport function findNodeById(root: INode, id: number): INode | undefined {\n if (root.id === id) return root;\n for (const child of getChildren(root)) {\n const found = findNodeById(child, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Find the parent of a node by the child's ID.\n * Returns the parent node and the child's index, or undefined.\n */\nexport function findParent(\n root: INode,\n childId: number,\n): { parent: INode; index: number } | undefined {\n const children = getChildren(root);\n for (let i = 0; i < children.length; i++) {\n if (children[i].id === childId) {\n return { parent: root, index: i };\n }\n const found = findParent(children[i], childId);\n if (found) return found;\n }\n return undefined;\n}\n\n/**\n * Remove a node by ID from the tree. Returns the removed node or undefined.\n */\nexport function removeNode(root: INode, id: number): INode | undefined {\n const result = findParent(root, id);\n if (!result) return undefined;\n return result.parent.children.splice(result.index, 1)[0];\n}\n\n/**\n * Insert a node as a child of a target node at a specific index and slot.\n */\nexport function insertNode(\n root: INode,\n parentId: number,\n node: INode,\n index: number,\n slot: string = 'default',\n): boolean {\n const parent = findNodeById(root, parentId);\n if (!parent) return false;\n if (!Array.isArray(parent.children)) {\n parent.children = [];\n }\n\n const targetIndex = clampIndex(index, parent.children.length);\n const insertedNode = { ...node, slot };\n parent.children.splice(targetIndex, 0, insertedNode);\n return true;\n}\n\n/**\n * Move a node within the tree to a new parent at a specific index.\n */\nexport function moveNode(\n root: INode,\n nodeId: number,\n newParentId: number,\n index: number,\n slot: string = 'default',\n): boolean {\n const sourceParentResult = findParent(root, nodeId);\n if (!sourceParentResult) return false;\n\n const sourceChildren = getChildren(sourceParentResult.parent);\n const [node] = sourceChildren.splice(sourceParentResult.index, 1);\n if (!node) return false;\n\n const moved = insertNode(root, newParentId, node, index, slot);\n if (moved) return true;\n\n // Roll back on failure so the caller never loses nodes due to invalid moves.\n const rollbackIndex = clampIndex(sourceParentResult.index, sourceChildren.length);\n sourceChildren.splice(rollbackIndex, 0, node);\n return false;\n}\n\n/**\n * Create a new node with default values and a given ID.\n */\nexport function createNode(\n id: number,\n name: string,\n options: Partial<Pick<INode, 'slot' | 'props' | 'children' | 'readonly'>> = {},\n): INode {\n return {\n id,\n name,\n slot: options.slot ?? 'default',\n props: options.props ?? {},\n children: options.children ?? [],\n readonly: options.readonly,\n };\n}\n\n/**\n * Walk the tree depth-first and call visitor for each node.\n * Return `false` from visitor to stop the entire traversal (not just the subtree).\n */\nexport function walkTree(root: INode, visitor: (node: INode, depth: number) => boolean | void, depth = 0): boolean {\n const visited = new WeakSet<object>();\n\n function visitNode(node: INode, currentDepth: number): boolean {\n if (visited.has(node as object)) return true;\n visited.add(node as object);\n\n if (visitor(node, currentDepth) === false) return false;\n for (const child of getChildren(node)) {\n if (visitNode(child, currentDepth + 1) === false) return false;\n }\n return true;\n }\n\n return visitNode(root, depth);\n}\n\n/**\n * Count the total number of nodes in the tree.\n */\nexport function countNodes(root: INode): number {\n let count = 0;\n walkTree(root, () => { count++; });\n return count;\n}\n\n/**\n * Get the maximum ID in the tree.\n */\nexport function getMaxId(root: INode): number {\n let max = root.id;\n walkTree(root, (node) => {\n if (Number.isFinite(node.id) && node.id > max) max = node.id;\n });\n return max;\n}\n\n/**\n * Interpolate template variables in node props.\n * Replaces `{{ VAR }}` patterns with values from the variables map.\n */\nexport function interpolateProps(\n props: Record<string, unknown>,\n variables: Record<string, string>,\n): Record<string, unknown> {\n if (!props || typeof props !== 'object' || Array.isArray(props)) {\n return {};\n }\n\n const safeVariables =\n variables && typeof variables === 'object' && !Array.isArray(variables) ? variables : {};\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props)) {\n if (typeof value === 'string') {\n result[key] = value.replace(/\\{\\{\\s*(\\w+)\\s*\\}\\}/g, (_, varName: string) => {\n return safeVariables[varName] ?? `{{ ${varName} }}`;\n });\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n","<script setup lang=\"ts\">\n import { computed, onErrorCaptured, ref } from 'vue';\n import { createPageBuilderError, reportDevDiagnostic, toErrorMessage } from '@/core/errors';\n\n const props = withDefaults(\n defineProps<{\n fallbackMessage?: string;\n showDetailsInDev?: boolean;\n diagnosticContext?: string;\n }>(),\n {\n fallbackMessage: 'Something went wrong while rendering this section.',\n showDetailsInDev: false,\n diagnosticContext: 'ErrorBoundary',\n },\n );\n\n const hasError = ref(false);\n const capturedError = ref<unknown>(null);\n const errorInfo = ref('');\n\n const shouldShowDetails = computed(() => import.meta.env.DEV && props.showDetailsInDev);\n const errorDetails = computed(() => {\n if (!capturedError.value) return '';\n if (capturedError.value instanceof Error) return capturedError.value.message;\n return String(capturedError.value);\n });\n const errorDebugText = computed(() =>\n [errorDetails.value, errorInfo.value].filter((segment) => Boolean(segment)).join('\\n'),\n );\n\n onErrorCaptured((error, _instance, info) => {\n hasError.value = true;\n capturedError.value = error;\n errorInfo.value = info;\n\n reportDevDiagnostic(\n props.diagnosticContext,\n createPageBuilderError(\n 'RENDER_FAILURE',\n `[PageBuilder] ${props.diagnosticContext} captured a render error: ${toErrorMessage(error)}`,\n {\n cause: error,\n details: {\n info,\n },\n },\n ),\n );\n\n return false;\n });\n</script>\n\n<template>\n <slot v-if=\"!hasError\" />\n <div v-else class=\"ipb-error-boundary\" role=\"alert\">\n <p class=\"ipb-error-boundary__message\">\n {{ fallbackMessage }}\n </p>\n\n <pre v-if=\"shouldShowDetails && errorDebugText\" class=\"ipb-error-boundary__details\">\n {{ errorDebugText }}\n </pre>\n </div>\n</template>\n\n<style scoped>\n .ipb-error-boundary {\n width: 100%;\n padding: 0.75rem;\n border: 1px solid #f3d1d1;\n border-radius: 0.375rem;\n background-color: #fff5f5;\n color: #7a1f1f;\n }\n\n .ipb-error-boundary__message {\n margin: 0;\n font-size: 0.9rem;\n line-height: 1.4;\n }\n\n .ipb-error-boundary__details {\n margin: 0.5rem 0 0;\n font-size: 0.75rem;\n line-height: 1.4;\n white-space: pre-wrap;\n word-break: break-word;\n color: #5f1b1b;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, defineComponent, type PropType } from 'vue';\n import type { INode } from '@/types/node';\n import { resolveComponent } from '@/core/registry';\n import { interpolateProps } from '@/core/tree';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import ErrorBoundary from '@/components/shared/ErrorBoundary.vue';\n\n const props = defineProps({\n node: {\n type: Object as PropType<INode>,\n required: true,\n },\n variables: {\n type: Object as PropType<Record<string, string>>,\n default: () => ({}),\n },\n markNodes: {\n type: Boolean,\n default: false,\n },\n });\n\n const reportedDiagnostics = new Set<string>();\n\n function reportOnce(key: string, message: string, details?: Record<string, unknown>) {\n if (reportedDiagnostics.has(key)) return;\n reportedDiagnostics.add(key);\n reportDevDiagnostic('NodeRenderer', createPageBuilderError('RENDER_FAILURE', message, { details }));\n }\n\n function isNodeObject(value: unknown): value is INode {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const maybeNode = value as Partial<INode>;\n if (typeof maybeNode.id !== 'number' || !Number.isFinite(maybeNode.id)) return false;\n if (typeof maybeNode.name !== 'string' || maybeNode.name.trim().length === 0) return false;\n if (!(maybeNode.slot === null || typeof maybeNode.slot === 'string')) return false;\n if (\n typeof maybeNode.props !== 'object' ||\n maybeNode.props === null ||\n Array.isArray(maybeNode.props)\n ) {\n return false;\n }\n return Array.isArray(maybeNode.children);\n }\n\n function sanitizeVariables(rawVariables: unknown): Record<string, string> {\n if (!rawVariables || typeof rawVariables !== 'object' || Array.isArray(rawVariables)) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(rawVariables).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n }\n\n const safeNode = computed<INode | null>(() => {\n if (isNodeObject(props.node)) return props.node;\n reportOnce('invalid-node', '[PageBuilder] NodeRenderer received an invalid node payload.', {\n node: props.node,\n });\n return null;\n });\n\n const safeVariables = computed<Record<string, string>>(() => sanitizeVariables(props.variables));\n\n const NodeRenderCrash = defineComponent({\n name: 'NodeRenderCrash',\n props: {\n error: {\n type: null as unknown as PropType<unknown>,\n required: true,\n },\n },\n setup(localProps) {\n return () => {\n const reason =\n localProps.error instanceof Error ? localProps.error : new Error(String(localProps.error));\n throw reason;\n };\n },\n });\n\n const resolutionResult = computed(() => {\n if (!safeNode.value) {\n return {\n component: NodeRenderCrash,\n error: createPageBuilderError(\n 'INVALID_NODE',\n '[PageBuilder] Cannot render node because its payload is invalid.',\n ),\n };\n }\n\n try {\n return { component: resolveComponent(safeNode.value.name), error: null as unknown };\n } catch (error) {\n reportOnce(\n `missing-component:${safeNode.value.name}`,\n `[PageBuilder] Component \"${safeNode.value.name}\" could not be resolved.`,\n { nodeId: safeNode.value.id },\n );\n return { component: NodeRenderCrash, error };\n }\n });\n\n const resolvedComponent = computed(() => resolutionResult.value.component);\n const resolvedProps = computed(() => {\n if (resolutionResult.value.error !== null) {\n return { error: resolutionResult.value.error };\n }\n\n if (!safeNode.value) {\n return {\n error: createPageBuilderError(\n 'INVALID_NODE',\n '[PageBuilder] Cannot render props for an invalid node payload.',\n ),\n };\n }\n\n try {\n return interpolateProps(safeNode.value.props, safeVariables.value);\n } catch (error) {\n reportOnce(\n `prop-interpolation:${safeNode.value.id}`,\n `[PageBuilder] Failed to interpolate props for node \"${safeNode.value.name}\".`,\n { nodeId: safeNode.value.id },\n );\n return { error };\n }\n });\n const markerAttrs = computed(() => {\n if (!props.markNodes || !safeNode.value) return {};\n return {\n 'data-ipb-node-id': String(safeNode.value.id),\n 'data-ipb-component': safeNode.value.name,\n };\n });\n const renderedAttrs = computed(() => ({\n ...resolvedProps.value,\n ...markerAttrs.value,\n }));\n\n const slotGroups = computed(() => {\n const groups: Record<string, INode[]> = {};\n if (!safeNode.value) return groups;\n\n for (const child of safeNode.value.children) {\n if (!isNodeObject(child)) {\n reportOnce(\n `invalid-child:${safeNode.value.id}`,\n `[PageBuilder] Ignoring invalid child node while rendering \"${safeNode.value.name}\".`,\n { parentNodeId: safeNode.value.id },\n );\n continue;\n }\n const slotName = child.slot ?? 'default';\n if (!groups[slotName]) groups[slotName] = [];\n groups[slotName].push(child);\n }\n return groups;\n });\n</script>\n\n<template>\n <div v-if=\"!safeNode\" class=\"ipb-node-renderer__invalid\" role=\"alert\">\n This block is invalid and could not be rendered.\n </div>\n <ErrorBoundary\n v-else\n fallback-message=\"This block could not be rendered.\"\n :show-details-in-dev=\"true\"\n diagnostic-context=\"NodeRenderer\"\n >\n <component :is=\"resolvedComponent\" v-bind=\"renderedAttrs\">\n <template v-for=\"(children, slotName) in slotGroups\" :key=\"slotName\" #[slotName]>\n <NodeRenderer\n v-for=\"child in children\"\n :key=\"child.id\"\n :node=\"child\"\n :variables=\"safeVariables\"\n :mark-nodes=\"markNodes\"\n />\n </template>\n </component>\n </ErrorBoundary>\n</template>\n\n<style scoped>\n .ipb-node-renderer__invalid {\n width: 100%;\n padding: 0.75rem;\n border: 1px solid #f3d1d1;\n border-radius: 0.375rem;\n background-color: #fff5f5;\n color: #7a1f1f;\n font-size: 0.825rem;\n line-height: 1.35;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, type PropType, watch } from 'vue';\n import type { IPageData, INode } from '@/types/node';\n import { validateNode, validatePageData } from '@/core/validation';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import NodeRenderer from './NodeRenderer.vue';\n import ErrorBoundary from '@/components/shared/ErrorBoundary.vue';\n\n const props = defineProps({\n pageData: {\n type: Object as PropType<IPageData>,\n required: true,\n },\n });\n\n const pageValidationResult = computed(() => validatePageData(props.pageData));\n const contentValidationResult = computed(() => validateNode(props.pageData.content, 'content'));\n const layoutValidationResult = computed(() => validateNode(props.pageData.layout, 'layout'));\n const reportedDiagnostics = new Set<string>();\n\n function reportOnce(key: string, message: string, details?: Record<string, unknown>) {\n if (reportedDiagnostics.has(key)) return;\n reportedDiagnostics.add(key);\n reportDevDiagnostic('PageReader', createPageBuilderError('INVALID_PAGE_DATA', message, { details }));\n }\n\n watch(\n pageValidationResult,\n (result) => {\n if (result.isValid) return;\n reportOnce(\n 'invalid-page-data',\n '[PageReader] Invalid pageData payload detected. Rendering continues with degraded behavior.',\n { errors: result.errors },\n );\n },\n { immediate: true },\n );\n\n function isNodeObject(value: unknown): value is INode {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n\n const safeVariables = computed<Record<string, string>>(() => {\n const rawVariables = props.pageData.variables;\n if (!rawVariables || typeof rawVariables !== 'object' || Array.isArray(rawVariables)) {\n reportOnce(\n 'invalid-variables-shape',\n '[PageReader] Invalid variables payload. Falling back to an empty variable map.',\n );\n return {};\n }\n\n const hasInvalidEntries = Object.values(rawVariables).some((value) => typeof value !== 'string');\n if (hasInvalidEntries) {\n reportOnce(\n 'invalid-variables-values',\n '[PageReader] Variables payload contains non-string values. Invalid entries were ignored.',\n );\n }\n\n return Object.fromEntries(\n Object.entries(rawVariables).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n });\n\n const readerRoot = computed<INode | null>(() => {\n if (!isNodeObject(props.pageData.content) || !contentValidationResult.value.isValid) {\n reportOnce(\n 'invalid-content',\n '[PageReader] Invalid content node. Nothing can be rendered.',\n { errors: contentValidationResult.value.errors },\n );\n return null;\n }\n\n // Backward-compatible fallback for legacy payloads that don't include layout.\n if (!isNodeObject(props.pageData.layout) || !layoutValidationResult.value.isValid) {\n reportOnce(\n 'invalid-layout',\n '[PageReader] Invalid layout node. Falling back to content-only rendering.',\n { errors: layoutValidationResult.value.errors },\n );\n return props.pageData.content;\n }\n\n const contentRoot: INode = {\n ...props.pageData.content,\n slot: props.pageData.content.slot ?? 'default',\n };\n\n const layoutChildren = Array.isArray(props.pageData.layout.children)\n ? props.pageData.layout.children\n : [];\n\n return {\n ...props.pageData.layout,\n children: [...layoutChildren, contentRoot],\n };\n });\n</script>\n\n<template>\n <div class=\"ipb-page-reader\">\n <ErrorBoundary\n v-if=\"readerRoot\"\n fallback-message=\"This page could not be fully rendered.\"\n :show-details-in-dev=\"true\"\n diagnostic-context=\"PageReader\"\n >\n <NodeRenderer :node=\"readerRoot\" :variables=\"safeVariables\" />\n </ErrorBoundary>\n <div v-else class=\"ipb-page-reader__invalid\" role=\"alert\">\n This page data is invalid and cannot be rendered safely.\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-page-reader {\n width: 100%;\n min-height: 100%;\n }\n\n .ipb-page-reader__invalid {\n padding: 0.75rem;\n border: 1px solid #f3d1d1;\n border-radius: 0.375rem;\n background-color: #fff5f5;\n color: #7a1f1f;\n font-size: 0.875rem;\n }\n</style>\n","import type { INode, IPageSavePayload } from './node';\n\n/** Operating mode for the page builder. */\nexport type PageBuilderMode = 'read' | 'edit';\n\n/**\n * Editor UI state managed by the useEditor composable.\n * Drag-and-drop state is managed separately by useDragDrop.\n */\nexport interface IEditorState {\n /** Currently selected node, or null. */\n selectedNodeId: number | null;\n\n /** Currently hovered node, or null. */\n hoveredNodeId: number | null;\n\n /** Whether the left drawer (component palette) is open. */\n leftDrawerOpen: boolean;\n\n /** Whether the right drawer (property editor) is open. */\n rightDrawerOpen: boolean;\n\n /** Undo/redo history stack. */\n history: IEditorHistoryEntry[];\n\n /** Current position in the history stack. */\n historyIndex: number;\n\n /** Dirty flag — true if unsaved changes exist. */\n isDirty: boolean;\n\n /** Viewport scale for the canvas iframe. */\n canvasScale: number;\n\n /** Viewport preset. */\n viewport: ViewportPreset;\n}\n\nexport interface IEditorHistoryEntry {\n timestamp: number;\n label: string;\n snapshot: string;\n}\n\nexport type ViewportPreset = 'desktop' | 'tablet' | 'mobile' | 'custom';\n\nexport interface IViewportDimensions {\n width: number;\n height: number;\n label: string;\n}\n\nexport interface IViewportSize {\n width: number;\n height: number;\n}\n\nexport const VIEWPORT_PRESETS: Record<ViewportPreset, IViewportDimensions> = {\n desktop: { width: 1440, height: 900, label: 'Desktop' },\n tablet: { width: 768, height: 1024, label: 'Tablet' },\n mobile: { width: 375, height: 812, label: 'Mobile' },\n custom: { width: 0, height: 0, label: 'Custom' },\n};\n\n/**\n * Events emitted by the page builder in edit mode.\n */\nexport interface IPageBuilderEvents {\n /** Emitted when the user saves (Ctrl+S or save button). */\n save: [payload: IPageSavePayload];\n\n /** Emitted when the tree structure changes. */\n change: [tree: INode];\n\n /** Emitted when a node is selected. */\n select: [nodeId: number | null];\n}\n","import type { InjectionKey } from 'vue';\nimport type { UsePageBuilderReturn } from '@/composables/use-page-builder';\nimport type { useEditor } from '@/composables/use-editor';\nimport type { useNodeTree } from '@/composables/use-node-tree';\nimport type { useDragDrop } from '@/composables/use-drag-drop';\n\n/**\n * Typed injection keys for provide/inject across the editor component tree.\n * Use these instead of raw strings for type-safe inject() calls.\n */\nexport const PAGE_BUILDER_KEY: InjectionKey<UsePageBuilderReturn> = Symbol('pageBuilder');\nexport const EDITOR_KEY: InjectionKey<ReturnType<typeof useEditor>> = Symbol('editor');\nexport const NODE_TREE_KEY: InjectionKey<ReturnType<typeof useNodeTree>> = Symbol('nodeTree');\nexport const DRAG_DROP_KEY: InjectionKey<ReturnType<typeof useDragDrop>> = Symbol('dragDrop');\n","import { ref, computed, type Ref, type ComputedRef } from 'vue';\nimport type { IPageData, INode } from '@/types/node';\nimport type { PageBuilderMode } from '@/types/editor';\nimport { getMaxId } from '@/core/tree';\nimport {\n createPageBuilderError,\n reportDevDiagnostic,\n toErrorMessage,\n} from '@/core/errors';\n\nexport interface UsePageBuilderOptions {\n initialData: IPageData;\n mode?: PageBuilderMode;\n}\n\nexport interface UsePageBuilderReturn {\n mode: Ref<PageBuilderMode>;\n pageData: ComputedRef<IPageData>;\n content: Ref<INode>;\n layout: Ref<INode>;\n maxId: Ref<number>;\n variables: Ref<Record<string, string>>;\n isDirty: Ref<boolean>;\n\n setMode: (newMode: PageBuilderMode) => void;\n updateContent: (newContent: INode) => void;\n updateLayout: (newLayout: INode) => void;\n nextId: () => number;\n getSnapshot: () => string;\n restoreSnapshot: (snapshot: string) => void;\n reset: () => void;\n}\n\ninterface SnapshotShape {\n content: INode;\n layout: INode;\n maxId: number;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isPositiveInteger(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n\nfunction createFallbackNode(id: number, name: string, slot: string | null): INode {\n return {\n id,\n name,\n slot,\n props: {},\n children: [],\n };\n}\n\nfunction isNode(value: unknown, visited = new WeakSet<object>()): value is INode {\n if (!isPlainObject(value)) return false;\n if (visited.has(value)) return false;\n visited.add(value);\n\n if (!isPositiveInteger(value.id)) return false;\n if (typeof value.name !== 'string' || value.name.trim().length === 0) return false;\n if (!(value.slot === null || typeof value.slot === 'string')) return false;\n if (!isPlainObject(value.props)) return false;\n if (!Array.isArray(value.children)) return false;\n if (typeof value.readonly !== 'undefined' && typeof value.readonly !== 'boolean') return false;\n\n return value.children.every((child) => isNode(child, visited));\n}\n\nfunction sanitizeVariables(value: unknown): Record<string, string> {\n if (!isPlainObject(value)) return {};\n const result: Record<string, string> = {};\n for (const [key, variableValue] of Object.entries(value)) {\n if (typeof variableValue === 'string') {\n result[key] = variableValue;\n }\n }\n return result;\n}\n\nfunction sanitizeInitialData(initialData: IPageData): IPageData {\n const issues: string[] = [];\n const fallbackContent = createFallbackNode(1, 'PbSection', null);\n const fallbackLayout = createFallbackNode(100, 'PbContainer', null);\n const source = isPlainObject(initialData) ? initialData : ({} as Record<string, unknown>);\n\n let content = fallbackContent;\n if (isNode(source.content)) {\n content = structuredClone(source.content);\n } else {\n issues.push('content node is invalid');\n }\n\n let layout = fallbackLayout;\n if (isNode(source.layout)) {\n layout = structuredClone(source.layout);\n } else {\n issues.push('layout node is invalid');\n }\n\n const rawMaxId = source.maxId;\n const computedMaxId = Math.max(getMaxId(content), getMaxId(layout));\n const hasValidMaxId = isNonNegativeInteger(rawMaxId);\n const maxId = hasValidMaxId ? Math.max(Math.trunc(rawMaxId), computedMaxId) : computedMaxId;\n\n if (!hasValidMaxId) {\n issues.push('maxId is invalid');\n }\n\n const variables = sanitizeVariables(source.variables);\n if (!isPlainObject(source.variables)) {\n issues.push('variables map is invalid');\n }\n\n const meta = isPlainObject(source.meta) ? source.meta : {};\n if (!isPlainObject(source.meta)) {\n issues.push('meta object is invalid');\n }\n\n const pageData: IPageData = {\n meta: {\n id: typeof meta.id === 'string' ? meta.id : 'unknown-page',\n name: typeof meta.name === 'string' ? meta.name : 'Untitled page',\n url: typeof meta.url === 'string' ? meta.url : '/',\n status:\n meta.status === 'draft' || meta.status === 'published' || meta.status === 'archived'\n ? meta.status\n : 'draft',\n updatedAt: typeof meta.updatedAt === 'string' ? meta.updatedAt : undefined,\n createdAt: typeof meta.createdAt === 'string' ? meta.createdAt : undefined,\n },\n content,\n layout,\n maxId,\n variables,\n };\n\n if (issues.length > 0) {\n reportDevDiagnostic(\n 'usePageBuilder.sanitizeInitialData',\n createPageBuilderError(\n 'INVALID_PAGE_DATA',\n `[PageBuilder] Invalid page data detected. Falling back to safe defaults for: ${issues.join(', ')}.`,\n ),\n { issues },\n );\n }\n\n return pageData;\n}\n\nfunction parseSnapshot(snapshot: string): SnapshotShape {\n let parsed: unknown;\n try {\n parsed = JSON.parse(snapshot);\n } catch (error) {\n throw createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Snapshot JSON is invalid.',\n {\n cause: error,\n details: {\n snapshotPreview: snapshot.slice(0, 200),\n },\n },\n );\n }\n\n if (!isPlainObject(parsed) || !isNode(parsed.content) || !isNode(parsed.layout) || !isNonNegativeInteger(parsed.maxId)) {\n throw createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Snapshot payload shape is invalid.',\n {\n details: {\n contentValid: isPlainObject(parsed) ? isNode(parsed.content) : false,\n layoutValid: isPlainObject(parsed) ? isNode(parsed.layout) : false,\n maxIdValid: isPlainObject(parsed) ? isNonNegativeInteger(parsed.maxId) : false,\n },\n },\n );\n }\n\n const normalizedMaxId = Math.max(\n Math.trunc(parsed.maxId),\n getMaxId(parsed.content),\n getMaxId(parsed.layout),\n );\n\n return {\n content: parsed.content,\n layout: parsed.layout,\n maxId: normalizedMaxId,\n };\n}\n\n/**\n * Main composable for managing page builder state.\n * Used internally by the PageBuilder component.\n */\nexport function usePageBuilder(options: UsePageBuilderOptions): UsePageBuilderReturn {\n const { initialData, mode: initialMode = 'read' } = options;\n\n const _initial = sanitizeInitialData(initialData);\n const mode = ref<PageBuilderMode>(initialMode);\n const meta = ref(_initial.meta);\n const content = ref<INode>(_initial.content);\n const layout = ref<INode>(_initial.layout);\n const maxId = ref(_initial.maxId);\n const variables = ref<Record<string, string>>(_initial.variables);\n const isDirty = ref(false);\n\n const pageData = computed<IPageData>(() => ({\n meta: meta.value,\n content: content.value,\n layout: layout.value,\n maxId: maxId.value,\n variables: variables.value,\n }));\n\n const _initialDirtySnapshot = _serializeDirtyState({\n content: _initial.content,\n layout: _initial.layout,\n });\n\n function _serializeSnapshot(snapshot: Pick<IPageData, 'content' | 'layout' | 'maxId'>): string {\n return JSON.stringify(snapshot);\n }\n\n function _serializeDirtyState(state: Pick<IPageData, 'content' | 'layout'>): string {\n return JSON.stringify(state);\n }\n\n function _syncDirtyFromCurrentState() {\n isDirty.value = _serializeDirtyState({\n content: content.value,\n layout: layout.value,\n }) !== _initialDirtySnapshot;\n }\n\n function setMode(newMode: PageBuilderMode) {\n mode.value = newMode;\n }\n\n function updateContent(newContent: INode) {\n content.value = newContent;\n maxId.value = Math.max(maxId.value, getMaxId(newContent));\n _syncDirtyFromCurrentState();\n }\n\n function updateLayout(newLayout: INode) {\n layout.value = newLayout;\n maxId.value = Math.max(maxId.value, getMaxId(newLayout));\n _syncDirtyFromCurrentState();\n }\n\n function nextId(): number {\n maxId.value++;\n return maxId.value;\n }\n\n function getSnapshot(): string {\n return _serializeSnapshot({\n content: content.value,\n layout: layout.value,\n maxId: maxId.value,\n });\n }\n\n function restoreSnapshot(snapshot: string) {\n try {\n const parsed = parseSnapshot(snapshot);\n content.value = parsed.content;\n layout.value = parsed.layout;\n maxId.value = parsed.maxId;\n _syncDirtyFromCurrentState();\n } catch (error) {\n throw createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Unable to restore snapshot.',\n {\n cause: error,\n details: {\n reason: toErrorMessage(error),\n },\n },\n );\n }\n }\n\n function reset() {\n const original = parseSnapshot(\n JSON.stringify({\n content: _initial.content,\n layout: _initial.layout,\n maxId: _initial.maxId,\n }),\n );\n content.value = structuredClone(original.content);\n layout.value = structuredClone(original.layout);\n maxId.value = original.maxId;\n variables.value = structuredClone(_initial.variables);\n isDirty.value = false;\n }\n\n return {\n mode,\n pageData,\n content,\n layout,\n maxId,\n variables,\n isDirty,\n setMode,\n updateContent,\n updateLayout,\n nextId,\n getSnapshot,\n restoreSnapshot,\n reset,\n };\n}\n","import { reactive, computed, toRefs } from 'vue';\nimport type { ViewportPreset } from '@/types/editor';\n\ninterface UseEditorOptions {\n initialSnapshot?: string;\n initialLabel?: string;\n}\n\ninterface EditorUIState {\n selectedNodeId: number | null;\n hoveredNodeId: number | null;\n leftDrawerOpen: boolean;\n rightDrawerOpen: boolean;\n history: { timestamp: number; label: string; snapshot: string }[];\n historyIndex: number;\n isDirty: boolean;\n canvasScale: number;\n viewport: ViewportPreset;\n}\n\n/**\n * Composable managing the editor UI state (selection, drawers, history, viewport).\n * Drag-and-drop state is handled separately by useDragDrop.\n */\nexport function useEditor(options: UseEditorOptions = {}) {\n const { initialSnapshot, initialLabel = 'Initial state' } = options;\n const initialHistory = initialSnapshot\n ? [{ timestamp: Date.now(), label: initialLabel, snapshot: initialSnapshot }]\n : [];\n let baselineSnapshot: string | null = initialSnapshot ?? null;\n\n const state = reactive<EditorUIState>({\n selectedNodeId: null,\n hoveredNodeId: null,\n leftDrawerOpen: true,\n rightDrawerOpen: false,\n history: initialHistory,\n historyIndex: initialHistory.length > 0 ? 0 : -1,\n isDirty: false,\n canvasScale: 1,\n viewport: 'desktop',\n });\n\n const canUndo = computed(() => state.historyIndex > 0);\n const canRedo = computed(() => state.historyIndex < state.history.length - 1);\n\n function selectNode(id: number | null) {\n state.selectedNodeId = id;\n if (id !== null) {\n state.rightDrawerOpen = true;\n }\n }\n\n function hoverNode(id: number | null) {\n state.hoveredNodeId = id;\n }\n\n function toggleLeftDrawer() {\n state.leftDrawerOpen = !state.leftDrawerOpen;\n }\n\n function toggleRightDrawer() {\n state.rightDrawerOpen = !state.rightDrawerOpen;\n }\n\n function setViewport(preset: ViewportPreset) {\n state.viewport = preset;\n }\n\n function syncDirtyWithHistory() {\n if (baselineSnapshot === null || state.historyIndex < 0) {\n state.isDirty = false;\n return;\n }\n const currentSnapshot = state.history[state.historyIndex]?.snapshot;\n state.isDirty = currentSnapshot !== baselineSnapshot;\n }\n\n function setHistoryBaseline(snapshot: string, label = initialLabel) {\n baselineSnapshot = snapshot;\n state.history = [{ timestamp: Date.now(), label, snapshot }];\n state.historyIndex = 0;\n state.isDirty = false;\n }\n\n function pushHistory(label: string, snapshot: string) {\n if (baselineSnapshot === null) {\n setHistoryBaseline(snapshot);\n return;\n }\n\n const currentSnapshot = state.history[state.historyIndex]?.snapshot;\n if (currentSnapshot === snapshot) return;\n\n if (state.historyIndex < state.history.length - 1) {\n state.history.splice(state.historyIndex + 1);\n }\n state.history.push({\n timestamp: Date.now(),\n label,\n snapshot,\n });\n state.historyIndex = state.history.length - 1;\n syncDirtyWithHistory();\n }\n\n function undo(): string | undefined {\n if (!canUndo.value) return undefined;\n state.historyIndex--;\n syncDirtyWithHistory();\n return state.history[state.historyIndex]?.snapshot;\n }\n\n function redo(): string | undefined {\n if (!canRedo.value) return undefined;\n state.historyIndex++;\n syncDirtyWithHistory();\n return state.history[state.historyIndex]?.snapshot;\n }\n\n return {\n ...toRefs(state),\n canUndo,\n canRedo,\n selectNode,\n hoverNode,\n toggleLeftDrawer,\n toggleRightDrawer,\n setViewport,\n setHistoryBaseline,\n pushHistory,\n undo,\n redo,\n };\n}\n","import type { Ref } from 'vue';\nimport { toRaw } from 'vue';\nimport type { INode } from '@/types/node';\nimport {\n cloneTree,\n findNodeById,\n findParent,\n removeNode,\n insertNode,\n moveNode,\n createNode,\n} from '@/core/tree';\n\nexport interface UseNodeTreeOptions {\n content: Ref<INode>;\n nextId: () => number;\n onUpdate: (newContent: INode) => void;\n onSnapshot?: (label: string) => void;\n}\n\n/**\n * Composable for manipulating the node tree (add, remove, move, update props).\n * All mutations clone before modifying to preserve immutability for history.\n */\nexport function useNodeTree({ content, nextId, onUpdate, onSnapshot }: UseNodeTreeOptions) {\n function _mutate(label: string, mutator: (tree: INode) => boolean | void): boolean {\n // `content.value` may be a Vue proxy; clone the raw node tree.\n const currentTree = toRaw(content.value);\n const currentSnapshot = JSON.stringify(currentTree);\n const cloned = cloneTree(currentTree);\n const shouldCommit = mutator(cloned);\n if (shouldCommit === false) return false;\n if (JSON.stringify(cloned) === currentSnapshot) return false;\n onUpdate(cloned);\n onSnapshot?.(label);\n return true;\n }\n\n function addNode(\n parentId: number,\n componentName: string,\n index: number,\n slot = 'default',\n defaultProps?: Record<string, unknown>,\n ): number | null {\n let createdNodeId: number | null = null;\n const didInsert = _mutate(`Add ${componentName}`, (tree) => {\n const parentNode = findNodeById(tree, parentId);\n if (!parentNode) return false;\n\n createdNodeId = nextId();\n const node = createNode(createdNodeId, componentName, { slot, props: defaultProps });\n return insertNode(tree, parentId, node, index, slot);\n });\n\n if (!didInsert || createdNodeId === null) return null;\n return createdNodeId;\n }\n\n function deleteNode(nodeId: number) {\n _mutate('Delete node', (tree) => {\n removeNode(tree, nodeId);\n });\n }\n\n function moveNodeTo(nodeId: number, newParentId: number, index: number, slot = 'default') {\n _mutate('Move node', (tree) => {\n return moveNode(tree, nodeId, newParentId, index, slot);\n });\n }\n\n function updateNodeProps(nodeId: number, props: Record<string, unknown>) {\n _mutate('Update props', (tree) => {\n const node = findNodeById(tree, nodeId);\n if (node) {\n node.props = { ...node.props, ...props };\n }\n });\n }\n\n function duplicateNode(nodeId: number) {\n _mutate('Duplicate node', (tree) => {\n const original = findNodeById(tree, nodeId);\n if (!original) return;\n\n const parentResult = findParent(tree, nodeId);\n if (!parentResult) return;\n\n const cloned = _deepCloneWithNewIds(original);\n parentResult.parent.children.splice(parentResult.index + 1, 0, cloned);\n });\n }\n\n function canMoveNodeUp(nodeId: number): boolean {\n const node = findNodeById(content.value, nodeId);\n if (!node || node.readonly) return false;\n const parentResult = findParent(content.value, nodeId);\n if (!parentResult) return false;\n return parentResult.index > 0;\n }\n\n function canMoveNodeDown(nodeId: number): boolean {\n const node = findNodeById(content.value, nodeId);\n if (!node || node.readonly) return false;\n const parentResult = findParent(content.value, nodeId);\n if (!parentResult) return false;\n return parentResult.index < parentResult.parent.children.length - 1;\n }\n\n function moveNodeUp(nodeId: number) {\n if (!canMoveNodeUp(nodeId)) return;\n _mutate('Move node up', (tree) => {\n const parentResult = findParent(tree, nodeId);\n if (!parentResult || parentResult.index <= 0) return;\n const [node] = parentResult.parent.children.splice(parentResult.index, 1);\n parentResult.parent.children.splice(parentResult.index - 1, 0, node);\n });\n }\n\n function moveNodeDown(nodeId: number) {\n if (!canMoveNodeDown(nodeId)) return;\n _mutate('Move node down', (tree) => {\n const parentResult = findParent(tree, nodeId);\n if (!parentResult || parentResult.index >= parentResult.parent.children.length - 1) return;\n const [node] = parentResult.parent.children.splice(parentResult.index, 1);\n parentResult.parent.children.splice(parentResult.index + 1, 0, node);\n });\n }\n\n function _deepCloneWithNewIds(node: INode): INode {\n return {\n ...node,\n id: nextId(),\n props: { ...node.props },\n children: node.children.map((child) => _deepCloneWithNewIds(child)),\n };\n }\n\n return {\n addNode,\n deleteNode,\n moveNodeTo,\n updateNodeProps,\n duplicateNode,\n canMoveNodeUp,\n canMoveNodeDown,\n moveNodeUp,\n moveNodeDown,\n };\n}\n","import { ref, type Ref } from 'vue';\n\nexport interface DragState {\n isDragging: boolean;\n sourceNodeId: number | null;\n sourceComponentName: string | null;\n isNewComponent: boolean;\n dropTargetId: number | null;\n dropIndex: number;\n dropSlot: string;\n}\n\nexport interface DragDropApi {\n dragState: Ref<DragState>;\n startDragExisting: (nodeId: number) => void;\n startDragNew: (componentName: string) => void;\n updateDropTarget: (targetId: number, index: number, slot?: string) => void;\n endDrag: () => DragState;\n cancelDrag: () => void;\n}\n\nconst DEFAULT_DROP_SLOT = 'default';\n\nfunction createInitialDragState(): DragState {\n return {\n isDragging: false,\n sourceNodeId: null,\n sourceComponentName: null,\n isNewComponent: false,\n dropTargetId: null,\n dropIndex: 0,\n dropSlot: DEFAULT_DROP_SLOT,\n };\n}\n\n/**\n * Composable for drag-and-drop interactions in the editor.\n * Handles both dragging existing nodes and new components from the palette.\n */\nexport function useDragDrop(): DragDropApi {\n const state = ref<DragState>(createInitialDragState());\n\n function resetDragState() {\n state.value = createInitialDragState();\n }\n\n function startDragExisting(nodeId: number) {\n state.value = {\n ...createInitialDragState(),\n isDragging: true,\n sourceNodeId: nodeId,\n };\n }\n\n function startDragNew(componentName: string) {\n state.value = {\n ...createInitialDragState(),\n isDragging: true,\n sourceComponentName: componentName,\n isNewComponent: true,\n };\n }\n\n function updateDropTarget(targetId: number, index: number, slot = DEFAULT_DROP_SLOT) {\n if (!state.value.isDragging) return;\n state.value.dropTargetId = targetId;\n state.value.dropIndex = index;\n state.value.dropSlot = slot;\n }\n\n function endDrag() {\n const result = { ...state.value };\n resetDragState();\n return result;\n }\n\n function cancelDrag() {\n resetDragState();\n }\n\n return {\n dragState: state,\n startDragExisting,\n startDragNew,\n updateDropTarget,\n endDrag,\n cancelDrag,\n };\n}\n","<script setup lang=\"ts\">\n import { nextTick, ref, type ComponentPublicInstance, type PropType } from 'vue';\n import type { ViewportPreset } from '@/types/editor';\n import { VIEWPORT_PRESETS } from '@/types/editor';\n import { usePageBuilderI18n } from '@/i18n';\n\n const MIN_VIEWPORT_WIDTH = 240;\n const MIN_VIEWPORT_HEIGHT = 320;\n const MAX_VIEWPORT_WIDTH = 3840;\n const MAX_VIEWPORT_HEIGHT = 4320;\n\n const props = defineProps({\n canUndo: { type: Boolean, default: false },\n canRedo: { type: Boolean, default: false },\n isDirty: { type: Boolean, default: false },\n viewport: { type: String as PropType<ViewportPreset>, default: 'desktop' },\n customViewportWidth: { type: Number, default: 1024 },\n customViewportHeight: { type: Number, default: 768 },\n activeViewportWidth: { type: Number as PropType<number | null>, default: null },\n activeViewportHeight: { type: Number as PropType<number | null>, default: null },\n });\n\n const emit = defineEmits<{\n undo: [];\n redo: [];\n save: [];\n 'viewport-change': [preset: ViewportPreset];\n 'custom-viewport-change': [payload: { width: number; height: number }];\n }>();\n\n const { t } = usePageBuilderI18n();\n\n const VIEWPORT_LABEL_KEYS: Record<ViewportPreset, string> = {\n desktop: 'toolbar.viewport.desktop',\n tablet: 'toolbar.viewport.tablet',\n mobile: 'toolbar.viewport.mobile',\n custom: 'toolbar.viewport.custom',\n };\n const VIEWPORT_ORDER: ViewportPreset[] = ['desktop', 'tablet', 'mobile', 'custom'];\n const viewportButtonRefs = ref(new Map<ViewportPreset, HTMLButtonElement>());\n\n function getViewportLabel(preset: ViewportPreset): string {\n return t(VIEWPORT_LABEL_KEYS[preset]);\n }\n\n function getViewportSwitchAriaLabel(preset: ViewportPreset): string {\n return t('toolbar.viewport.switchAriaLabel', { viewport: getViewportLabel(preset) });\n }\n\n function setViewportButtonRef(preset: ViewportPreset, element: Element | ComponentPublicInstance | null) {\n const maybeElement =\n element instanceof HTMLButtonElement\n ? element\n : element && '$el' in element && element.$el instanceof HTMLButtonElement\n ? element.$el\n : null;\n\n if (maybeElement) {\n viewportButtonRefs.value.set(preset, maybeElement);\n return;\n }\n\n viewportButtonRefs.value.delete(preset);\n }\n\n function getViewportIndex(preset: ViewportPreset): number {\n return VIEWPORT_ORDER.indexOf(preset);\n }\n\n function focusViewportButton(preset: ViewportPreset) {\n viewportButtonRefs.value.get(preset)?.focus();\n }\n\n function handleViewportKeydown(event: KeyboardEvent, currentPreset: ViewportPreset) {\n const currentIndex = getViewportIndex(currentPreset);\n if (currentIndex < 0) return;\n\n if (\n event.key !== 'ArrowLeft' &&\n event.key !== 'ArrowRight' &&\n event.key !== 'ArrowUp' &&\n event.key !== 'ArrowDown' &&\n event.key !== 'Home' &&\n event.key !== 'End'\n ) {\n return;\n }\n\n event.preventDefault();\n\n let nextIndex = currentIndex;\n if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {\n nextIndex = (currentIndex - 1 + VIEWPORT_ORDER.length) % VIEWPORT_ORDER.length;\n } else if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {\n nextIndex = (currentIndex + 1) % VIEWPORT_ORDER.length;\n } else if (event.key === 'Home') {\n nextIndex = 0;\n } else if (event.key === 'End') {\n nextIndex = VIEWPORT_ORDER.length - 1;\n }\n\n const nextPreset = VIEWPORT_ORDER[nextIndex];\n emit('viewport-change', nextPreset);\n void nextTick(() => {\n focusViewportButton(nextPreset);\n });\n }\n\n function clampViewportSize(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n }\n\n function parseViewportSize(value: string): number | null {\n if (!value.trim()) return null;\n const parsed = Number(value);\n if (!Number.isFinite(parsed)) return null;\n return Math.round(parsed);\n }\n\n function updateCustomViewportSize(dimension: 'width' | 'height', rawValue: string) {\n const parsed = parseViewportSize(rawValue);\n if (parsed === null) return;\n\n const width =\n dimension === 'width'\n ? clampViewportSize(parsed, MIN_VIEWPORT_WIDTH, MAX_VIEWPORT_WIDTH)\n : clampViewportSize(props.customViewportWidth, MIN_VIEWPORT_WIDTH, MAX_VIEWPORT_WIDTH);\n\n const height =\n dimension === 'height'\n ? clampViewportSize(parsed, MIN_VIEWPORT_HEIGHT, MAX_VIEWPORT_HEIGHT)\n : clampViewportSize(props.customViewportHeight, MIN_VIEWPORT_HEIGHT, MAX_VIEWPORT_HEIGHT);\n\n emit('custom-viewport-change', { width, height });\n }\n</script>\n\n<template>\n <header class=\"ipb-toolbar\" role=\"toolbar\" :aria-label=\"t('toolbar.aria.toolbar')\">\n <div class=\"ipb-toolbar__left\" role=\"group\" :aria-label=\"t('toolbar.aria.historyControls')\">\n <button\n type=\"button\"\n class=\"ipb-toolbar__btn\"\n :disabled=\"!canUndo\"\n :aria-label=\"t('toolbar.undo.ariaLabel')\"\n :title=\"t('toolbar.undo.title')\"\n aria-keyshortcuts=\"Control+Z Meta+Z\"\n @click=\"$emit('undo')\"\n >\n ↩\n </button>\n <button\n type=\"button\"\n class=\"ipb-toolbar__btn\"\n :disabled=\"!canRedo\"\n :aria-label=\"t('toolbar.redo.ariaLabel')\"\n :title=\"t('toolbar.redo.title')\"\n aria-keyshortcuts=\"Control+Y Meta+Y Control+Shift+Z Meta+Shift+Z\"\n @click=\"$emit('redo')\"\n >\n ↪\n </button>\n </div>\n\n <div class=\"ipb-toolbar__center\" role=\"group\" :aria-label=\"t('toolbar.aria.viewportControls')\">\n <button\n v-for=\"(_, key) in VIEWPORT_PRESETS\"\n :key=\"key\"\n :ref=\"(element) => setViewportButtonRef(key as ViewportPreset, element)\"\n type=\"button\"\n class=\"ipb-toolbar__btn\"\n :class=\"{ 'ipb-toolbar__btn--active': viewport === key }\"\n :title=\"getViewportLabel(key as ViewportPreset)\"\n :aria-label=\"getViewportSwitchAriaLabel(key as ViewportPreset)\"\n :aria-pressed=\"viewport === key ? 'true' : 'false'\"\n :data-viewport-preset=\"key\"\n @click=\"$emit('viewport-change', key as ViewportPreset)\"\n @keydown=\"handleViewportKeydown($event, key as ViewportPreset)\"\n >\n {{ getViewportLabel(key as ViewportPreset) }}\n </button>\n <div v-if=\"viewport === 'custom'\" class=\"ipb-toolbar__custom-size\">\n <label class=\"ipb-toolbar__size-control\">\n <span>{{ t('toolbar.viewport.width.short') }}</span>\n <input\n class=\"ipb-toolbar__size-input\"\n type=\"number\"\n inputmode=\"numeric\"\n :aria-label=\"t('toolbar.viewport.width.ariaLabel')\"\n :min=\"MIN_VIEWPORT_WIDTH\"\n :max=\"MAX_VIEWPORT_WIDTH\"\n :value=\"customViewportWidth\"\n @input=\"updateCustomViewportSize('width', ($event.target as HTMLInputElement).value)\"\n />\n </label>\n <label class=\"ipb-toolbar__size-control\">\n <span>{{ t('toolbar.viewport.height.short') }}</span>\n <input\n class=\"ipb-toolbar__size-input\"\n type=\"number\"\n inputmode=\"numeric\"\n :aria-label=\"t('toolbar.viewport.height.ariaLabel')\"\n :min=\"MIN_VIEWPORT_HEIGHT\"\n :max=\"MAX_VIEWPORT_HEIGHT\"\n :value=\"customViewportHeight\"\n @input=\"updateCustomViewportSize('height', ($event.target as HTMLInputElement).value)\"\n />\n </label>\n </div>\n <span\n v-if=\"activeViewportWidth !== null && activeViewportHeight !== null\"\n class=\"ipb-toolbar__viewport-size\"\n aria-live=\"polite\"\n >\n {{ activeViewportWidth }}×{{ activeViewportHeight }}\n </span>\n </div>\n\n <div class=\"ipb-toolbar__right\" role=\"group\" :aria-label=\"t('toolbar.aria.saveControls')\">\n <span\n v-if=\"isDirty\"\n class=\"ipb-toolbar__dirty-indicator\"\n role=\"status\"\n :aria-label=\"t('toolbar.aria.unsavedChanges')\"\n >\n ●\n </span>\n <button\n type=\"button\"\n class=\"ipb-toolbar__btn ipb-toolbar__btn--primary\"\n :aria-label=\"t('toolbar.save.ariaLabel')\"\n :title=\"t('toolbar.save.title')\"\n aria-keyshortcuts=\"Control+S Meta+S\"\n @click=\"$emit('save')\"\n >\n {{ t('toolbar.save') }}\n </button>\n </div>\n </header>\n</template>\n\n<style scoped>\n .ipb-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: 48px;\n padding: 0 16px;\n background: var(--ipb-toolbar-bg, #fff);\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n flex-shrink: 0;\n }\n\n .ipb-toolbar__left,\n .ipb-toolbar__center,\n .ipb-toolbar__right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .ipb-toolbar__btn {\n padding: 6px 12px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: transparent;\n cursor: pointer;\n font-size: 13px;\n transition: background 0.15s;\n }\n\n .ipb-toolbar__btn:focus-visible,\n .ipb-toolbar__size-input:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-toolbar__custom-size {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: 8px;\n padding-left: 8px;\n border-left: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-toolbar__size-control {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--ipb-text-secondary, #4b5563);\n }\n\n .ipb-toolbar__size-input {\n width: 72px;\n padding: 4px 6px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 12px;\n }\n\n .ipb-toolbar__viewport-size {\n margin-left: 8px;\n color: var(--ipb-text-secondary, #6b7280);\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n }\n\n .ipb-toolbar__btn:hover:not(:disabled) {\n background: var(--ipb-hover-bg, #f5f5f5);\n }\n\n .ipb-toolbar__btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n\n .ipb-toolbar__btn--active {\n background: var(--ipb-active-bg, #e8f0fe);\n border-color: var(--ipb-primary-color, #1a73e8);\n color: var(--ipb-primary-color, #1a73e8);\n }\n\n .ipb-toolbar__btn--primary {\n background: var(--ipb-primary-color, #1a73e8);\n color: #fff;\n border-color: var(--ipb-primary-color, #1a73e8);\n }\n\n .ipb-toolbar__btn--primary:hover {\n background: var(--ipb-primary-hover, #1557b0);\n }\n\n .ipb-toolbar__dirty-indicator {\n color: var(--ipb-warning-color, #f59e0b);\n font-size: 10px;\n }\n</style>\n","import { getComponent } from '@/core/registry';\nimport type { INode } from '@/types/node';\nimport type { ISlotDefinition } from '@/types/component';\n\n/**\n * Slots of the parent component that accept the given child component name.\n * Used to validate drop targets (canvas and tree panel).\n */\nexport function getAllowedDropSlots(parentNode: INode, componentName: string): ISlotDefinition[] {\n const definition = getComponent(parentNode.name);\n if (!definition || definition.slots.length === 0) return [];\n return definition.slots.filter((slot) => {\n const allowedComponents = slot.allowedComponents;\n return (\n !allowedComponents ||\n allowedComponents.length === 0 ||\n allowedComponents.includes(componentName)\n );\n });\n}\n\n/**\n * Resolve a valid slot name for dropping the given component into the parent,\n * or null if the parent does not accept this component in any slot.\n */\nexport function normalizeDropSlot(\n parentNode: INode,\n preferredSlot: string | null | undefined,\n componentName: string,\n): string | null {\n const allowedSlots = getAllowedDropSlots(parentNode, componentName);\n if (allowedSlots.length === 0) return null;\n\n if (preferredSlot) {\n const preferred = allowedSlots.find((slot) => slot.name === preferredSlot);\n if (preferred) return preferred.name;\n }\n\n const defaultSlot = allowedSlots.find((slot) => slot.name === 'default');\n return defaultSlot?.name ?? allowedSlots[0].name;\n}\n","import type { INode } from '@/types/node';\n\nexport interface IVirtualTreeRow {\n node: INode;\n id: number;\n key: string;\n depth: number;\n index: number;\n parentId: number | null;\n}\n\nexport interface IVirtualWindowRange {\n start: number;\n end: number;\n size: number;\n total: number;\n}\n\nexport interface IVirtualTreeIndexMaps {\n keyByIndex: string[];\n indexByKey: Map<string, number>;\n indexByNodeId: Map<number, number>;\n}\n\nexport interface IFlattenTreeOptions {\n createKey?: (node: INode) => string;\n}\n\nfunction toSafeInteger(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.trunc(value);\n}\n\nexport function createStableNodeKey(nodeId: number): string {\n return `ipb-node-${nodeId}`;\n}\n\n/**\n * Flatten a node tree in depth-first pre-order with depth metadata.\n * Uses an iterative stack to avoid recursion depth issues on large trees.\n */\nexport function flattenTree(root: INode, options: IFlattenTreeOptions = {}): IVirtualTreeRow[] {\n const createKey = options.createKey ?? ((node: INode) => createStableNodeKey(node.id));\n const rows: IVirtualTreeRow[] = [];\n const stack: Array<{ node: INode; depth: number; parentId: number | null }> = [\n { node: root, depth: 0, parentId: null },\n ];\n\n while (stack.length > 0) {\n const current = stack.pop();\n if (!current) break;\n\n const index = rows.length;\n rows.push({\n node: current.node,\n id: current.node.id,\n key: createKey(current.node),\n depth: current.depth,\n index,\n parentId: current.parentId,\n });\n\n for (let i = current.node.children.length - 1; i >= 0; i--) {\n stack.push({\n node: current.node.children[i],\n depth: current.depth + 1,\n parentId: current.node.id,\n });\n }\n }\n\n return rows;\n}\n\n/**\n * Compute a clamped window range over a flat list.\n */\nexport function computeWindowRange(\n total: number,\n startIndex: number,\n windowSize: number,\n overscan = 0,\n): IVirtualWindowRange {\n const safeTotal = Math.max(0, toSafeInteger(total));\n const safeWindowSize = Math.max(0, toSafeInteger(windowSize));\n const safeOverscan = Math.max(0, toSafeInteger(overscan));\n\n if (safeTotal === 0 || safeWindowSize === 0) {\n return { start: 0, end: 0, size: 0, total: safeTotal };\n }\n\n const maxStart = safeTotal - 1;\n const safeStartIndex = Math.min(Math.max(toSafeInteger(startIndex), 0), maxStart);\n const start = Math.max(0, safeStartIndex - safeOverscan);\n const end = Math.min(safeTotal, safeStartIndex + safeWindowSize + safeOverscan);\n\n return {\n start,\n end,\n size: Math.max(0, end - start),\n total: safeTotal,\n };\n}\n\n/**\n * Slice a list using a computed virtual window.\n */\nexport function sliceWindow<T>(\n rows: readonly T[],\n startIndex: number,\n windowSize: number,\n overscan = 0,\n): { rows: T[]; range: IVirtualWindowRange } {\n const range = computeWindowRange(rows.length, startIndex, windowSize, overscan);\n return {\n rows: rows.slice(range.start, range.end),\n range,\n };\n}\n\n/**\n * Build stable key/index lookup maps from flattened tree rows.\n */\nexport function createVirtualTreeIndexMaps(rows: readonly IVirtualTreeRow[]): IVirtualTreeIndexMaps {\n const keyByIndex: string[] = [];\n const indexByKey = new Map<string, number>();\n const indexByNodeId = new Map<number, number>();\n\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i];\n keyByIndex[i] = row.key;\n\n if (!indexByKey.has(row.key)) {\n indexByKey.set(row.key, i);\n }\n\n if (!indexByNodeId.has(row.id)) {\n indexByNodeId.set(row.id, i);\n }\n }\n\n return {\n keyByIndex,\n indexByKey,\n indexByNodeId,\n };\n}\n","<script setup lang=\"ts\">\n import { computed, inject, nextTick, ref, watch, type ComponentPublicInstance, type PropType } from 'vue';\n import { normalizeDropSlot } from '@/core/drop-slot';\n import { getComponent } from '@/core/registry';\n import { findNodeById, findParent } from '@/core/tree';\n import { flattenTree } from '@/core/virtual-tree';\n import type { INode } from '@/types/node';\n import { NODE_TREE_KEY, DRAG_DROP_KEY } from '@/types/keys';\n import { usePageBuilderI18n } from '@/i18n';\n\n type DropZone = 'above' | 'on' | 'below';\n\n interface TreeRow {\n id: number;\n key: string;\n name: string;\n depth: number;\n readonly: boolean;\n }\n\n const props = defineProps({\n content: { type: Object as PropType<INode>, required: true },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n });\n\n const emit = defineEmits<{\n select: [nodeId: number];\n }>();\n const { t } = usePageBuilderI18n();\n\n const nodeTree = inject(NODE_TREE_KEY, null);\n const dragDrop = inject(DRAG_DROP_KEY, null);\n const dropHandled = ref(false);\n const dropTargetRowId = ref<number | null>(null);\n const dropZone = ref<DropZone | null>(null);\n\n const rootId = computed(() => props.content.id);\n\n /** Get drop zone from mouse position relative to the row button, or from drop-line element. */\n function getDropZoneFromEvent(\n event: DragEvent,\n rowElement: HTMLElement | undefined,\n fallback: DropZone = 'on',\n ): DropZone {\n const dropZoneEl = (event.target as HTMLElement)?.closest?.('[data-drop-zone]');\n const zoneAttr = dropZoneEl?.getAttribute('data-drop-zone');\n if (zoneAttr === 'above') return 'above';\n if (zoneAttr === 'below') return 'below';\n if (!rowElement) return fallback;\n const rect = rowElement.getBoundingClientRect();\n const y = event.clientY - rect.top;\n const third = rect.height / 3;\n if (y < third) return 'above';\n if (y > 2 * third) return 'below';\n return 'on';\n }\n\n /** Resolve parent id, index and slot when dropping above or below a row (sibling position). */\n function getSiblingDropTarget(rowId: number, zone: 'above' | 'below'): { parentId: number; index: number; slot: string } | null {\n const rowNode = findNodeById(props.content, rowId);\n if (!rowNode) return null;\n const slot = rowNode.slot ?? 'default';\n const parentResult = findParent(props.content, rowId);\n if (!parentResult) {\n // Row is root: above = index 0, below = last\n const parentId = props.content.id;\n const index = zone === 'above' ? 0 : props.content.children.length;\n return { parentId, index, slot: 'default' };\n }\n const index = zone === 'above' ? parentResult.index : parentResult.index + 1;\n return { parentId: parentResult.parent.id, index, slot };\n }\n\n function isNodeInSubtree(node: INode, nodeId: number): boolean {\n if (node.id === nodeId) return true;\n return node.children.some((child) => isNodeInSubtree(child, nodeId));\n }\n\n function getDraggedComponentName(state: {\n sourceNodeId: number | null;\n sourceComponentName: string | null;\n isNewComponent: boolean;\n }): string | null {\n if (state.sourceComponentName) return state.sourceComponentName;\n if (state.sourceNodeId === null) return null;\n return findNodeById(props.content, state.sourceNodeId)?.name ?? null;\n }\n\n function isValidDropTarget(\n state: { sourceNodeId: number | null; sourceComponentName: string | null; isNewComponent: boolean },\n targetNodeId: number,\n ): boolean {\n if (state.sourceNodeId === targetNodeId) return false;\n const sourceName = getDraggedComponentName(state);\n if (!sourceName) return false;\n const targetNode = findNodeById(props.content, targetNodeId);\n if (!targetNode || targetNode.readonly) return false;\n if (!state.isNewComponent && state.sourceNodeId !== null) {\n const sourceNode = findNodeById(props.content, state.sourceNodeId);\n if (!sourceNode || sourceNode.readonly) return false;\n if (isNodeInSubtree(sourceNode, targetNodeId)) return false;\n }\n return normalizeDropSlot(targetNode, 'default', sourceName) !== null;\n }\n\n function isValidSiblingDropTarget(\n state: { sourceNodeId: number | null; sourceComponentName: string | null; isNewComponent: boolean },\n parentId: number,\n slot: string,\n ): boolean {\n const sourceName = getDraggedComponentName(state);\n if (!sourceName) return false;\n const parentNode = findNodeById(props.content, parentId);\n if (!parentNode || parentNode.readonly) return false;\n if (normalizeDropSlot(parentNode, slot, sourceName) === null) return false;\n if (!state.isNewComponent && state.sourceNodeId !== null) {\n const sourceNode = findNodeById(props.content, state.sourceNodeId);\n if (!sourceNode || sourceNode.readonly) return false;\n if (isNodeInSubtree(sourceNode, parentId)) return false;\n }\n return true;\n }\n\n const rows = computed<TreeRow[]>(() => {\n return flattenTree(props.content).map((row) => ({\n id: row.id,\n key: row.key,\n name: row.node.name,\n depth: row.depth,\n readonly: Boolean(row.node.readonly),\n }));\n });\n\n const rowButtonRefs = ref(new Map<number, HTMLButtonElement>());\n\n function setRowButtonRef(nodeId: number, element: Element | ComponentPublicInstance | null) {\n const maybeElement =\n element instanceof HTMLButtonElement\n ? element\n : element && '$el' in element && element.$el instanceof HTMLButtonElement\n ? element.$el\n : null;\n\n if (maybeElement) {\n rowButtonRefs.value.set(nodeId, maybeElement);\n return;\n }\n rowButtonRefs.value.delete(nodeId);\n }\n\n function getRowIdFromEventTarget(target: EventTarget | null): number | null {\n if (!(target instanceof HTMLElement)) return null;\n const nodeId = target.dataset.nodeId;\n if (!nodeId) return null;\n const parsed = Number(nodeId);\n return Number.isInteger(parsed) ? parsed : null;\n }\n\n function getActiveRowIndex(fallbackToFirst = true): number {\n if (rows.value.length === 0) return -1;\n if (props.selectedNodeId !== null) {\n const selectedIndex = rows.value.findIndex((row) => row.id === props.selectedNodeId);\n if (selectedIndex >= 0) return selectedIndex;\n }\n return fallbackToFirst ? 0 : -1;\n }\n\n function focusRowById(nodeId: number) {\n rowButtonRefs.value.get(nodeId)?.focus();\n }\n\n function selectRowByIndex(index: number) {\n const row = rows.value[index];\n if (!row) return;\n emit('select', row.id);\n void nextTick(() => {\n focusRowById(row.id);\n });\n }\n\n function isRowTabStop(rowId: number): boolean {\n const activeIndex = getActiveRowIndex();\n return rows.value[activeIndex]?.id === rowId;\n }\n\n const canDragDrop = computed(() => Boolean(nodeTree && dragDrop));\n\n const isDropTargetOn = (rowId: number) =>\n Boolean(\n dragDrop?.dragState.value.isDragging &&\n dropTargetRowId.value === rowId &&\n dropZone.value === 'on',\n );\n const isDropTargetAbove = (rowId: number) =>\n Boolean(\n dragDrop?.dragState.value.isDragging &&\n dropTargetRowId.value === rowId &&\n dropZone.value === 'above',\n );\n const isDropTargetBelow = (rowId: number) =>\n Boolean(\n dragDrop?.dragState.value.isDragging &&\n dropTargetRowId.value === rowId &&\n dropZone.value === 'below',\n );\n\n function isRowDraggable(row: TreeRow): boolean {\n if (!canDragDrop.value || row.readonly) return false;\n return row.id !== rootId.value;\n }\n\n function handleTreeDragStart(row: TreeRow, event: DragEvent) {\n if (!dragDrop || !isRowDraggable(row)) return;\n dropHandled.value = false;\n dragDrop.startDragExisting(row.id);\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n event.dataTransfer.setData('application/x-ipb-node-id', String(row.id));\n event.dataTransfer.setData('text/plain', String(row.id));\n }\n }\n\n function handleTreeDragOver(row: TreeRow, event: DragEvent) {\n if (!dragDrop || !dragDrop.dragState.value.isDragging) return;\n const state = dragDrop.dragState.value;\n const zone = getDropZoneFromEvent(event, rowButtonRefs.value.get(row.id));\n\n if (zone === 'on') {\n if (!isValidDropTarget(state, row.id)) return;\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = state.isNewComponent ? 'copy' : 'move';\n }\n dropTargetRowId.value = row.id;\n dropZone.value = 'on';\n dragDrop.updateDropTarget(row.id, 0, 'default');\n return;\n }\n\n const siblingTarget = getSiblingDropTarget(row.id, zone);\n if (!siblingTarget || !isValidSiblingDropTarget(state, siblingTarget.parentId, siblingTarget.slot)) return;\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = state.isNewComponent ? 'copy' : 'move';\n }\n dropTargetRowId.value = row.id;\n dropZone.value = zone;\n dragDrop.updateDropTarget(siblingTarget.parentId, siblingTarget.index, siblingTarget.slot);\n }\n\n function handleTreeDrop(row: TreeRow, event: DragEvent) {\n event.preventDefault();\n if (!nodeTree || !dragDrop || !dragDrop.dragState.value.isDragging) return;\n const state = dragDrop.dragState.value;\n // Prefer stored zone when we're dropping on the row we were hovering (line was visible)\n const storedZone =\n dropTargetRowId.value === row.id && dropZone.value ? dropZone.value : null;\n const zone = storedZone ?? getDropZoneFromEvent(event, rowButtonRefs.value.get(row.id), 'on');\n\n if (zone === 'on') {\n const targetNode = findNodeById(props.content, row.id);\n if (!targetNode || !isValidDropTarget(state, row.id)) {\n dragDrop.cancelDrag();\n return;\n }\n const sourceName = getDraggedComponentName(state);\n const slot = sourceName ? normalizeDropSlot(targetNode, 'default', sourceName) ?? 'default' : 'default';\n\n if (state.isNewComponent && state.sourceComponentName) {\n const defaultProps = getComponent(state.sourceComponentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(row.id, state.sourceComponentName, 0, slot, defaultProps);\n dropHandled.value = true;\n dragDrop.endDrag();\n if (newNodeId !== null) emit('select', newNodeId);\n return;\n }\n if (state.sourceNodeId === null) return;\n nodeTree.moveNodeTo(state.sourceNodeId, row.id, 0, slot);\n dropHandled.value = true;\n dragDrop.endDrag();\n emit('select', state.sourceNodeId);\n return;\n }\n\n const siblingTarget = getSiblingDropTarget(row.id, zone);\n if (!siblingTarget || !isValidSiblingDropTarget(state, siblingTarget.parentId, siblingTarget.slot)) {\n dragDrop.cancelDrag();\n return;\n }\n const parentNode = findNodeById(props.content, siblingTarget.parentId);\n const sourceName = getDraggedComponentName(state);\n const slot =\n parentNode && sourceName\n ? normalizeDropSlot(parentNode, siblingTarget.slot, sourceName) ?? siblingTarget.slot\n : siblingTarget.slot;\n\n if (state.isNewComponent && state.sourceComponentName) {\n const defaultProps = getComponent(state.sourceComponentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(\n siblingTarget.parentId,\n state.sourceComponentName,\n siblingTarget.index,\n slot,\n defaultProps,\n );\n dropHandled.value = true;\n dragDrop.endDrag();\n if (newNodeId !== null) emit('select', newNodeId);\n return;\n }\n if (state.sourceNodeId === null) return;\n // When moving within same parent, removal shifts indices: insert index must be adjusted\n let insertIndex = siblingTarget.index;\n const sourceParent = findParent(props.content, state.sourceNodeId);\n if (\n sourceParent &&\n sourceParent.parent.id === siblingTarget.parentId &&\n sourceParent.index < siblingTarget.index\n ) {\n insertIndex = siblingTarget.index - 1;\n }\n nodeTree.moveNodeTo(state.sourceNodeId, siblingTarget.parentId, insertIndex, slot);\n dropHandled.value = true;\n dragDrop.endDrag();\n emit('select', state.sourceNodeId);\n }\n\n function handleTreeDragEnd() {\n dropTargetRowId.value = null;\n dropZone.value = null;\n if (!dropHandled.value && dragDrop?.dragState.value.isDragging) {\n dragDrop.cancelDrag();\n }\n }\n\n function handleTreeKeydown(event: KeyboardEvent) {\n if (rows.value.length === 0) return;\n\n const currentRowId = getRowIdFromEventTarget(event.target);\n const currentIndex =\n currentRowId === null ? getActiveRowIndex() : rows.value.findIndex((row) => row.id === currentRowId);\n if (currentIndex < 0) return;\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n const nextIndex = Math.min(rows.value.length - 1, currentIndex + 1);\n selectRowByIndex(nextIndex);\n return;\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n const nextIndex = Math.max(0, currentIndex - 1);\n selectRowByIndex(nextIndex);\n return;\n }\n\n if (event.key === 'Home') {\n event.preventDefault();\n selectRowByIndex(0);\n return;\n }\n\n if (event.key === 'End') {\n event.preventDefault();\n selectRowByIndex(rows.value.length - 1);\n return;\n }\n\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n selectRowByIndex(currentIndex);\n }\n }\n\n watch(\n () => props.selectedNodeId,\n (selectedNodeId) => {\n if (selectedNodeId === null) return;\n void nextTick(() => {\n focusRowById(selectedNodeId);\n });\n },\n );\n</script>\n\n<template>\n <div class=\"ipb-tree-panel\">\n <div class=\"ipb-tree-panel__list\" role=\"tree\" :aria-label=\"t('treePanel.ariaLabel')\" @keydown=\"handleTreeKeydown\">\n <div\n v-for=\"row in rows\"\n :key=\"row.key\"\n class=\"ipb-tree-panel__row-wrapper\"\n @dragover=\"handleTreeDragOver(row, $event)\"\n @drop=\"handleTreeDrop(row, $event)\"\n >\n <div\n v-if=\"isDropTargetAbove(row.id)\"\n class=\"ipb-tree-panel__drop-line\"\n data-drop-zone=\"above\"\n aria-hidden=\"true\"\n />\n <button\n :ref=\"(element) => setRowButtonRef(row.id, element)\"\n type=\"button\"\n class=\"ipb-tree-panel__item\"\n :class=\"{\n 'ipb-tree-panel__item--selected': selectedNodeId === row.id,\n 'ipb-tree-panel__item--readonly': row.readonly,\n 'ipb-tree-panel__item--drop-target': isDropTargetOn(row.id),\n 'ipb-tree-panel__item--draggable': isRowDraggable(row),\n }\"\n :style=\"{ paddingInlineStart: `${row.depth * 16 + 8}px` }\"\n :data-node-id=\"row.id\"\n :draggable=\"isRowDraggable(row)\"\n role=\"treeitem\"\n :aria-selected=\"selectedNodeId === row.id ? 'true' : 'false'\"\n :aria-level=\"row.depth + 1\"\n :aria-readonly=\"row.readonly ? 'true' : 'false'\"\n :tabindex=\"isRowTabStop(row.id) ? 0 : -1\"\n @click=\"emit('select', row.id)\"\n @dragstart=\"handleTreeDragStart(row, $event)\"\n @dragend=\"handleTreeDragEnd\"\n >\n <span class=\"ipb-tree-panel__name\">{{ row.name }}</span>\n <span class=\"ipb-tree-panel__id\">#{{ row.id }}</span>\n <span v-if=\"row.readonly\" class=\"ipb-tree-panel__readonly\">{{ t('treePanel.readonly') }}</span>\n </button>\n <div\n v-if=\"isDropTargetBelow(row.id)\"\n class=\"ipb-tree-panel__drop-line\"\n data-drop-zone=\"below\"\n aria-hidden=\"true\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-tree-panel {\n min-width: 0;\n }\n\n .ipb-tree-panel__list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .ipb-tree-panel__row-wrapper {\n display: flex;\n flex-direction: column;\n gap: 0;\n }\n\n .ipb-tree-panel__drop-line {\n min-height: 8px;\n margin: 0 8px;\n padding: 3px 0;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n cursor: default;\n }\n\n .ipb-tree-panel__drop-line::before {\n content: '';\n display: block;\n width: 100%;\n height: 2px;\n border-radius: 1px;\n background: var(--ipb-primary-color, #1d4ed8);\n }\n\n .ipb-tree-panel__item {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-width: 0;\n padding: 6px 8px;\n border: 0;\n border-radius: 4px;\n background: transparent;\n color: inherit;\n text-align: left;\n cursor: pointer;\n font-size: 12px;\n line-height: 1.3;\n }\n\n .ipb-tree-panel__item:hover {\n background: var(--ipb-hover-bg, #f5f5f5);\n }\n\n .ipb-tree-panel__item:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: -1px;\n }\n\n .ipb-tree-panel__item--selected {\n background: var(--ipb-primary-soft, rgba(37, 99, 235, 0.14));\n color: var(--ipb-primary-color, #1d4ed8);\n }\n\n .ipb-tree-panel__item--readonly {\n opacity: 0.8;\n }\n\n .ipb-tree-panel__item--drop-target {\n background: var(--ipb-primary-soft, rgba(37, 99, 235, 0.2));\n outline: 2px dashed var(--ipb-primary-color, #1d4ed8);\n outline-offset: 2px;\n }\n\n .ipb-tree-panel__item--draggable {\n cursor: grab;\n }\n\n .ipb-tree-panel__item--draggable:active {\n cursor: grabbing;\n }\n\n .ipb-tree-panel__name {\n font-weight: 500;\n white-space: nowrap;\n }\n\n .ipb-tree-panel__id {\n color: var(--ipb-text-muted, #6b7280);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;\n font-size: 11px;\n white-space: nowrap;\n }\n\n .ipb-tree-panel__readonly {\n margin-left: auto;\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n color: var(--ipb-text-muted, #6b7280);\n border: 1px solid var(--ipb-border-color, #d1d5db);\n border-radius: 3px;\n padding: 1px 4px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, nextTick, ref, watch, type PropType } from 'vue';\n import { getComponentsByCategory } from '@/core/registry';\n import type { IComponentDefinition } from '@/types/component';\n import type { INode } from '@/types/node';\n import { usePageBuilderI18n } from '@/i18n';\n import TreePanel from './TreePanel.vue';\n\n const props = defineProps({\n open: { type: Boolean, default: true },\n content: { type: Object as PropType<INode | null>, default: null },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n });\n\n const emit = defineEmits<{\n toggle: [];\n dragStart: [componentName: string];\n dragEnd: [];\n add: [componentName: string];\n select: [nodeId: number];\n }>();\n\n const categorizedComponents = computed(() => getComponentsByCategory());\n const { t } = usePageBuilderI18n();\n const searchQuery = ref('');\n const treeOpen = ref(true);\n const DRAWER_CONTENT_ID = 'ipb-left-drawer-content';\n const TREE_PANEL_REGION_ID = 'ipb-left-drawer-tree-panel';\n const drawerRef = ref<HTMLElement | null>(null);\n const drawerToggleRef = ref<HTMLButtonElement | null>(null);\n const searchInputRef = ref<HTMLInputElement | null>(null);\n const focusContentOnNextOpen = ref(false);\n\n const filteredCategorizedComponents = computed(() => {\n const query = searchQuery.value.trim().toLowerCase();\n if (!query) {\n return categorizedComponents.value;\n }\n\n const filtered = new Map<string, IComponentDefinition[]>();\n for (const [category, components] of categorizedComponents.value) {\n const matching = components.filter((comp) => {\n const searchable = [comp.name, comp.label, comp.description ?? '', category, comp.category];\n return searchable.some((value) => value.toLowerCase().includes(query));\n });\n if (matching.length > 0) {\n filtered.set(category, matching);\n }\n }\n\n return filtered;\n });\n\n function handleDragStart(componentName: string, event: DragEvent) {\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'copy';\n event.dataTransfer.setData('application/x-ipb-component', componentName);\n event.dataTransfer.setData('text/plain', componentName);\n }\n emit('dragStart', componentName);\n }\n\n function handleDragEnd() {\n emit('dragEnd');\n }\n\n function handleComponentAdd(componentName: string) {\n emit('add', componentName);\n }\n\n function toggleTree() {\n treeOpen.value = !treeOpen.value;\n }\n\n function getFirstFocusableDrawerControl(): HTMLElement | null {\n const drawer = drawerRef.value;\n if (!drawer) return null;\n\n return drawer.querySelector<HTMLElement>(\n `#${DRAWER_CONTENT_ID} button:not([disabled]), #${DRAWER_CONTENT_ID} input:not([disabled]), #${DRAWER_CONTENT_ID} select:not([disabled]), #${DRAWER_CONTENT_ID} textarea:not([disabled]), #${DRAWER_CONTENT_ID} [tabindex]:not([tabindex=\"-1\"])`,\n );\n }\n\n function focusDrawerContent() {\n searchInputRef.value?.focus();\n if (document.activeElement === searchInputRef.value) return;\n getFirstFocusableDrawerControl()?.focus();\n }\n\n function handleDrawerToggle() {\n focusContentOnNextOpen.value = !props.open;\n emit('toggle');\n }\n\n function getCategoryAriaLabel(category: string): string {\n return t('leftDrawer.category.ariaLabel', { category });\n }\n\n function getDragAriaLabel(label: string): string {\n return t('leftDrawer.component.dragAriaLabel', { label });\n }\n\n watch(\n () => props.open,\n (isOpen, wasOpen) => {\n if (isOpen && !wasOpen && focusContentOnNextOpen.value) {\n void nextTick(() => {\n focusDrawerContent();\n });\n }\n\n if (!isOpen && wasOpen) {\n const activeElement = document.activeElement;\n if (activeElement instanceof HTMLElement && drawerRef.value?.contains(activeElement)) {\n void nextTick(() => {\n drawerToggleRef.value?.focus();\n });\n }\n }\n\n if (isOpen !== wasOpen) {\n focusContentOnNextOpen.value = false;\n }\n },\n );\n</script>\n\n<template>\n <aside\n ref=\"drawerRef\"\n class=\"ipb-left-drawer\"\n :class=\"{ 'ipb-left-drawer--open': open }\"\n :aria-label=\"t('leftDrawer.aria.componentPalette')\"\n role=\"complementary\"\n >\n <div class=\"ipb-left-drawer__header\">\n <span class=\"ipb-left-drawer__title\" id=\"ipb-left-drawer-title\">{{ t('leftDrawer.title') }}</span>\n <button\n ref=\"drawerToggleRef\"\n type=\"button\"\n class=\"ipb-left-drawer__toggle\"\n :aria-label=\"t('leftDrawer.toggle.ariaLabel')\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :aria-controls=\"DRAWER_CONTENT_ID\"\n @click=\"handleDrawerToggle\"\n >\n {{ open ? '◀' : '▶' }}\n </button>\n </div>\n\n <div\n v-if=\"open\"\n :id=\"DRAWER_CONTENT_ID\"\n class=\"ipb-left-drawer__content\"\n role=\"region\"\n aria-labelledby=\"ipb-left-drawer-title\"\n >\n <div class=\"ipb-left-drawer__section\">\n <h3 class=\"ipb-left-drawer__section-title\" id=\"ipb-left-drawer-components-title\">\n {{ t('leftDrawer.section.components') }}\n </h3>\n <div class=\"ipb-left-drawer__search\" role=\"search\">\n <input\n ref=\"searchInputRef\"\n v-model=\"searchQuery\"\n type=\"search\"\n class=\"ipb-left-drawer__search-input\"\n :placeholder=\"t('leftDrawer.search.placeholder')\"\n :aria-label=\"t('leftDrawer.search.ariaLabel')\"\n />\n </div>\n <div\n v-for=\"[category, components] in filteredCategorizedComponents\"\n :key=\"category\"\n class=\"ipb-left-drawer__category\"\n >\n <h4 class=\"ipb-left-drawer__category-title\">{{ category }}</h4>\n <div class=\"ipb-left-drawer__component-list\" role=\"group\" :aria-label=\"getCategoryAriaLabel(category)\">\n <button\n v-for=\"comp in components\"\n :key=\"comp.name\"\n type=\"button\"\n class=\"ipb-left-drawer__component-item\"\n draggable=\"true\"\n :title=\"comp.description\"\n :aria-label=\"getDragAriaLabel(comp.label)\"\n :aria-keyshortcuts=\"'Enter Space'\"\n @click=\"handleComponentAdd(comp.name)\"\n @dragstart=\"handleDragStart(comp.name, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"ipb-left-drawer__component-icon\" aria-hidden=\"true\">{{ comp.icon ?? '◻' }}</span>\n <span class=\"ipb-left-drawer__component-label\">{{ comp.label }}</span>\n </button>\n </div>\n </div>\n <p v-if=\"filteredCategorizedComponents.size === 0\" class=\"ipb-left-drawer__empty\">\n {{ t('leftDrawer.empty') }}\n </p>\n </div>\n\n <div v-if=\"content\" class=\"ipb-left-drawer__section ipb-left-drawer__section--tree\">\n <div class=\"ipb-left-drawer__section-header\">\n <h3 class=\"ipb-left-drawer__section-title\">{{ t('leftDrawer.section.tree') }}</h3>\n <button\n type=\"button\"\n class=\"ipb-left-drawer__section-toggle\"\n :aria-expanded=\"treeOpen ? 'true' : 'false'\"\n :aria-controls=\"TREE_PANEL_REGION_ID\"\n :aria-label=\"t('leftDrawer.tree.toggle.ariaLabel')\"\n @click=\"toggleTree\"\n >\n {{ treeOpen ? '−' : '+' }}\n </button>\n </div>\n\n <div v-if=\"treeOpen\" :id=\"TREE_PANEL_REGION_ID\" role=\"region\" :aria-label=\"t('treePanel.ariaLabel')\">\n <TreePanel :content=\"content\" :selected-node-id=\"selectedNodeId\" @select=\"emit('select', $event)\" />\n </div>\n </div>\n </div>\n </aside>\n</template>\n\n<style scoped>\n .ipb-left-drawer {\n width: 48px;\n background: var(--ipb-drawer-bg, #fff);\n border-right: 1px solid var(--ipb-border-color, #e0e0e0);\n transition: width 0.2s ease;\n overflow: hidden;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n }\n\n .ipb-left-drawer--open {\n width: 260px;\n }\n\n .ipb-left-drawer__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n padding: 12px;\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-left-drawer__title {\n font-weight: 600;\n font-size: 14px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .ipb-left-drawer__toggle {\n flex-shrink: 0;\n background: none;\n border: none;\n cursor: pointer;\n font-size: 12px;\n padding: 4px;\n }\n\n .ipb-left-drawer__toggle:focus-visible,\n .ipb-left-drawer__section-toggle:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n border-radius: 4px;\n }\n\n .ipb-left-drawer__content {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .ipb-left-drawer__section {\n min-width: 0;\n }\n\n .ipb-left-drawer__search {\n margin-top: 8px;\n margin-bottom: 8px;\n }\n\n .ipb-left-drawer__search-input {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: var(--ipb-input-bg, #fff);\n color: var(--ipb-text-color, #111827);\n font-size: 12px;\n }\n\n .ipb-left-drawer__search-input:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-left-drawer__section--tree {\n padding-top: 8px;\n border-top: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-left-drawer__section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 8px;\n }\n\n .ipb-left-drawer__section-title {\n margin: 0;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--ipb-text-muted, #6b7280);\n }\n\n .ipb-left-drawer__section-toggle {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n font-size: 14px;\n line-height: 1;\n }\n\n .ipb-left-drawer__category-title {\n font-size: 11px;\n font-weight: 600;\n margin: 10px 0 8px;\n }\n\n .ipb-left-drawer__component-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .ipb-left-drawer__component-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 4px;\n cursor: grab;\n transition: background 0.15s;\n font-size: 13px;\n width: 100%;\n border: 0;\n background: transparent;\n color: inherit;\n text-align: left;\n }\n\n .ipb-left-drawer__component-item:hover {\n background: var(--ipb-hover-bg, #f5f5f5);\n }\n\n .ipb-left-drawer__component-item:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: -1px;\n }\n\n .ipb-left-drawer__component-icon {\n font-size: 16px;\n width: 24px;\n text-align: center;\n }\n\n .ipb-left-drawer__empty {\n margin: 8px 0 0;\n font-size: 12px;\n color: var(--ipb-text-muted, #6b7280);\n }\n</style>\n","<script setup lang=\"ts\">\n const props = defineProps({\n modelValue: { type: [String, Number, Boolean], default: '' },\n placeholder: { type: String, default: '' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n }>();\n\n function handleInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).value);\n }\n</script>\n\n<template>\n <input\n class=\"ipb-prop-editor ipb-prop-editor--text\"\n type=\"text\"\n :value=\"String(props.modelValue ?? '')\"\n :placeholder=\"placeholder\"\n @input=\"handleInput\"\n />\n</template>\n\n<style scoped>\n .ipb-prop-editor {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-prop-editor:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n modelValue: { type: [String, Number], default: undefined },\n min: { type: Number, default: undefined },\n max: { type: Number, default: undefined },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: number | undefined];\n }>();\n\n const inputValue = computed(() => {\n if (typeof props.modelValue === 'number') return String(props.modelValue);\n if (typeof props.modelValue === 'string') return props.modelValue;\n return '';\n });\n\n function handleInput(event: Event) {\n const value = (event.target as HTMLInputElement).value.trim();\n if (value === '') {\n emit('update:modelValue', undefined);\n return;\n }\n\n const parsed = Number(value);\n emit('update:modelValue', Number.isNaN(parsed) ? undefined : parsed);\n }\n</script>\n\n<template>\n <input\n class=\"ipb-prop-editor ipb-prop-editor--number\"\n type=\"number\"\n :value=\"inputValue\"\n :min=\"min\"\n :max=\"max\"\n @input=\"handleInput\"\n />\n</template>\n\n<style scoped>\n .ipb-prop-editor {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-prop-editor:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useAttrs } from 'vue';\n import { usePageBuilderI18n } from '@/i18n';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n defineProps({\n modelValue: { type: Boolean, default: false },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: boolean];\n }>();\n\n function handleChange(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).checked);\n }\n\n const { t } = usePageBuilderI18n();\n const attrs = useAttrs();\n const checkboxAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n</script>\n\n<template>\n <label class=\"ipb-prop-editor ipb-prop-editor--boolean\" :class=\"attrs.class\" :style=\"attrs.style\">\n <input v-bind=\"checkboxAttrs\" type=\"checkbox\" :checked=\"modelValue\" @change=\"handleChange\" />\n <span>{{ modelValue ? t('propBoolean.enabled') : t('propBoolean.disabled') }}</span>\n </label>\n</template>\n\n<style scoped>\n .ipb-prop-editor--boolean {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n user-select: none;\n }\n\n .ipb-prop-editor--boolean input:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 2px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue';\n import type { IPropDefinition } from '@/types/component';\n import { usePageBuilderI18n } from '@/i18n';\n\n const props = defineProps({\n modelValue: { type: [String, Number, Boolean], default: undefined },\n options: {\n type: Array as () => IPropDefinition['options'],\n default: () => [],\n },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string | number | boolean | undefined];\n }>();\n\n const selectedIndex = computed(() => {\n if (!props.options || props.options.length === 0) return '';\n const idx = props.options.findIndex((option) => option.value === props.modelValue);\n if (idx >= 0) return String(idx);\n return '0';\n });\n\n function handleChange(event: Event) {\n const value = (event.target as HTMLSelectElement).value;\n if (value === '' || !props.options) {\n emit('update:modelValue', undefined);\n return;\n }\n\n const option = props.options[Number(value)];\n emit('update:modelValue', option?.value);\n }\n\n const { t } = usePageBuilderI18n();\n</script>\n\n<template>\n <select class=\"ipb-prop-editor ipb-prop-editor--select\" :value=\"selectedIndex\" @change=\"handleChange\">\n <option v-if=\"!options || options.length === 0\" value=\"\">{{ t('propSelect.noOptions') }}</option>\n <option v-for=\"(option, index) in options ?? []\" :key=\"`${option.label}-${index}`\" :value=\"String(index)\">\n {{ option.label }}\n </option>\n </select>\n</template>\n\n<style scoped>\n .ipb-prop-editor {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n background: var(--ipb-drawer-bg, #fff);\n }\n\n .ipb-prop-editor:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useAttrs } from 'vue';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n const props = defineProps({\n modelValue: { type: String, default: '' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n }>();\n\n const pickerValue = computed(() => {\n const value = props.modelValue.trim();\n if (/^#[0-9a-fA-F]{6}$/.test(value)) return value;\n if (/^#[0-9a-fA-F]{3}$/.test(value)) {\n const chars = value.slice(1).split('');\n return `#${chars.map((char) => `${char}${char}`).join('')}`;\n }\n return '#000000';\n });\n\n function handlePickerInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).value);\n }\n\n function handleTextInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).value);\n }\n\n const attrs = useAttrs();\n const inputAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n</script>\n\n<template>\n <div class=\"ipb-prop-editor ipb-prop-editor--color\" :class=\"attrs.class\" :style=\"attrs.style\">\n <input\n v-bind=\"inputAttrs\"\n class=\"ipb-prop-editor__picker\"\n type=\"color\"\n :value=\"pickerValue\"\n @input=\"handlePickerInput\"\n />\n <input\n v-bind=\"inputAttrs\"\n class=\"ipb-prop-editor__text\"\n type=\"text\"\n :value=\"modelValue\"\n placeholder=\"#000000\"\n @input=\"handleTextInput\"\n />\n </div>\n</template>\n\n<style scoped>\n .ipb-prop-editor--color {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .ipb-prop-editor__picker {\n width: 40px;\n height: 32px;\n padding: 2px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: var(--ipb-drawer-bg, #fff);\n }\n\n .ipb-prop-editor__text {\n flex: 1;\n min-width: 0;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-prop-editor__picker:focus-visible,\n .ipb-prop-editor__text:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, useAttrs, watch } from 'vue';\n import { sanitizeRichTextHtml, sanitizeUrlByKind } from '@/core/sanitize';\n import { usePageBuilderI18n } from '@/i18n';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n const props = defineProps({\n modelValue: { type: String, default: '' },\n placeholder: { type: String, default: 'Type text...' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n }>();\n\n const editorRef = ref<HTMLDivElement | null>(null);\n const lastEmittedValue = ref('');\n\n function getSanitizedHtml(value: unknown): string {\n if (typeof value !== 'string') return '';\n return sanitizeRichTextHtml(value);\n }\n\n function syncEditorHtml(value: string) {\n const editor = editorRef.value;\n if (!editor) return;\n\n const sanitizedHtml = getSanitizedHtml(value);\n if (editor.innerHTML !== sanitizedHtml) {\n editor.innerHTML = sanitizedHtml;\n }\n lastEmittedValue.value = sanitizedHtml;\n }\n\n function emitCurrentHtml() {\n const editor = editorRef.value;\n if (!editor) return;\n\n const sanitizedHtml = getSanitizedHtml(editor.innerHTML);\n if (editor.innerHTML !== sanitizedHtml) {\n editor.innerHTML = sanitizedHtml;\n }\n if (sanitizedHtml === lastEmittedValue.value) return;\n\n lastEmittedValue.value = sanitizedHtml;\n emit('update:modelValue', sanitizedHtml);\n }\n\n function focusEditor() {\n editorRef.value?.focus();\n }\n\n function executeCommand(command: string, value?: string) {\n if (typeof document.execCommand !== 'function') return;\n document.execCommand(command, false, value);\n }\n\n function runCommand(command: 'bold' | 'italic' | 'insertUnorderedList' | 'insertOrderedList') {\n focusEditor();\n executeCommand(command);\n emitCurrentHtml();\n }\n\n function insertLink() {\n focusEditor();\n const rawUrl = window.prompt(t('richText.prompt.enterUrl'), t('richText.prompt.defaultUrl'));\n if (!rawUrl) return;\n\n const safeUrl = sanitizeUrlByKind(rawUrl, 'link');\n if (!safeUrl) return;\n\n executeCommand('createLink', safeUrl);\n emitCurrentHtml();\n }\n\n onMounted(() => {\n syncEditorHtml(getSanitizedHtml(props.modelValue));\n });\n\n watch(\n () => props.modelValue,\n (nextValue) => {\n syncEditorHtml(getSanitizedHtml(nextValue));\n }\n );\n\n const { t } = usePageBuilderI18n();\n const attrs = useAttrs();\n const contentAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n const editorAriaLabel = computed(() => {\n const ariaLabelledBy = attrs['aria-labelledby'];\n const ariaLabel = attrs['aria-label'];\n if (ariaLabelledBy || ariaLabel) return undefined;\n return t('richText.aria.editor');\n });\n</script>\n\n<template>\n <div class=\"ipb-richtext-editor\" :class=\"attrs.class\" :style=\"attrs.style\">\n <div class=\"ipb-richtext-editor__toolbar\" role=\"toolbar\" :aria-label=\"t('richText.aria.toolbar')\">\n <button\n type=\"button\"\n data-command=\"bold\"\n :aria-label=\"t('richText.action.bold')\"\n :title=\"t('richText.action.bold')\"\n @click=\"runCommand('bold')\"\n >\n <strong>B</strong>\n </button>\n <button\n type=\"button\"\n data-command=\"italic\"\n :aria-label=\"t('richText.action.italic')\"\n :title=\"t('richText.action.italic')\"\n @click=\"runCommand('italic')\"\n >\n <em>I</em>\n </button>\n <button\n type=\"button\"\n data-command=\"ul\"\n :aria-label=\"t('richText.action.unorderedList')\"\n :title=\"t('richText.action.unorderedList')\"\n @click=\"runCommand('insertUnorderedList')\"\n >\n UL\n </button>\n <button\n type=\"button\"\n data-command=\"ol\"\n :aria-label=\"t('richText.action.orderedList')\"\n :title=\"t('richText.action.orderedList')\"\n @click=\"runCommand('insertOrderedList')\"\n >\n OL\n </button>\n <button\n type=\"button\"\n data-command=\"link\"\n :aria-label=\"t('richText.action.link')\"\n :title=\"t('richText.action.link')\"\n @click=\"insertLink\"\n >\n {{ t('richText.action.link') }}\n </button>\n </div>\n\n <div\n v-bind=\"contentAttrs\"\n ref=\"editorRef\"\n class=\"ipb-richtext-editor__content\"\n contenteditable=\"true\"\n role=\"textbox\"\n aria-multiline=\"true\"\n :aria-label=\"editorAriaLabel\"\n :data-placeholder=\"placeholder\"\n @input=\"emitCurrentHtml\"\n @blur=\"emitCurrentHtml\"\n />\n </div>\n</template>\n\n<style scoped>\n .ipb-richtext-editor {\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n overflow: hidden;\n }\n\n .ipb-richtext-editor__toolbar {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n padding: 6px;\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n background: var(--ipb-surface-muted, #f8fafc);\n }\n\n .ipb-richtext-editor__toolbar button {\n min-width: 30px;\n height: 28px;\n padding: 0 8px;\n border: 1px solid var(--ipb-border-color, #d1d5db);\n border-radius: 4px;\n background: var(--ipb-drawer-bg, #fff);\n cursor: pointer;\n font-size: 12px;\n }\n\n .ipb-richtext-editor__toolbar button:hover {\n background: var(--ipb-surface-hover, #f3f4f6);\n }\n\n .ipb-richtext-editor__toolbar button:focus-visible,\n .ipb-richtext-editor__content:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-richtext-editor__content {\n min-height: 120px;\n padding: 8px;\n font-size: 13px;\n line-height: 1.5;\n outline: none;\n }\n\n .ipb-richtext-editor__content:empty::before {\n content: attr(data-placeholder);\n color: var(--ipb-text-muted, #9ca3af);\n pointer-events: none;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useAttrs } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n import { usePageBuilderI18n } from '@/i18n';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n const props = defineProps({\n modelValue: { type: String, default: '' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n upload: [];\n }>();\n\n const rawValue = computed(() => props.modelValue.trim());\n const safePreviewUrl = computed(() => sanitizeUrlByKind(rawValue.value, 'media'));\n const hasValue = computed(() => rawValue.value.length > 0);\n const canPreview = computed(() => safePreviewUrl.value.length > 0);\n\n function handleInput(event: Event) {\n const inputValue = (event.target as HTMLInputElement).value;\n emit('update:modelValue', sanitizeUrlByKind(inputValue, 'media'));\n }\n\n function handleClear() {\n emit('update:modelValue', '');\n }\n\n function handleUploadPlaceholder() {\n emit('upload');\n }\n\n const { t } = usePageBuilderI18n();\n const attrs = useAttrs();\n const inputAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n</script>\n\n<template>\n <div class=\"ipb-media-picker\" :class=\"attrs.class\" :style=\"attrs.style\">\n <div class=\"ipb-media-picker__controls\">\n <input\n v-bind=\"inputAttrs\"\n class=\"ipb-media-picker__input\"\n type=\"url\"\n :value=\"modelValue\"\n :placeholder=\"t('mediaPicker.input.placeholder')\"\n @input=\"handleInput\"\n />\n <button class=\"ipb-media-picker__btn\" type=\"button\" :disabled=\"!hasValue\" @click=\"handleClear\">\n {{ t('mediaPicker.clear') }}\n </button>\n <button class=\"ipb-media-picker__btn\" type=\"button\" @click=\"handleUploadPlaceholder\">\n {{ t('mediaPicker.upload') }}\n </button>\n </div>\n\n <div class=\"ipb-media-picker__preview\">\n <img\n v-if=\"hasValue && canPreview\"\n class=\"ipb-media-picker__image\"\n :src=\"safePreviewUrl\"\n :alt=\"t('mediaPicker.preview.alt')\"\n />\n <p v-else class=\"ipb-media-picker__empty\">{{ t('mediaPicker.empty') }}</p>\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-media-picker {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .ipb-media-picker__controls {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto auto;\n gap: 8px;\n align-items: center;\n }\n\n .ipb-media-picker__input {\n min-width: 0;\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-media-picker__btn {\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: var(--ipb-drawer-bg, #fff);\n cursor: pointer;\n font-size: 12px;\n }\n\n .ipb-media-picker__input:focus-visible,\n .ipb-media-picker__btn:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-media-picker__btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .ipb-media-picker__preview {\n border: 1px dashed var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n padding: 6px;\n min-height: 88px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ipb-bg-subtle, #fafafa);\n }\n\n .ipb-media-picker__image {\n max-width: 100%;\n max-height: 140px;\n object-fit: contain;\n display: block;\n }\n\n .ipb-media-picker__empty {\n margin: 0;\n font-size: 12px;\n color: var(--ipb-text-muted, #6b7280);\n text-align: center;\n }\n</style>\n","import type { Component } from 'vue';\nimport type { PropEditorType } from '@/types/component';\nimport PropTextEditor from './PropTextEditor.vue';\nimport PropNumberEditor from './PropNumberEditor.vue';\nimport PropBooleanEditor from './PropBooleanEditor.vue';\nimport PropSelectEditor from './PropSelectEditor.vue';\nimport PropColorEditor from './PropColorEditor.vue';\nimport RichTextEditor from './RichTextEditor.vue';\nimport MediaPicker from './MediaPicker.vue';\n\nexport const DEFAULT_PROP_EDITOR = PropTextEditor;\n\nexport const PROP_EDITORS: Partial<Record<PropEditorType, Component>> = {\n text: PropTextEditor,\n textarea: PropTextEditor,\n richtext: RichTextEditor,\n number: PropNumberEditor,\n boolean: PropBooleanEditor,\n select: PropSelectEditor,\n color: PropColorEditor,\n image: MediaPicker,\n url: MediaPicker,\n json: PropTextEditor,\n};\n","<script setup lang=\"ts\">\n import { computed, nextTick, ref, watch, type PropType, type Component } from 'vue';\n import type { IPropDefinition, PropEditorType } from '@/types/component';\n import type { INode } from '@/types/node';\n import { findNodeById } from '@/core/tree';\n import { getComponent } from '@/core/registry';\n import { usePageBuilderI18n } from '@/i18n';\n import { DEFAULT_PROP_EDITOR, PROP_EDITORS } from './prop-editors';\n\n const props = defineProps({\n open: { type: Boolean, default: false },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n content: { type: Object as PropType<INode>, required: true },\n });\n\n const emit = defineEmits<{\n toggle: [];\n 'update-props': [nodeId: number, props: Record<string, unknown>];\n delete: [nodeId: number];\n duplicate: [nodeId: number];\n }>();\n const { t } = usePageBuilderI18n();\n const drawerRef = ref<HTMLElement | null>(null);\n const drawerToggleRef = ref<HTMLButtonElement | null>(null);\n const focusContentOnNextOpen = ref(false);\n\n const selectedNode = computed(() => {\n if (props.selectedNodeId === null) return null;\n return findNodeById(props.content, props.selectedNodeId) ?? null;\n });\n\n const componentDef = computed(() => {\n if (!selectedNode.value) return null;\n return getComponent(selectedNode.value.name) ?? null;\n });\n\n function getPropValue(propDef: IPropDefinition): unknown {\n if (!selectedNode.value) return propDef.defaultValue ?? '';\n return selectedNode.value.props[propDef.key] ?? propDef.defaultValue ?? '';\n }\n\n function getEditorComponent(type: PropEditorType): Component {\n return PROP_EDITORS[type] ?? DEFAULT_PROP_EDITOR;\n }\n\n function getEditorBindings(propDef: IPropDefinition): Record<string, unknown> {\n const modelValue = getPropValue(propDef);\n\n if (propDef.type === 'number') {\n return {\n modelValue,\n min: propDef.validation?.min,\n max: propDef.validation?.max,\n };\n }\n\n if (propDef.type === 'select') {\n return {\n modelValue,\n options: propDef.options ?? [],\n };\n }\n\n if (propDef.type === 'image' || propDef.type === 'url') {\n return { modelValue };\n }\n\n if (\n propDef.type === 'text' ||\n propDef.type === 'textarea' ||\n propDef.type === 'richtext' ||\n propDef.type === 'json'\n ) {\n return {\n modelValue,\n placeholder: propDef.label,\n };\n }\n\n return { modelValue };\n }\n\n function handlePropUpdate(propKey: string, value: unknown) {\n if (!selectedNode.value) return;\n emit('update-props', selectedNode.value.id, { [propKey]: value });\n }\n\n const DRAWER_CONTENT_ID = 'ipb-right-drawer-content';\n\n function getPropLabelId(propKey: string): string {\n return `ipb-right-drawer-prop-label-${propKey}`;\n }\n\n function getFirstFocusableContentControl(): HTMLElement | null {\n const drawer = drawerRef.value;\n if (!drawer) return null;\n\n return drawer.querySelector<HTMLElement>(\n `#${DRAWER_CONTENT_ID} input:not([disabled]), #${DRAWER_CONTENT_ID} select:not([disabled]), #${DRAWER_CONTENT_ID} textarea:not([disabled]), #${DRAWER_CONTENT_ID} button:not([disabled]), #${DRAWER_CONTENT_ID} [contenteditable]:not([contenteditable=\"false\"]), #${DRAWER_CONTENT_ID} [tabindex]:not([tabindex=\"-1\"])`,\n );\n }\n\n function focusDrawerContent() {\n getFirstFocusableContentControl()?.focus();\n }\n\n function handleDrawerToggle() {\n focusContentOnNextOpen.value = !props.open;\n emit('toggle');\n }\n\n watch(\n () => props.open,\n (isOpen, wasOpen) => {\n if (isOpen && !wasOpen && focusContentOnNextOpen.value) {\n void nextTick(() => {\n focusDrawerContent();\n });\n }\n\n if (!isOpen && wasOpen) {\n const activeElement = document.activeElement;\n if (activeElement instanceof HTMLElement && drawerRef.value?.contains(activeElement)) {\n void nextTick(() => {\n drawerToggleRef.value?.focus();\n });\n }\n }\n\n if (isOpen !== wasOpen) {\n focusContentOnNextOpen.value = false;\n }\n },\n );\n</script>\n\n<template>\n <aside\n ref=\"drawerRef\"\n class=\"ipb-right-drawer\"\n :class=\"{ 'ipb-right-drawer--open': open }\"\n role=\"complementary\"\n :aria-label=\"t('rightDrawer.aria.componentProperties')\"\n >\n <div class=\"ipb-right-drawer__header\">\n <span class=\"ipb-right-drawer__title\" id=\"ipb-right-drawer-title\">{{ t('rightDrawer.title') }}</span>\n <button\n ref=\"drawerToggleRef\"\n type=\"button\"\n class=\"ipb-right-drawer__toggle\"\n :aria-label=\"t('rightDrawer.toggle.ariaLabel')\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :aria-controls=\"DRAWER_CONTENT_ID\"\n @click=\"handleDrawerToggle\"\n >\n {{ open ? '▶' : '◀' }}\n </button>\n </div>\n\n <div\n v-if=\"open && selectedNode && componentDef\"\n :id=\"DRAWER_CONTENT_ID\"\n class=\"ipb-right-drawer__content\"\n role=\"region\"\n aria-labelledby=\"ipb-right-drawer-title\"\n >\n <div class=\"ipb-right-drawer__section\">\n <h3 class=\"ipb-right-drawer__section-title\">{{ componentDef.label }}</h3>\n <p v-if=\"componentDef.description\" class=\"ipb-right-drawer__description\">\n {{ componentDef.description }}\n </p>\n </div>\n\n <div class=\"ipb-right-drawer__section\">\n <h4 class=\"ipb-right-drawer__section-subtitle\">{{ t('rightDrawer.section.properties') }}</h4>\n <!-- Property editors will be rendered here based on editableProps -->\n <div\n v-for=\"propDef in componentDef.editableProps\"\n :key=\"propDef.key\"\n class=\"ipb-right-drawer__prop\"\n :data-prop-key=\"propDef.key\"\n >\n <label :id=\"getPropLabelId(propDef.key)\" class=\"ipb-right-drawer__prop-label\">{{ propDef.label }}</label>\n <component\n :is=\"getEditorComponent(propDef.type)\"\n class=\"ipb-right-drawer__prop-editor\"\n v-bind=\"getEditorBindings(propDef)\"\n :aria-labelledby=\"getPropLabelId(propDef.key)\"\n @update:model-value=\"handlePropUpdate(propDef.key, $event)\"\n />\n </div>\n </div>\n\n <div class=\"ipb-right-drawer__actions\">\n <button\n type=\"button\"\n class=\"ipb-right-drawer__btn\"\n :aria-label=\"t('rightDrawer.actions.duplicate.ariaLabel')\"\n @click=\"emit('duplicate', selectedNode!.id)\"\n >\n {{ t('rightDrawer.actions.duplicate') }}\n </button>\n <button\n type=\"button\"\n class=\"ipb-right-drawer__btn ipb-right-drawer__btn--danger\"\n :disabled=\"selectedNode!.readonly\"\n :aria-label=\"t('rightDrawer.actions.delete.ariaLabel')\"\n @click=\"emit('delete', selectedNode!.id)\"\n >\n {{ t('rightDrawer.actions.delete') }}\n </button>\n </div>\n </div>\n\n <div v-else-if=\"open\" class=\"ipb-right-drawer__empty\">\n <p>{{ t('rightDrawer.empty') }}</p>\n </div>\n </aside>\n</template>\n\n<style scoped>\n .ipb-right-drawer {\n width: 48px;\n background: var(--ipb-drawer-bg, #fff);\n border-left: 1px solid var(--ipb-border-color, #e0e0e0);\n transition: width 0.2s ease;\n overflow: hidden;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n }\n\n .ipb-right-drawer--open {\n width: 320px;\n }\n\n .ipb-right-drawer__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n padding: 12px;\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-right-drawer__title {\n font-weight: 600;\n font-size: 14px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .ipb-right-drawer__toggle {\n flex-shrink: 0;\n background: none;\n border: none;\n cursor: pointer;\n font-size: 12px;\n padding: 4px;\n }\n\n .ipb-right-drawer__toggle:focus-visible,\n .ipb-right-drawer__btn:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-right-drawer__content {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .ipb-right-drawer__section {\n margin-bottom: 20px;\n }\n\n .ipb-right-drawer__section-title {\n font-size: 16px;\n font-weight: 600;\n margin: 0 0 4px;\n }\n\n .ipb-right-drawer__section-subtitle {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--ipb-text-muted, #6b7280);\n margin: 0 0 12px;\n }\n\n .ipb-right-drawer__description {\n font-size: 13px;\n color: var(--ipb-text-muted, #6b7280);\n margin: 0;\n }\n\n .ipb-right-drawer__prop {\n margin-bottom: 12px;\n }\n\n .ipb-right-drawer__prop-label {\n display: block;\n font-size: 12px;\n font-weight: 500;\n margin-bottom: 4px;\n }\n\n .ipb-right-drawer__prop-editor {\n width: 100%;\n }\n\n .ipb-right-drawer__actions {\n display: flex;\n gap: 8px;\n padding-top: 16px;\n border-top: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-right-drawer__btn {\n flex: 1;\n padding: 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: transparent;\n cursor: pointer;\n font-size: 13px;\n }\n\n .ipb-right-drawer__btn--danger {\n color: var(--ipb-danger-color, #dc2626);\n border-color: var(--ipb-danger-color, #dc2626);\n }\n\n .ipb-right-drawer__btn--danger:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n\n .ipb-right-drawer__empty {\n padding: 24px 16px;\n text-align: center;\n color: var(--ipb-text-muted, #6b7280);\n font-size: 13px;\n }\n</style>\n","export const IFRAME_BRIDGE_NAMESPACE = '@improba/page-builder/iframe-bridge';\nexport const IFRAME_BRIDGE_VERSION = 1 as const;\n\ntype IframeBridgeChannel = 'keydown' | 'pointer' | 'lifecycle';\nexport type IframeBridgeSessionToken = string;\n\ninterface IframeBridgeEnvelope<TChannel extends IframeBridgeChannel, TPayload> {\n namespace: typeof IFRAME_BRIDGE_NAMESPACE;\n version: typeof IFRAME_BRIDGE_VERSION;\n sessionToken: IframeBridgeSessionToken;\n channel: TChannel;\n payload: TPayload;\n}\n\nexport interface IframeBridgeKeydownPayload {\n key: string;\n code: string;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n defaultPrevented: boolean;\n isEditable: boolean;\n}\n\nexport type IframeBridgePointerInteraction = 'hover' | 'select' | 'context';\n\ninterface IframeBridgePointerBasePayload {\n interaction: IframeBridgePointerInteraction;\n nodeId: number | null;\n}\n\ninterface IframeBridgePointerContextPayload extends IframeBridgePointerBasePayload {\n interaction: 'context';\n clientX: number;\n clientY: number;\n}\n\ninterface IframeBridgePointerHoverOrSelectPayload extends IframeBridgePointerBasePayload {\n interaction: 'hover' | 'select';\n}\n\nexport type IframeBridgePointerPayload = IframeBridgePointerContextPayload | IframeBridgePointerHoverOrSelectPayload;\n\nexport interface IframeBridgeLifecyclePayload {\n state: 'ready';\n}\n\nexport type IframeBridgeKeydownMessage = IframeBridgeEnvelope<'keydown', IframeBridgeKeydownPayload>;\nexport type IframeBridgePointerMessage = IframeBridgeEnvelope<'pointer', IframeBridgePointerPayload>;\nexport type IframeBridgeLifecycleMessage = IframeBridgeEnvelope<'lifecycle', IframeBridgeLifecyclePayload>;\n\nexport type IframeBridgeMessage = IframeBridgeKeydownMessage | IframeBridgePointerMessage | IframeBridgeLifecycleMessage;\n\nfunction createIframeBridgeEnvelope<TChannel extends IframeBridgeChannel, TPayload>(\n channel: TChannel,\n payload: TPayload,\n sessionToken: IframeBridgeSessionToken,\n): IframeBridgeEnvelope<TChannel, TPayload> {\n return {\n namespace: IFRAME_BRIDGE_NAMESPACE,\n version: IFRAME_BRIDGE_VERSION,\n sessionToken,\n channel,\n payload,\n };\n}\n\nexport function createIframeBridgeSessionToken(): IframeBridgeSessionToken {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID();\n }\n\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n const bytes = new Uint8Array(16);\n globalThis.crypto.getRandomValues(bytes);\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');\n }\n\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;\n}\n\nexport function createIframeBridgeReadyMessage(sessionToken: IframeBridgeSessionToken): IframeBridgeLifecycleMessage {\n return createIframeBridgeEnvelope('lifecycle', { state: 'ready' }, sessionToken);\n}\n\nexport function createIframeBridgePointerMessage(\n payload: IframeBridgePointerPayload,\n sessionToken: IframeBridgeSessionToken,\n): IframeBridgePointerMessage {\n return createIframeBridgeEnvelope('pointer', payload, sessionToken);\n}\n\nexport function createIframeBridgeKeydownMessage(\n payload: IframeBridgeKeydownPayload,\n sessionToken: IframeBridgeSessionToken,\n): IframeBridgeKeydownMessage {\n return createIframeBridgeEnvelope('keydown', payload, sessionToken);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object';\n}\n\nfunction parsePointerPayload(payload: unknown): IframeBridgePointerPayload | null {\n if (!isRecord(payload)) return null;\n\n const interaction = payload.interaction;\n const maybeNodeId = payload.nodeId;\n if (interaction !== 'hover' && interaction !== 'select' && interaction !== 'context') return null;\n if (maybeNodeId !== null && typeof maybeNodeId !== 'number') return null;\n if (typeof maybeNodeId === 'number' && !Number.isInteger(maybeNodeId)) return null;\n\n const nodeId: number | null = maybeNodeId;\n\n if (interaction === 'context') {\n const clientX = payload.clientX;\n const clientY = payload.clientY;\n if (typeof clientX !== 'number' || typeof clientY !== 'number') return null;\n return { interaction, nodeId, clientX, clientY };\n }\n\n return { interaction, nodeId };\n}\n\nfunction parseKeydownPayload(payload: unknown): IframeBridgeKeydownPayload | null {\n if (!isRecord(payload)) return null;\n\n if (typeof payload.key !== 'string') return null;\n if (typeof payload.code !== 'string') return null;\n if (typeof payload.ctrlKey !== 'boolean') return null;\n if (typeof payload.metaKey !== 'boolean') return null;\n if (typeof payload.shiftKey !== 'boolean') return null;\n if (typeof payload.altKey !== 'boolean') return null;\n if (typeof payload.defaultPrevented !== 'boolean') return null;\n if (typeof payload.isEditable !== 'boolean') return null;\n\n return {\n key: payload.key,\n code: payload.code,\n ctrlKey: payload.ctrlKey,\n metaKey: payload.metaKey,\n shiftKey: payload.shiftKey,\n altKey: payload.altKey,\n defaultPrevented: payload.defaultPrevented,\n isEditable: payload.isEditable,\n };\n}\n\nexport interface ParseIframeBridgeMessageOptions {\n expectedSessionToken?: IframeBridgeSessionToken;\n allowLegacyNoSessionToken?: boolean;\n}\n\nexport function parseIframeBridgeMessage(\n value: unknown,\n options: ParseIframeBridgeMessageOptions = {},\n): IframeBridgeMessage | null {\n if (!isRecord(value)) return null;\n if (value.namespace !== IFRAME_BRIDGE_NAMESPACE) return null;\n if (value.version !== IFRAME_BRIDGE_VERSION) return null;\n if (value.channel !== 'keydown' && value.channel !== 'pointer' && value.channel !== 'lifecycle') return null;\n\n const sessionTokenCandidate = value.sessionToken;\n const hasValidSessionToken = typeof sessionTokenCandidate === 'string' && sessionTokenCandidate.length > 0;\n if (options.expectedSessionToken) {\n if (!hasValidSessionToken || sessionTokenCandidate !== options.expectedSessionToken) return null;\n } else if (!hasValidSessionToken && !options.allowLegacyNoSessionToken) {\n return null;\n }\n\n const sessionToken = hasValidSessionToken ? sessionTokenCandidate : '';\n\n if (value.channel === 'lifecycle') {\n if (!isRecord(value.payload) || value.payload.state !== 'ready') return null;\n return createIframeBridgeReadyMessage(sessionToken);\n }\n\n if (value.channel === 'pointer') {\n const payload = parsePointerPayload(value.payload);\n if (!payload) return null;\n return createIframeBridgePointerMessage(payload, sessionToken);\n }\n\n const payload = parseKeydownPayload(value.payload);\n if (!payload) return null;\n return createIframeBridgeKeydownMessage(payload, sessionToken);\n}\n\nexport interface IframeBridgeParentOptions {\n hostWindow: Window;\n expectedSource: Window;\n expectedOrigin: string;\n expectedSessionToken?: IframeBridgeSessionToken;\n allowLegacyNoSessionToken?: boolean;\n onReady?: () => void;\n onPointer?: (payload: IframeBridgePointerPayload) => void;\n onKeydown?: (payload: IframeBridgeKeydownPayload) => void;\n}\n\nexport interface IframeBridgeParent {\n dispose: () => void;\n}\n\nexport function createIframeBridgeParent(options: IframeBridgeParentOptions): IframeBridgeParent {\n const onMessage = (event: MessageEvent) => {\n if (event.source !== options.expectedSource) return;\n if (event.origin !== options.expectedOrigin) return;\n\n const message = parseIframeBridgeMessage(event.data, {\n expectedSessionToken: options.expectedSessionToken,\n allowLegacyNoSessionToken: options.allowLegacyNoSessionToken ?? !options.expectedSessionToken,\n });\n if (!message) return;\n\n if (message.channel === 'lifecycle') {\n options.onReady?.();\n return;\n }\n\n if (message.channel === 'pointer') {\n options.onPointer?.(message.payload);\n return;\n }\n\n options.onKeydown?.(message.payload);\n };\n\n options.hostWindow.addEventListener('message', onMessage);\n return {\n dispose: () => {\n options.hostWindow.removeEventListener('message', onMessage);\n },\n };\n}\n\nexport interface IframeBridgeChild {\n postReady: () => void;\n postPointer: (payload: IframeBridgePointerPayload) => void;\n postKeydown: (payload: IframeBridgeKeydownPayload) => void;\n}\n\nexport interface IframeBridgeChildOptions {\n targetWindow: Window;\n targetOrigin: string;\n sessionToken: IframeBridgeSessionToken;\n}\n\nexport function createIframeBridgeChild(options: IframeBridgeChildOptions): IframeBridgeChild {\n return {\n postReady: () => {\n options.targetWindow.postMessage(createIframeBridgeReadyMessage(options.sessionToken), options.targetOrigin);\n },\n postPointer: (payload) => {\n options.targetWindow.postMessage(\n createIframeBridgePointerMessage(payload, options.sessionToken),\n options.targetOrigin,\n );\n },\n postKeydown: (payload) => {\n options.targetWindow.postMessage(\n createIframeBridgeKeydownMessage(payload, options.sessionToken),\n options.targetOrigin,\n );\n },\n };\n}\n\nexport interface MountIframeBridgeDomListenersOptions {\n frameDocument: Document;\n contentRoot: HTMLElement;\n bridge: IframeBridgeChild;\n resolveNodeId: (target: EventTarget | null) => number | null;\n isEditableTarget: (target: EventTarget | null) => boolean;\n}\n\nfunction shouldAutoPreventShortcut(payload: IframeBridgeKeydownPayload): boolean {\n if (payload.defaultPrevented || payload.isEditable) return false;\n\n const hasModifier = payload.ctrlKey || payload.metaKey;\n const key = payload.key.toLowerCase();\n const code = payload.code.toLowerCase();\n\n if (hasModifier && (key === 'z' || key === 'y' || key === 's')) return true;\n\n const isDeleteKey = key === 'delete' || key === 'backspace' || code === 'delete' || code === 'backspace';\n return isDeleteKey && !payload.ctrlKey && !payload.metaKey && !payload.altKey;\n}\n\nexport function mountIframeBridgeDomListeners(options: MountIframeBridgeDomListenersOptions): () => void {\n const handleClick = (event: MouseEvent) => {\n options.bridge.postPointer({\n interaction: 'select',\n nodeId: options.resolveNodeId(event.target),\n });\n };\n\n const handleMouseMove = (event: MouseEvent) => {\n options.bridge.postPointer({\n interaction: 'hover',\n nodeId: options.resolveNodeId(event.target),\n });\n };\n\n const handleMouseLeave = () => {\n options.bridge.postPointer({\n interaction: 'hover',\n nodeId: null,\n });\n };\n\n const handleContextMenu = (event: MouseEvent) => {\n event.preventDefault();\n options.bridge.postPointer({\n interaction: 'context',\n nodeId: options.resolveNodeId(event.target),\n clientX: event.clientX,\n clientY: event.clientY,\n });\n };\n\n const handleKeydown = (event: KeyboardEvent) => {\n const payload: IframeBridgeKeydownPayload = {\n key: event.key,\n code: event.code,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n defaultPrevented: event.defaultPrevented,\n isEditable:\n options.isEditableTarget(event.target) ||\n options.isEditableTarget(options.frameDocument.activeElement),\n };\n\n if (shouldAutoPreventShortcut(payload)) {\n event.preventDefault();\n }\n\n options.bridge.postKeydown(payload);\n };\n\n options.contentRoot.addEventListener('click', handleClick);\n options.contentRoot.addEventListener('mousemove', handleMouseMove);\n options.contentRoot.addEventListener('mouseleave', handleMouseLeave);\n options.contentRoot.addEventListener('contextmenu', handleContextMenu);\n options.frameDocument.addEventListener('keydown', handleKeydown);\n\n options.bridge.postReady();\n\n return () => {\n options.contentRoot.removeEventListener('click', handleClick);\n options.contentRoot.removeEventListener('mousemove', handleMouseMove);\n options.contentRoot.removeEventListener('mouseleave', handleMouseLeave);\n options.contentRoot.removeEventListener('contextmenu', handleContextMenu);\n options.frameDocument.removeEventListener('keydown', handleKeydown);\n };\n}\n","<script setup lang=\"ts\">\n import { computed, nextTick, onBeforeUnmount, ref, watch, type CSSProperties, type PropType } from 'vue';\n import { usePageBuilderI18n } from '@/i18n';\n\n export type NodeContextMenuAction = 'duplicate' | 'delete' | 'move-up' | 'move-down';\n\n const props = defineProps({\n open: { type: Boolean, default: false },\n x: { type: Number, default: 0 },\n y: { type: Number, default: 0 },\n canDelete: { type: Boolean, default: true },\n canMoveUp: { type: Boolean, default: false },\n canMoveDown: { type: Boolean, default: false },\n });\n\n const emit = defineEmits<{\n action: [action: NodeContextMenuAction];\n close: [];\n }>();\n const { t } = usePageBuilderI18n();\n\n interface MenuItem {\n key: NodeContextMenuAction;\n label: string;\n danger?: boolean;\n disabled?: boolean;\n }\n\n const menuStyle = computed<CSSProperties>(() => ({\n top: `${props.y}px`,\n left: `${props.x}px`,\n }));\n\n const menuItems = computed<MenuItem[]>(() => [\n { key: 'duplicate', label: t('contextMenu.duplicate') },\n { key: 'move-up', label: t('contextMenu.moveUp'), disabled: !props.canMoveUp },\n { key: 'move-down', label: t('contextMenu.moveDown'), disabled: !props.canMoveDown },\n { key: 'delete', label: t('contextMenu.delete'), danger: true, disabled: !props.canDelete },\n ]);\n\n function handleAction(action: NodeContextMenuAction, disabled?: boolean) {\n if (disabled) return;\n emit('action', action);\n }\n\n const menuRootRef = ref<HTMLElement | null>(null);\n const previousFocusedElement = ref<HTMLElement | null>(null);\n\n function getFocusableItems(): HTMLButtonElement[] {\n if (!menuRootRef.value) return [];\n return Array.from(menuRootRef.value.querySelectorAll<HTMLButtonElement>('.ipb-node-context-menu__item')).filter(\n (item) => !item.disabled,\n );\n }\n\n function focusFirstMenuItem() {\n const [firstItem] = getFocusableItems();\n firstItem?.focus();\n }\n\n function restorePreviousFocus() {\n if (previousFocusedElement.value instanceof HTMLElement) {\n previousFocusedElement.value.focus();\n }\n previousFocusedElement.value = null;\n }\n\n function handleMenuKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault();\n emit('close');\n return;\n }\n\n if (event.key === 'Tab') {\n event.preventDefault();\n emit('close');\n return;\n }\n\n const items = getFocusableItems();\n if (items.length === 0) return;\n\n const activeElement = document.activeElement instanceof HTMLButtonElement ? document.activeElement : null;\n const activeIndex = activeElement ? items.indexOf(activeElement) : -1;\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n const nextIndex = activeIndex < 0 ? 0 : (activeIndex + 1) % items.length;\n items[nextIndex]?.focus();\n return;\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n const nextIndex = activeIndex < 0 ? items.length - 1 : (activeIndex - 1 + items.length) % items.length;\n items[nextIndex]?.focus();\n return;\n }\n\n if (event.key === 'Home') {\n event.preventDefault();\n items[0]?.focus();\n return;\n }\n\n if (event.key === 'End') {\n event.preventDefault();\n items[items.length - 1]?.focus();\n }\n }\n\n function handleMenuFocusOut(event: FocusEvent) {\n const nextTarget = event.relatedTarget;\n if (!(nextTarget instanceof Node)) {\n emit('close');\n return;\n }\n if (!menuRootRef.value?.contains(nextTarget)) {\n emit('close');\n }\n }\n\n watch(\n () => props.open,\n (isOpen) => {\n if (isOpen) {\n previousFocusedElement.value = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n void nextTick(() => {\n focusFirstMenuItem();\n });\n return;\n }\n\n restorePreviousFocus();\n },\n { immediate: true },\n );\n\n onBeforeUnmount(() => {\n restorePreviousFocus();\n });\n</script>\n\n<template>\n <div\n v-if=\"open\"\n ref=\"menuRootRef\"\n class=\"ipb-node-context-menu\"\n :style=\"menuStyle\"\n role=\"menu\"\n :aria-label=\"t('contextMenu.ariaLabel')\"\n aria-orientation=\"vertical\"\n tabindex=\"-1\"\n @click.stop\n @contextmenu.prevent\n @keydown=\"handleMenuKeydown\"\n @focusout=\"handleMenuFocusOut\"\n >\n <button\n v-for=\"item in menuItems\"\n :key=\"item.key\"\n type=\"button\"\n class=\"ipb-node-context-menu__item\"\n :class=\"{ 'ipb-node-context-menu__item--danger': item.danger }\"\n :disabled=\"item.disabled\"\n :data-action=\"item.key\"\n role=\"menuitem\"\n :aria-disabled=\"item.disabled ? 'true' : undefined\"\n @click=\"handleAction(item.key, item.disabled)\"\n >\n {{ item.label }}\n </button>\n </div>\n</template>\n\n<style scoped>\n .ipb-node-context-menu {\n position: absolute;\n z-index: 30;\n display: flex;\n flex-direction: column;\n min-width: 148px;\n padding: 6px;\n border: 1px solid var(--ipb-border-color, #d1d5db);\n border-radius: 8px;\n background: #fff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.16);\n }\n\n .ipb-node-context-menu__item {\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--ipb-text-color, #111827);\n font-size: 13px;\n line-height: 1.4;\n text-align: left;\n padding: 7px 10px;\n cursor: pointer;\n }\n\n .ipb-node-context-menu__item:hover:not(:disabled) {\n background: rgba(59, 130, 246, 0.1);\n }\n\n .ipb-node-context-menu__item:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: -1px;\n }\n\n .ipb-node-context-menu__item--danger {\n color: var(--ipb-danger-color, #dc2626);\n }\n\n .ipb-node-context-menu__item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n }\n</style>\n","<script setup lang=\"ts\">\n import {\n computed,\n h,\n inject,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n render,\n watch,\n type CSSProperties,\n type PropType,\n } from 'vue';\n import { getComponent } from '@/core/registry';\n import {\n createIframeBridgeChild,\n createIframeBridgeParent,\n createIframeBridgeSessionToken,\n mountIframeBridgeDomListeners,\n type IframeBridgeKeydownPayload,\n type IframeBridgePointerPayload,\n } from '@/core/iframe-bridge';\n import { normalizeDropSlot } from '@/core/drop-slot';\n import { findNodeById, findParent } from '@/core/tree';\n import { DRAG_DROP_KEY, NODE_TREE_KEY } from '@/types/keys';\n import type { INode } from '@/types/node';\n import type { IViewportSize, ViewportPreset } from '@/types/editor';\n import { VIEWPORT_PRESETS } from '@/types/editor';\n import { usePageBuilderI18n } from '@/i18n';\n import NodeRenderer from '../reader/NodeRenderer.vue';\n import NodeContextMenu, { type NodeContextMenuAction } from './NodeContextMenu.vue';\n\n const props = defineProps({\n content: { type: Object as PropType<INode>, required: true },\n variables: { type: Object as PropType<Record<string, string>>, default: () => ({}) },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n hoveredNodeId: { type: Number as PropType<number | null>, default: null },\n viewport: { type: String as PropType<ViewportPreset>, default: 'desktop' },\n viewportWidth: { type: Number as PropType<number | null>, default: null },\n viewportHeight: { type: Number as PropType<number | null>, default: null },\n });\n\n interface IframeCanvasKeydownPayload extends IframeBridgeKeydownPayload {\n preventDefault: () => void;\n }\n\n const emit = defineEmits<{\n select: [nodeId: number | null];\n hover: [nodeId: number | null];\n 'context-action': [payload: { action: NodeContextMenuAction; nodeId: number }];\n 'iframe-keydown': [payload: IframeCanvasKeydownPayload];\n 'viewport-size-change': [payload: IViewportSize];\n }>();\n\n interface OverlayRect {\n top: number;\n left: number;\n width: number;\n height: number;\n }\n\n interface DropLocation {\n targetId: number;\n index: number;\n slot: string;\n }\n\n const IFRAME_CONTENT_ROOT_ID = 'ipb-iframe-canvas-content';\n const IFRAME_BASE_STYLE_ID = 'ipb-iframe-canvas-base-style';\n const MIN_VIEWPORT_WIDTH = 240;\n const MIN_VIEWPORT_HEIGHT = 320;\n\n const nodeTree = inject(NODE_TREE_KEY, null);\n const dragDrop = inject(DRAG_DROP_KEY, null);\n const { t } = usePageBuilderI18n();\n\n const iframeRef = ref<HTMLIFrameElement | null>(null);\n const stageRef = ref<HTMLElement | null>(null);\n const fallbackContentRef = ref<HTMLElement | null>(null);\n const useFallbackDom = ref(false);\n const contentRef = ref<HTMLElement | null>(null);\n const iframeDocumentRef = ref<Document | null>(null);\n const iframeWindowRef = ref<Window | null>(null);\n const teardownBridgeParentRef = ref<(() => void) | null>(null);\n const teardownBridgeDomRef = ref<(() => void) | null>(null);\n const resizeObserverRef = ref<ResizeObserver | null>(null);\n const currentViewportSize = ref<IViewportSize>({ width: 0, height: 0 });\n const hasViewportSizeReport = ref(false);\n\n const selectedRect = ref<OverlayRect | null>(null);\n const hoveredRect = ref<OverlayRect | null>(null);\n const dropRect = ref<OverlayRect | null>(null);\n const contextMenuOpen = ref(false);\n const contextMenuNodeId = ref<number | null>(null);\n const contextMenuX = ref(0);\n const contextMenuY = ref(0);\n const canDeleteFromMenu = ref(false);\n const canMoveUpFromMenu = ref(false);\n const canMoveDownFromMenu = ref(false);\n\n const resolvedViewportDimensions = computed<IViewportSize>(() => {\n if (props.viewport === 'custom') {\n return {\n width: Math.max(MIN_VIEWPORT_WIDTH, Math.round(props.viewportWidth ?? VIEWPORT_PRESETS.desktop.width)),\n height: Math.max(MIN_VIEWPORT_HEIGHT, Math.round(props.viewportHeight ?? VIEWPORT_PRESETS.desktop.height)),\n };\n }\n\n const preset = VIEWPORT_PRESETS[props.viewport];\n return { width: preset.width, height: preset.height };\n });\n\n const canvasStyle = computed(() => {\n return {\n width: `min(100%, ${resolvedViewportDimensions.value.width}px)`,\n height: `${resolvedViewportDimensions.value.height}px`,\n };\n });\n\n const selectedOverlayStyle = computed<CSSProperties | null>(() =>\n selectedRect.value\n ? {\n top: `${selectedRect.value.top}px`,\n left: `${selectedRect.value.left}px`,\n width: `${selectedRect.value.width}px`,\n height: `${selectedRect.value.height}px`,\n }\n : null,\n );\n\n const hoveredOverlayStyle = computed<CSSProperties | null>(() =>\n hoveredRect.value && props.hoveredNodeId !== props.selectedNodeId\n ? {\n top: `${hoveredRect.value.top}px`,\n left: `${hoveredRect.value.left}px`,\n width: `${hoveredRect.value.width}px`,\n height: `${hoveredRect.value.height}px`,\n }\n : null,\n );\n\n const dropOverlayStyle = computed<CSSProperties | null>(() =>\n dropRect.value\n ? {\n top: `${dropRect.value.top}px`,\n left: `${dropRect.value.left}px`,\n width: `${dropRect.value.width}px`,\n height: `${dropRect.value.height}px`,\n }\n : null,\n );\n\n function isElementTarget(target: EventTarget | null): target is Element {\n if (!target || typeof target !== 'object') return false;\n const maybeNode = target as { nodeType?: number };\n return maybeNode.nodeType === 1;\n }\n\n function parseNodeId(value: string | null): number | null {\n if (value === null) return null;\n const parsed = Number(value);\n return Number.isInteger(parsed) ? parsed : null;\n }\n\n function getNodeIdFromEventTarget(target: EventTarget | null): number | null {\n if (!isElementTarget(target)) return null;\n const marker = target.closest('[data-ipb-node-id]');\n return parseNodeId(marker?.getAttribute('data-ipb-node-id') ?? null);\n }\n\n function findMarkedElement(nodeId: number | null): Element | null {\n if (nodeId === null || !contentRef.value) return null;\n return contentRef.value.querySelector(`[data-ipb-node-id=\"${nodeId}\"]`);\n }\n\n function getOverlayRect(element: Element | null): OverlayRect | null {\n if (!element || !contentRef.value) return null;\n const nodeRect = element.getBoundingClientRect();\n const contentRect = contentRef.value.getBoundingClientRect();\n const frameScrollTop = iframeWindowRef.value?.scrollY ?? 0;\n const frameScrollLeft = iframeWindowRef.value?.scrollX ?? 0;\n\n return {\n top: nodeRect.top - contentRect.top + frameScrollTop,\n left: nodeRect.left - contentRect.left + frameScrollLeft,\n width: nodeRect.width,\n height: nodeRect.height,\n };\n }\n\n function clampIndex(index: number, max: number): number {\n return Math.max(0, Math.min(index, max));\n }\n\n function isNodeInSubtree(root: INode, maybeNodeId: number): boolean {\n if (root.id === maybeNodeId) return true;\n return root.children.some((child) => isNodeInSubtree(child, maybeNodeId));\n }\n\n function getDraggedComponentName(state: { sourceNodeId: number | null; sourceComponentName: string | null }): string | null {\n if (state.sourceComponentName) return state.sourceComponentName;\n if (state.sourceNodeId === null) return null;\n return findNodeById(props.content, state.sourceNodeId)?.name ?? null;\n }\n\n function resolveDropLocation(\n targetNodeId: number | null,\n state: { sourceNodeId: number | null; sourceComponentName: string | null },\n ): DropLocation | null {\n const sourceName = getDraggedComponentName(state);\n if (!sourceName) return null;\n\n const targetNode = targetNodeId === null ? null : findNodeById(props.content, targetNodeId);\n if (targetNode && !targetNode.readonly) {\n const directSlot = normalizeDropSlot(targetNode, 'default', sourceName);\n if (directSlot) {\n return {\n targetId: targetNode.id,\n index: targetNode.children.length,\n slot: directSlot,\n };\n }\n }\n\n if (targetNodeId !== null) {\n const parentResult = findParent(props.content, targetNodeId);\n if (parentResult && !parentResult.parent.readonly) {\n const targetChild = parentResult.parent.children[parentResult.index];\n const slot = normalizeDropSlot(parentResult.parent, targetChild?.slot ?? 'default', sourceName);\n if (slot) {\n return {\n targetId: parentResult.parent.id,\n index: parentResult.index + 1,\n slot,\n };\n }\n }\n }\n\n if (props.content.readonly) return null;\n const rootSlot = normalizeDropSlot(props.content, 'default', sourceName);\n if (!rootSlot) return null;\n\n return {\n targetId: props.content.id,\n index: props.content.children.length,\n slot: rootSlot,\n };\n }\n\n function canMoveNode(\n sourceNodeId: number,\n targetId: number,\n slot: string,\n proposedIndex: number,\n ): { valid: true; index: number; slot: string } | { valid: false } {\n const sourceNode = findNodeById(props.content, sourceNodeId);\n const sourceParentResult = findParent(props.content, sourceNodeId);\n const targetNode = findNodeById(props.content, targetId);\n\n if (!sourceNode || !sourceParentResult || sourceNode.readonly) return { valid: false };\n if (!targetNode || targetNode.readonly) return { valid: false };\n if (sourceNodeId === targetId) return { valid: false };\n if (isNodeInSubtree(sourceNode, targetId)) return { valid: false };\n\n const normalizedSlot = normalizeDropSlot(targetNode, slot, sourceNode.name);\n if (!normalizedSlot) return { valid: false };\n\n const targetChildrenCount = targetNode.children.length;\n if (sourceParentResult.parent.id === targetId && sourceParentResult.index < proposedIndex) {\n return { valid: true, index: clampIndex(proposedIndex - 1, targetChildrenCount), slot: normalizedSlot };\n }\n\n return { valid: true, index: clampIndex(proposedIndex, targetChildrenCount), slot: normalizedSlot };\n }\n\n function ensureIframeBaseStyle(doc: Document) {\n if (doc.getElementById(IFRAME_BASE_STYLE_ID)) return;\n const styleEl = doc.createElement('style');\n styleEl.id = IFRAME_BASE_STYLE_ID;\n styleEl.textContent = `\n html, body {\n margin: 0;\n padding: 0;\n min-height: 100%;\n overflow-x: hidden;\n }\n\n body {\n background: #fff;\n }\n\n #${IFRAME_CONTENT_ROOT_ID} {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-height: 100%;\n overflow-x: hidden;\n box-sizing: border-box;\n }\n\n /* Minimum size for layout containers so empty columns/rows remain droppable in the editor */\n [data-ipb-component=\"PbColumn\"] {\n min-width: 80px;\n min-height: 80px;\n }\n [data-ipb-component=\"PbRow\"] {\n min-height: 80px;\n }\n `;\n doc.head.appendChild(styleEl);\n }\n\n function ensureIframeContentRoot(doc: Document): HTMLElement | null {\n if (!doc.body) return null;\n ensureIframeBaseStyle(doc);\n\n let root = doc.getElementById(IFRAME_CONTENT_ROOT_ID) as HTMLElement | null;\n if (!root) {\n root = doc.createElement('div');\n root.id = IFRAME_CONTENT_ROOT_ID;\n doc.body.innerHTML = '';\n doc.body.appendChild(root);\n }\n return root;\n }\n\n function renderIframeNodeTree() {\n if (!contentRef.value) return;\n render(\n h(NodeRenderer, {\n node: props.content,\n variables: props.variables,\n markNodes: true,\n }),\n contentRef.value,\n );\n }\n\n function unmountIframeNodeTree() {\n if (!contentRef.value) return;\n render(null, contentRef.value);\n }\n\n function syncDraggableMarkers() {\n if (!contentRef.value) return;\n\n const markers = contentRef.value.querySelectorAll<HTMLElement>('[data-ipb-node-id]');\n markers.forEach((element) => {\n const nodeId = parseNodeId(element.getAttribute('data-ipb-node-id'));\n const node = nodeId === null ? null : findNodeById(props.content, nodeId);\n element.draggable = Boolean(node && !node.readonly && node.id !== props.content.id);\n });\n }\n\n function syncOverlayRects() {\n selectedRect.value = getOverlayRect(findMarkedElement(props.selectedNodeId));\n hoveredRect.value = getOverlayRect(findMarkedElement(props.hoveredNodeId));\n const dropTargetId = dragDrop ? dragDrop.dragState.value.dropTargetId : null;\n dropRect.value = dropTargetId === null ? null : getOverlayRect(findMarkedElement(dropTargetId));\n }\n\n function getStageViewportSize(): IViewportSize {\n if (stageRef.value) {\n return {\n width: Math.round(stageRef.value.clientWidth),\n height: Math.round(stageRef.value.clientHeight),\n };\n }\n\n return {\n width: 0,\n height: 0,\n };\n }\n\n function syncViewportSize() {\n const nextSize = getStageViewportSize();\n if (\n hasViewportSizeReport.value &&\n nextSize.width === currentViewportSize.value.width &&\n nextSize.height === currentViewportSize.value.height\n ) {\n return;\n }\n\n currentViewportSize.value = nextSize;\n hasViewportSizeReport.value = true;\n emit('viewport-size-change', nextSize);\n }\n\n function handleCanvasResize() {\n syncOverlayRects();\n syncViewportSize();\n }\n\n function disconnectResizeObserver() {\n resizeObserverRef.value?.disconnect();\n resizeObserverRef.value = null;\n }\n\n function setupResizeObserver() {\n disconnectResizeObserver();\n if (typeof ResizeObserver === 'undefined') return;\n if (!stageRef.value || !contentRef.value) return;\n\n const observer = new ResizeObserver(() => {\n handleCanvasResize();\n });\n\n observer.observe(stageRef.value);\n observer.observe(contentRef.value);\n\n resizeObserverRef.value = observer;\n }\n\n async function syncOverlayRectsAfterRender() {\n await nextTick();\n renderIframeNodeTree();\n await nextTick();\n syncDraggableMarkers();\n syncOverlayRects();\n syncViewportSize();\n }\n\n function clearDropTargetOverlay() {\n dropRect.value = null;\n }\n\n function hideContextMenu() {\n contextMenuOpen.value = false;\n contextMenuNodeId.value = null;\n }\n\n function handleCanvasClick() {\n hideContextMenu();\n emit('select', null);\n emit('hover', null);\n }\n\n function handleContentClick(event: MouseEvent) {\n event.stopPropagation();\n hideContextMenu();\n const nodeId = getNodeIdFromEventTarget(event.target);\n emit('select', nodeId);\n }\n\n function handleContentMouseMove(event: MouseEvent) {\n const nodeId = getNodeIdFromEventTarget(event.target);\n if (nodeId !== props.hoveredNodeId) {\n emit('hover', nodeId);\n }\n }\n\n function handleContentMouseLeave() {\n emit('hover', null);\n }\n\n function handleContentDragStart(event: DragEvent) {\n if (!dragDrop) return;\n const nodeId = getNodeIdFromEventTarget(event.target);\n if (nodeId === null) return;\n\n const node = findNodeById(props.content, nodeId);\n if (!node || node.readonly || node.id === props.content.id) {\n event.preventDefault();\n return;\n }\n\n dragDrop.startDragExisting(nodeId);\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n event.dataTransfer.setData('text/plain', String(nodeId));\n }\n }\n\n function handleContentDragOver(event: DragEvent) {\n if (!dragDrop || !dragDrop.dragState.value.isDragging) return;\n\n const targetNodeId = getNodeIdFromEventTarget(event.target);\n const location = resolveDropLocation(targetNodeId, dragDrop.dragState.value);\n if (!location) {\n clearDropTargetOverlay();\n return;\n }\n\n event.preventDefault();\n dragDrop.updateDropTarget(location.targetId, location.index, location.slot);\n dropRect.value = getOverlayRect(findMarkedElement(location.targetId));\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = dragDrop.dragState.value.isNewComponent ? 'copy' : 'move';\n }\n }\n\n function handleContentDragLeave(event: DragEvent) {\n if (!contentRef.value) return;\n const nextTarget = event.relatedTarget;\n if (nextTarget && typeof nextTarget === 'object' && 'nodeType' in nextTarget) {\n if (contentRef.value.contains(nextTarget as Node)) return;\n }\n clearDropTargetOverlay();\n }\n\n function handleContentDrop(event: DragEvent) {\n event.preventDefault();\n\n if (!dragDrop || !nodeTree || !dragDrop.dragState.value.isDragging) {\n clearDropTargetOverlay();\n return;\n }\n\n const targetNodeId = getNodeIdFromEventTarget(event.target);\n const location = resolveDropLocation(targetNodeId, dragDrop.dragState.value);\n if (!location) {\n dragDrop.cancelDrag();\n clearDropTargetOverlay();\n return;\n }\n\n dragDrop.updateDropTarget(location.targetId, location.index, location.slot);\n const finalState = dragDrop.endDrag();\n clearDropTargetOverlay();\n\n if (finalState.dropTargetId === null) return;\n\n if (finalState.isNewComponent && finalState.sourceComponentName) {\n const defaultProps = getComponent(finalState.sourceComponentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(\n finalState.dropTargetId,\n finalState.sourceComponentName,\n finalState.dropIndex,\n finalState.dropSlot,\n defaultProps,\n );\n if (newNodeId !== null) {\n emit('select', newNodeId);\n }\n return;\n }\n\n if (finalState.sourceNodeId === null) return;\n\n const moveResult = canMoveNode(\n finalState.sourceNodeId,\n finalState.dropTargetId,\n finalState.dropSlot,\n finalState.dropIndex,\n );\n if (!moveResult.valid) return;\n\n nodeTree.moveNodeTo(\n finalState.sourceNodeId,\n finalState.dropTargetId,\n moveResult.index,\n moveResult.slot,\n );\n emit('select', finalState.sourceNodeId);\n }\n\n function handleContentDragEnd() {\n if (dragDrop?.dragState.value.isDragging) {\n dragDrop.cancelDrag();\n }\n clearDropTargetOverlay();\n }\n\n function updateContextMenuCapabilities(nodeId: number) {\n const node = findNodeById(props.content, nodeId);\n if (node?.readonly) {\n canDeleteFromMenu.value = false;\n canMoveUpFromMenu.value = false;\n canMoveDownFromMenu.value = false;\n return;\n }\n\n const parentResult = findParent(props.content, nodeId);\n if (!parentResult) {\n canDeleteFromMenu.value = false;\n canMoveUpFromMenu.value = false;\n canMoveDownFromMenu.value = false;\n return;\n }\n\n canDeleteFromMenu.value = true;\n canMoveUpFromMenu.value = parentResult.index > 0;\n canMoveDownFromMenu.value = parentResult.index < parentResult.parent.children.length - 1;\n }\n\n function handleContentContextMenu(event: MouseEvent) {\n event.preventDefault();\n event.stopPropagation();\n const nodeId = getNodeIdFromEventTarget(event.target);\n if (nodeId === null || !contentRef.value) {\n hideContextMenu();\n return;\n }\n\n const contentRect = contentRef.value.getBoundingClientRect();\n const frameScrollTop = iframeWindowRef.value?.scrollY ?? 0;\n const frameScrollLeft = iframeWindowRef.value?.scrollX ?? 0;\n contextMenuX.value = event.clientX - contentRect.left + frameScrollLeft;\n contextMenuY.value = event.clientY - contentRect.top + frameScrollTop;\n contextMenuNodeId.value = nodeId;\n updateContextMenuCapabilities(nodeId);\n contextMenuOpen.value = true;\n\n emit('select', nodeId);\n }\n\n function handleContextMenuAction(action: NodeContextMenuAction) {\n if (contextMenuNodeId.value === null) return;\n emit('context-action', { action, nodeId: contextMenuNodeId.value });\n hideContextMenu();\n }\n\n function isEditableTarget(target: EventTarget | null): boolean {\n if (!isElementTarget(target)) return false;\n const tagName = target.tagName.toLowerCase();\n if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') return true;\n return Boolean(target.closest('[contenteditable]:not([contenteditable=\"false\"])'));\n }\n\n function handleBridgePointer(payload: IframeBridgePointerPayload) {\n if (payload.interaction === 'hover') {\n if (payload.nodeId !== props.hoveredNodeId) {\n emit('hover', payload.nodeId);\n }\n return;\n }\n\n if (payload.interaction === 'select') {\n hideContextMenu();\n emit('select', payload.nodeId);\n return;\n }\n\n if (payload.interaction !== 'context') return;\n\n if (payload.nodeId === null || !contentRef.value) {\n hideContextMenu();\n return;\n }\n\n const contentRect = contentRef.value.getBoundingClientRect();\n const frameScrollTop = iframeWindowRef.value?.scrollY ?? 0;\n const frameScrollLeft = iframeWindowRef.value?.scrollX ?? 0;\n contextMenuX.value = payload.clientX - contentRect.left + frameScrollLeft;\n contextMenuY.value = payload.clientY - contentRect.top + frameScrollTop;\n contextMenuNodeId.value = payload.nodeId;\n updateContextMenuCapabilities(payload.nodeId);\n contextMenuOpen.value = true;\n\n emit('select', payload.nodeId);\n }\n\n function handleBridgeKeydown(payload: IframeBridgeKeydownPayload) {\n if (payload.key === 'Escape') {\n hideContextMenu();\n }\n\n emit('iframe-keydown', {\n ...payload,\n // Preventing defaults from the parent is asynchronous in postMessage mode.\n preventDefault: () => {},\n });\n }\n\n function getWindowOrigin(targetWindow: Window): string {\n try {\n return targetWindow.location.origin;\n } catch {\n return window.location.origin;\n }\n }\n\n function teardownIframeBridge() {\n teardownBridgeParentRef.value?.();\n teardownBridgeParentRef.value = null;\n\n teardownBridgeDomRef.value?.();\n teardownBridgeDomRef.value = null;\n }\n\n function setupIframeBridge() {\n const frameWindow = iframeWindowRef.value;\n const frameDocument = iframeDocumentRef.value;\n const contentRoot = contentRef.value;\n if (!frameWindow || !frameDocument || !contentRoot) return;\n\n teardownIframeBridge();\n const sessionToken = createIframeBridgeSessionToken();\n\n const bridgeParent = createIframeBridgeParent({\n hostWindow: window,\n expectedSource: window,\n expectedOrigin: getWindowOrigin(window),\n expectedSessionToken: sessionToken,\n onReady: () => {\n void syncOverlayRectsAfterRender();\n },\n onPointer: handleBridgePointer,\n onKeydown: handleBridgeKeydown,\n });\n\n const bridgeChild = createIframeBridgeChild({\n targetWindow: window,\n targetOrigin: getWindowOrigin(window),\n sessionToken,\n });\n\n teardownBridgeParentRef.value = () => bridgeParent.dispose();\n teardownBridgeDomRef.value = mountIframeBridgeDomListeners({\n frameDocument,\n contentRoot,\n bridge: bridgeChild,\n resolveNodeId: getNodeIdFromEventTarget,\n isEditableTarget,\n });\n }\n\n function handleWindowResize() {\n handleCanvasResize();\n }\n\n function teardownIframeListeners() {\n disconnectResizeObserver();\n teardownIframeBridge();\n\n if (contentRef.value) {\n contentRef.value.removeEventListener('click', handleContentClick);\n contentRef.value.removeEventListener('contextmenu', handleContentContextMenu);\n contentRef.value.removeEventListener('mousemove', handleContentMouseMove);\n contentRef.value.removeEventListener('mouseleave', handleContentMouseLeave);\n contentRef.value.removeEventListener('dragstart', handleContentDragStart);\n contentRef.value.removeEventListener('dragover', handleContentDragOver);\n contentRef.value.removeEventListener('dragleave', handleContentDragLeave);\n contentRef.value.removeEventListener('drop', handleContentDrop);\n contentRef.value.removeEventListener('dragend', handleContentDragEnd);\n }\n\n if (!useFallbackDom.value && iframeWindowRef.value) {\n iframeWindowRef.value.removeEventListener('scroll', handleWindowResize);\n iframeWindowRef.value.removeEventListener('resize', handleWindowResize);\n }\n }\n\n function setupIframeListeners() {\n if (!contentRef.value) return;\n\n if (useFallbackDom.value) {\n contentRef.value.addEventListener('click', handleContentClick);\n contentRef.value.addEventListener('contextmenu', handleContentContextMenu);\n contentRef.value.addEventListener('mousemove', handleContentMouseMove);\n contentRef.value.addEventListener('mouseleave', handleContentMouseLeave);\n } else {\n setupIframeBridge();\n }\n\n contentRef.value.addEventListener('dragstart', handleContentDragStart);\n contentRef.value.addEventListener('dragover', handleContentDragOver);\n contentRef.value.addEventListener('dragleave', handleContentDragLeave);\n contentRef.value.addEventListener('drop', handleContentDrop);\n contentRef.value.addEventListener('dragend', handleContentDragEnd);\n\n if (!useFallbackDom.value && iframeWindowRef.value) {\n iframeWindowRef.value.addEventListener('scroll', handleWindowResize);\n iframeWindowRef.value.addEventListener('resize', handleWindowResize);\n }\n\n setupResizeObserver();\n }\n\n function initializeFallbackContent() {\n useFallbackDom.value = true;\n void nextTick().then(() => {\n if (!fallbackContentRef.value) return;\n\n teardownIframeListeners();\n unmountIframeNodeTree();\n\n iframeDocumentRef.value = null;\n iframeWindowRef.value = null;\n contentRef.value = fallbackContentRef.value;\n\n setupIframeListeners();\n void syncOverlayRectsAfterRender();\n });\n }\n\n function initializeIframeDocument() {\n const iframe = iframeRef.value;\n if (!iframe) {\n initializeFallbackContent();\n return;\n }\n\n const frameDocument = iframe.contentDocument;\n const frameWindow = iframe.contentWindow;\n if (!frameDocument || !frameWindow) {\n initializeFallbackContent();\n return;\n }\n\n const frameRoot = ensureIframeContentRoot(frameDocument);\n if (!frameRoot) {\n initializeFallbackContent();\n return;\n }\n\n teardownIframeListeners();\n unmountIframeNodeTree();\n\n useFallbackDom.value = false;\n iframeDocumentRef.value = frameDocument;\n iframeWindowRef.value = frameWindow;\n contentRef.value = frameRoot;\n\n setupIframeListeners();\n void syncOverlayRectsAfterRender();\n }\n\n watch(\n () => [props.selectedNodeId, props.hoveredNodeId],\n () => {\n void syncOverlayRectsAfterRender();\n },\n { immediate: true },\n );\n\n watch(\n () => [props.viewport, props.viewportWidth, props.viewportHeight],\n () => {\n void syncOverlayRectsAfterRender();\n },\n );\n\n watch(\n () => props.content,\n () => {\n if (contextMenuNodeId.value !== null && !findNodeById(props.content, contextMenuNodeId.value)) {\n hideContextMenu();\n }\n void syncOverlayRectsAfterRender();\n },\n { deep: true },\n );\n\n watch(\n () => props.variables,\n () => {\n void syncOverlayRectsAfterRender();\n },\n { deep: true },\n );\n\n watch(\n () => dragDrop?.dragState.value.isDragging ?? false,\n (isDragging) => {\n if (!isDragging) {\n clearDropTargetOverlay();\n }\n },\n );\n\n onMounted(() => {\n window.addEventListener('resize', handleWindowResize);\n iframeRef.value?.addEventListener('load', initializeIframeDocument);\n initializeIframeDocument();\n });\n\n onBeforeUnmount(() => {\n window.removeEventListener('resize', handleWindowResize);\n iframeRef.value?.removeEventListener('load', initializeIframeDocument);\n teardownIframeListeners();\n unmountIframeNodeTree();\n });\n</script>\n\n<template>\n <main class=\"ipb-canvas\" @click=\"handleCanvasClick\" @contextmenu.prevent=\"hideContextMenu\">\n <div class=\"ipb-canvas__viewport\" :style=\"canvasStyle\">\n <div ref=\"stageRef\" class=\"ipb-iframe-canvas__stage\">\n <iframe\n v-if=\"!useFallbackDom\"\n ref=\"iframeRef\"\n class=\"ipb-iframe-canvas__frame\"\n :title=\"t('iframeCanvas.title')\"\n sandbox=\"allow-same-origin\"\n />\n <div\n v-else\n ref=\"fallbackContentRef\"\n id=\"ipb-iframe-canvas-content\"\n class=\"ipb-iframe-canvas__fallback\"\n />\n <div\n v-if=\"dropOverlayStyle\"\n class=\"ipb-canvas__overlay ipb-canvas__overlay--drop\"\n :style=\"dropOverlayStyle\"\n />\n <div\n v-if=\"hoveredOverlayStyle\"\n class=\"ipb-canvas__overlay ipb-canvas__overlay--hovered\"\n :style=\"hoveredOverlayStyle\"\n />\n <div\n v-if=\"selectedOverlayStyle\"\n class=\"ipb-canvas__overlay ipb-canvas__overlay--selected\"\n :style=\"selectedOverlayStyle\"\n />\n <NodeContextMenu\n :open=\"contextMenuOpen\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n :can-delete=\"canDeleteFromMenu\"\n :can-move-up=\"canMoveUpFromMenu\"\n :can-move-down=\"canMoveDownFromMenu\"\n @action=\"handleContextMenuAction\"\n @close=\"hideContextMenu\"\n />\n </div>\n </div>\n </main>\n</template>\n\n<style scoped>\n .ipb-canvas {\n flex: 1;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding: 24px;\n overflow: auto;\n background: var(--ipb-canvas-bg, #e5e7eb);\n }\n\n .ipb-canvas__viewport {\n position: relative;\n flex: 0 0 auto;\n background: #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.06);\n border-radius: 4px;\n overflow: hidden;\n transition: width 0.2s ease, height 0.2s ease;\n }\n\n .ipb-iframe-canvas__stage {\n position: relative;\n width: 100%;\n height: 100%;\n background: #fff;\n }\n\n .ipb-iframe-canvas__frame {\n width: 100%;\n height: 100%;\n border: 0;\n display: block;\n background: #fff;\n }\n\n .ipb-iframe-canvas__fallback {\n position: relative;\n width: 100%;\n height: 100%;\n background: #fff;\n }\n\n .ipb-canvas__overlay {\n position: absolute;\n pointer-events: none;\n border-radius: 4px;\n box-sizing: border-box;\n }\n\n .ipb-canvas__overlay--hovered {\n border: 1px dashed rgba(59, 130, 246, 0.75);\n background: rgba(59, 130, 246, 0.08);\n z-index: 10;\n }\n\n .ipb-canvas__overlay--drop {\n border: 2px dashed rgba(16, 185, 129, 0.9);\n background: rgba(16, 185, 129, 0.14);\n z-index: 12;\n }\n\n .ipb-canvas__overlay--selected {\n border: 2px solid rgba(37, 99, 235, 0.95);\n background: rgba(37, 99, 235, 0.14);\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85) inset;\n z-index: 11;\n }\n</style>\n","<script setup lang=\"ts\">\n import { provide, onMounted, onUnmounted, ref, type PropType } from 'vue';\n import type { IPageData, INode, IPageSavePayload } from '@/types/node';\n import type { IViewportSize, ViewportPreset } from '@/types/editor';\n import { VIEWPORT_PRESETS } from '@/types/editor';\n import { findNodeById, findParent } from '@/core/tree';\n import { getComponent } from '@/core/registry';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import { PAGE_BUILDER_KEY, EDITOR_KEY, NODE_TREE_KEY, DRAG_DROP_KEY } from '@/types/keys';\n import { usePageBuilder } from '@/composables/use-page-builder';\n import { useEditor } from '@/composables/use-editor';\n import { useNodeTree } from '@/composables/use-node-tree';\n import { useDragDrop } from '@/composables/use-drag-drop';\n import EditorToolbar from './EditorToolbar.vue';\n import LeftDrawer from './LeftDrawer.vue';\n import RightDrawer from './RightDrawer.vue';\n import IframeCanvas from './IframeCanvas.vue';\n import type { NodeContextMenuAction } from './NodeContextMenu.vue';\n interface CanvasShortcutPayload {\n key: string;\n code: string;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n defaultPrevented: boolean;\n isEditable: boolean;\n preventDefault: () => void;\n }\n\n\n const props = defineProps({\n pageData: {\n type: Object as PropType<IPageData>,\n required: true,\n },\n });\n\n const emit = defineEmits<{\n save: [payload: IPageSavePayload];\n change: [tree: INode];\n }>();\n\n const pb = usePageBuilder({ initialData: props.pageData, mode: 'edit' });\n const editor = useEditor({ initialSnapshot: pb.getSnapshot() });\n const dragDrop = useDragDrop();\n\n const nodeTree = useNodeTree({\n content: pb.content,\n nextId: pb.nextId,\n onUpdate: (newContent) => {\n pb.updateContent(newContent);\n emit('change', newContent);\n },\n onSnapshot: (label) => {\n editor.pushHistory(label, pb.getSnapshot());\n },\n });\n\n const customViewportWidth = ref(1024);\n const customViewportHeight = ref(768);\n const activeViewportWidth = ref<number | null>(null);\n const activeViewportHeight = ref<number | null>(null);\n\n function handleSave() {\n emit('save', {\n content: pb.content.value,\n layout: pb.layout.value,\n maxId: pb.maxId.value,\n });\n }\n\n function restoreSnapshotAndEmit(snapshot: string | undefined): boolean {\n if (!snapshot) return false;\n try {\n pb.restoreSnapshot(snapshot);\n const selectedNodeId = editor.selectedNodeId.value;\n if (selectedNodeId !== null && !findNodeById(pb.content.value, selectedNodeId)) {\n editor.selectNode(null);\n }\n emit('change', pb.content.value);\n return true;\n } catch (error) {\n reportDevDiagnostic(\n 'PageEditor.restoreSnapshotAndEmit',\n createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Failed to apply history snapshot. Undo/redo step was skipped.',\n {\n cause: error,\n details: {\n snapshotPreview: snapshot.slice(0, 200),\n },\n },\n ),\n );\n return false;\n }\n }\n\n function handleUndo() {\n restoreSnapshotAndEmit(editor.undo());\n }\n\n function handleRedo() {\n restoreSnapshotAndEmit(editor.redo());\n }\n\n function handleDeleteNode(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node || node.readonly) return;\n nodeTree.deleteNode(nodeId);\n }\n\n function handleDuplicateNode(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node) return;\n nodeTree.duplicateNode(nodeId);\n }\n\n function handleMoveNodeUp(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node || node.readonly) return;\n if (!nodeTree.canMoveNodeUp(nodeId)) return;\n nodeTree.moveNodeUp(nodeId);\n }\n\n function handleMoveNodeDown(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node || node.readonly) return;\n if (!nodeTree.canMoveNodeDown(nodeId)) return;\n nodeTree.moveNodeDown(nodeId);\n }\n\n function handleNodeContextAction(payload: { action: NodeContextMenuAction; nodeId: number }) {\n if (payload.action === 'duplicate') {\n handleDuplicateNode(payload.nodeId);\n return;\n }\n\n if (payload.action === 'delete') {\n handleDeleteNode(payload.nodeId);\n return;\n }\n\n if (payload.action === 'move-up') {\n handleMoveNodeUp(payload.nodeId);\n return;\n }\n\n if (payload.action === 'move-down') {\n handleMoveNodeDown(payload.nodeId);\n }\n }\n\n function isEditableTarget(target: EventTarget | null): boolean {\n if (!target || typeof target !== 'object') return false;\n if (!('nodeType' in target) || (target as { nodeType?: number }).nodeType !== 1) return false;\n const element = target as Element;\n const tagName = element.tagName.toLowerCase();\n if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') return true;\n return Boolean(element.closest('[contenteditable]:not([contenteditable=\"false\"])'));\n }\n\n function handleDeleteSelected() {\n const selectedNodeId = editor.selectedNodeId.value;\n if (selectedNodeId === null) return;\n handleDeleteNode(selectedNodeId);\n }\n\n function handleShortcut(payload: CanvasShortcutPayload) {\n if (payload.defaultPrevented || payload.isEditable) return;\n\n const hasModifier = payload.ctrlKey || payload.metaKey;\n const key = payload.key.toLowerCase();\n const code = payload.code.toLowerCase();\n\n if (hasModifier && key === 'z') {\n payload.preventDefault();\n if (payload.shiftKey) {\n handleRedo();\n } else {\n handleUndo();\n }\n return;\n }\n\n if (hasModifier && key === 'y') {\n payload.preventDefault();\n handleRedo();\n return;\n }\n\n if (hasModifier && key === 's') {\n payload.preventDefault();\n handleSave();\n return;\n }\n\n const isDeleteKey = key === 'delete' || key === 'backspace' || code === 'delete' || code === 'backspace';\n if (isDeleteKey && !payload.ctrlKey && !payload.metaKey && !payload.altKey) {\n payload.preventDefault();\n handleDeleteSelected();\n }\n }\n\n function handleEditorKeydown(event: KeyboardEvent) {\n handleShortcut({\n key: event.key,\n code: event.code,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n defaultPrevented: event.defaultPrevented,\n isEditable: isEditableTarget(event.target) || isEditableTarget(document.activeElement),\n preventDefault: () => event.preventDefault(),\n });\n }\n\n function handleIframeKeydown(payload: CanvasShortcutPayload) {\n handleShortcut(payload);\n }\n\n function getViewportDimensions(preset: ViewportPreset): IViewportSize {\n const dimensions = VIEWPORT_PRESETS[preset];\n if (preset === 'custom') {\n return {\n width: customViewportWidth.value,\n height: customViewportHeight.value,\n };\n }\n\n return {\n width: dimensions.width,\n height: dimensions.height,\n };\n }\n\n function handleViewportChange(preset: ViewportPreset) {\n if (preset === 'custom' && editor.viewport.value !== 'custom') {\n if (activeViewportWidth.value !== null && activeViewportHeight.value !== null) {\n customViewportWidth.value = activeViewportWidth.value;\n customViewportHeight.value = activeViewportHeight.value;\n } else {\n const currentViewport = getViewportDimensions(editor.viewport.value);\n customViewportWidth.value = currentViewport.width;\n customViewportHeight.value = currentViewport.height;\n }\n }\n editor.setViewport(preset);\n }\n\n function handleCustomViewportChange(payload: IViewportSize) {\n customViewportWidth.value = payload.width;\n customViewportHeight.value = payload.height;\n if (editor.viewport.value !== 'custom') {\n editor.setViewport('custom');\n }\n }\n\n function handleViewportSizeChange(payload: IViewportSize) {\n activeViewportWidth.value = payload.width;\n activeViewportHeight.value = payload.height;\n }\n\n function handlePaletteDragStart(componentName: string) {\n dragDrop.startDragNew(componentName);\n }\n\n function handlePaletteDragEnd() {\n dragDrop.cancelDrag();\n }\n\n function handlePaletteAdd(componentName: string) {\n const selectedNodeId = editor.selectedNodeId.value;\n const selectedNode = selectedNodeId !== null ? findNodeById(pb.content.value, selectedNodeId) : undefined;\n\n let parentId = pb.content.value.id;\n let index = pb.content.value.children.length;\n let slot = 'default';\n\n if (selectedNodeId !== null && selectedNode) {\n const parentResult = findParent(pb.content.value, selectedNodeId);\n if (parentResult) {\n parentId = parentResult.parent.id;\n index = parentResult.index + 1;\n slot = selectedNode.slot ?? 'default';\n } else {\n // Selected root node: append into root children.\n parentId = selectedNode.id;\n index = selectedNode.children.length;\n }\n }\n\n const defaultProps = getComponent(componentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(parentId, componentName, index, slot, defaultProps);\n if (newNodeId !== null) {\n editor.selectNode(newNodeId);\n }\n }\n\n onMounted(() => {\n window.addEventListener('keydown', handleEditorKeydown);\n });\n\n onUnmounted(() => {\n window.removeEventListener('keydown', handleEditorKeydown);\n });\n\n provide(PAGE_BUILDER_KEY, pb);\n provide(EDITOR_KEY, editor);\n provide(NODE_TREE_KEY, nodeTree);\n provide(DRAG_DROP_KEY, dragDrop);\n</script>\n\n<template>\n <div class=\"ipb-page-editor\">\n <EditorToolbar\n :can-undo=\"editor.canUndo.value\"\n :can-redo=\"editor.canRedo.value\"\n :is-dirty=\"pb.isDirty.value\"\n :viewport=\"editor.viewport.value\"\n :custom-viewport-width=\"customViewportWidth\"\n :custom-viewport-height=\"customViewportHeight\"\n :active-viewport-width=\"activeViewportWidth\"\n :active-viewport-height=\"activeViewportHeight\"\n @undo=\"handleUndo\"\n @redo=\"handleRedo\"\n @save=\"handleSave\"\n @viewport-change=\"handleViewportChange\"\n @custom-viewport-change=\"handleCustomViewportChange\"\n />\n\n <div class=\"ipb-page-editor__body\">\n <LeftDrawer\n :open=\"editor.leftDrawerOpen.value\"\n :content=\"pb.content.value\"\n :selected-node-id=\"editor.selectedNodeId.value\"\n @toggle=\"editor.toggleLeftDrawer\"\n @select=\"editor.selectNode\"\n @add=\"handlePaletteAdd\"\n @drag-start=\"handlePaletteDragStart\"\n @drag-end=\"handlePaletteDragEnd\"\n />\n\n <IframeCanvas\n :content=\"pb.content.value\"\n :variables=\"pb.variables.value\"\n :selected-node-id=\"editor.selectedNodeId.value\"\n :hovered-node-id=\"editor.hoveredNodeId.value\"\n :viewport=\"editor.viewport.value\"\n :viewport-width=\"editor.viewport.value === 'custom' ? customViewportWidth : null\"\n :viewport-height=\"editor.viewport.value === 'custom' ? customViewportHeight : null\"\n @select=\"editor.selectNode\"\n @hover=\"editor.hoverNode\"\n @context-action=\"handleNodeContextAction\"\n @iframe-keydown=\"handleIframeKeydown\"\n @viewport-size-change=\"handleViewportSizeChange\"\n />\n\n <RightDrawer\n :open=\"editor.rightDrawerOpen.value\"\n :selected-node-id=\"editor.selectedNodeId.value\"\n :content=\"pb.content.value\"\n @toggle=\"editor.toggleRightDrawer\"\n @update-props=\"nodeTree.updateNodeProps\"\n @delete=\"handleDeleteNode\"\n @duplicate=\"handleDuplicateNode\"\n />\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-page-editor {\n display: flex;\n flex-direction: column;\n height: 100vh;\n width: 100vw;\n overflow: hidden;\n background: var(--ipb-editor-bg, #f0f2f5);\n }\n\n .ipb-page-editor__body {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, inject, provide, type PropType, watch } from 'vue';\n import type { IPageData, INode, IPageSavePayload } from '@/types/node';\n import type { PageBuilderMode } from '@/types/editor';\n import { validateNode, validatePageData } from '@/core/validation';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import {\n DEFAULT_LOCALE,\n PAGE_BUILDER_I18N_KEY,\n PAGE_BUILDER_I18N_OPTIONS_KEY,\n createTranslator,\n defaultTranslations,\n mergeTranslations,\n type TranslationDictionary,\n } from '@/i18n';\n import PageReader from './reader/PageReader.vue';\n import PageEditor from './editor/PageEditor.vue';\n\n const props = defineProps({\n pageData: {\n type: Object as PropType<IPageData>,\n required: true,\n },\n mode: {\n type: String as PropType<PageBuilderMode>,\n default: 'read',\n },\n locale: {\n type: String,\n default: undefined,\n },\n messages: {\n type: Object as PropType<TranslationDictionary>,\n default: undefined,\n },\n });\n\n const reportedDiagnostics = new Set<string>();\n\n function reportOnce(key: string, message: string, details?: Record<string, unknown>) {\n if (reportedDiagnostics.has(key)) return;\n reportedDiagnostics.add(key);\n reportDevDiagnostic('PageBuilder', createPageBuilderError('INVALID_PAGE_DATA', message, { details }));\n }\n\n const pageData = computed(() => props.pageData);\n const mode = computed<PageBuilderMode>(() => {\n if (props.mode === 'read' || props.mode === 'edit') return props.mode;\n reportOnce(\n 'invalid-mode',\n `[PageBuilder] Unknown mode \"${String(props.mode)}\". Falling back to \"read\".`,\n { mode: props.mode },\n );\n return 'read';\n });\n\n const pageValidationResult = computed(() => validatePageData(pageData.value));\n const canRenderEditor = computed(() => {\n const contentResult = validateNode(pageData.value.content, 'content');\n const layoutResult = validateNode(pageData.value.layout, 'layout');\n return contentResult.isValid && layoutResult.isValid;\n });\n const showEditModeFallback = computed(() => mode.value === 'edit' && !canRenderEditor.value);\n const pluginI18nOptions = inject(PAGE_BUILDER_I18N_OPTIONS_KEY, null);\n const resolvedLocale = computed(() => props.locale ?? pluginI18nOptions?.locale ?? DEFAULT_LOCALE);\n const mergedMessages = computed(() =>\n mergeTranslations(defaultTranslations, pluginI18nOptions?.messages, props.messages),\n );\n const t = createTranslator(() => resolvedLocale.value, () => mergedMessages.value);\n\n watch(\n pageValidationResult,\n (result) => {\n if (result.isValid) return;\n reportOnce(\n 'invalid-page-data',\n '[PageBuilder] Invalid pageData payload detected. Rendering continues with degraded behavior.',\n { errors: result.errors },\n );\n },\n { immediate: true },\n );\n\n defineEmits<{\n save: [payload: IPageSavePayload];\n change: [tree: INode];\n }>();\n\n provide(PAGE_BUILDER_I18N_KEY, {\n locale: resolvedLocale,\n t,\n });\n</script>\n\n<template>\n <div v-if=\"showEditModeFallback\" class=\"ipb-page-builder__warning\" role=\"alert\">\n {{ t('pageBuilder.warning.invalidEditMode') }}\n </div>\n <PageReader v-if=\"mode === 'read' || showEditModeFallback\" :page-data=\"pageData\" />\n <PageEditor\n v-else\n :page-data=\"pageData\"\n @save=\"$emit('save', $event)\"\n @change=\"$emit('change', $event)\"\n />\n</template>\n\n<style scoped>\n .ipb-page-builder__warning {\n margin-bottom: 0.5rem;\n padding: 0.625rem 0.75rem;\n border: 1px solid #f8d7a8;\n border-radius: 0.375rem;\n background-color: #fff8ec;\n color: #7d4a00;\n font-size: 0.875rem;\n }\n</style>\n","import type { App } from 'vue';\nimport type { IComponentDefinition } from '@/types/component';\nimport { getComponent, registerComponents } from '@/core/registry';\nimport { createPageBuilderError } from '@/core/errors';\nimport { builtInComponents } from '@/built-in';\nimport PageBuilder from '@/components/PageBuilder.vue';\nimport { PAGE_BUILDER_I18N_OPTIONS_KEY, type TranslationDictionary } from '@/i18n';\n\nexport interface PageBuilderPluginOptions {\n /** Custom components to register in addition to built-in ones. */\n components?: IComponentDefinition[];\n\n /** If false, built-in components (PbColumn, PbRow, etc.) won't be registered. Default: true. */\n registerBuiltIn?: boolean;\n\n /** Global component name for <PageBuilder>. Default: 'PageBuilder'. Set to false to skip global registration. */\n globalName?: string | false;\n\n /** Default locale for editor UI text. Can be overridden per <PageBuilder> instance. */\n locale?: string;\n\n /** Additional/overridden translation messages grouped by locale. */\n messages?: TranslationDictionary;\n}\n\nconst INSTALLED_APPS = new WeakSet<App>();\n\nfunction registerComponentsIdempotently(definitions: IComponentDefinition[]): void {\n const pendingDefinitions: IComponentDefinition[] = [];\n\n for (const definition of definitions) {\n const normalizedName = definition.name.trim();\n const existing = getComponent(normalizedName);\n if (!existing) {\n pendingDefinitions.push(definition);\n continue;\n }\n\n if (existing.component !== definition.component) {\n throw createPageBuilderError(\n 'DUPLICATE_COMPONENT',\n `[PageBuilder] Component \"${normalizedName}\" is already registered with a different implementation.`,\n {\n details: {\n componentName: normalizedName,\n },\n },\n );\n }\n }\n\n if (pendingDefinitions.length > 0) {\n registerComponents(pendingDefinitions);\n }\n}\n\nexport const PageBuilderPlugin = {\n install(app: App, options: PageBuilderPluginOptions = {}) {\n if (INSTALLED_APPS.has(app)) return;\n INSTALLED_APPS.add(app);\n\n const {\n components = [],\n registerBuiltIn = true,\n globalName = 'PageBuilder',\n locale,\n messages,\n } = options;\n\n app.provide(PAGE_BUILDER_I18N_OPTIONS_KEY, { locale, messages });\n\n if (registerBuiltIn) {\n registerComponentsIdempotently(builtInComponents);\n }\n\n if (components.length > 0) {\n registerComponentsIdempotently(components);\n }\n\n if (globalName !== false) {\n app.component(globalName, PageBuilder);\n }\n },\n};\n","import type { Component, PropType } from 'vue';\n\n/**\n * Metadata describing a page builder component.\n * Every component registered in the page builder must provide this.\n */\nexport interface IComponentDefinition {\n /** Unique name used as key in the registry and in INode.name. */\n name: string;\n\n /** Human-readable label shown in the editor palette. */\n label: string;\n\n /** Short description for the editor tooltip. */\n description?: string;\n\n /** Category for grouping in the component palette. */\n category: ComponentCategory;\n\n /** URL or import path of a preview icon/thumbnail for the palette. */\n icon?: string;\n\n /** The Vue component to render. */\n component: Component;\n\n /** Named slots this component exposes for child nodes. */\n slots: ISlotDefinition[];\n\n /** Editable props schema for the right-drawer property editor. */\n editableProps: IPropDefinition[];\n\n /** Default props applied when the component is first added. */\n defaultProps?: Record<string, unknown>;\n\n /** If true, this component cannot be added by users (used for internal wrappers). */\n hidden?: boolean;\n}\n\nexport type ComponentCategory =\n | 'layout'\n | 'content'\n | 'media'\n | 'navigation'\n | 'form'\n | 'data'\n | 'custom';\n\nexport interface ISlotDefinition {\n /** Slot name matching Vue's named slot system. */\n name: string;\n\n /** Human-readable label. */\n label: string;\n\n /** Component names allowed in this slot. Empty array = all allowed. */\n allowedComponents?: string[];\n}\n\nexport interface IPropDefinition {\n /** Prop key (matches the component prop name). */\n key: string;\n\n /** Human-readable label for the property editor. */\n label: string;\n\n /** Editor widget type. */\n type: PropEditorType;\n\n /** Default value. */\n defaultValue?: unknown;\n\n /** Whether this prop is required. */\n required?: boolean;\n\n /** For 'select' type — available options. */\n options?: { label: string; value: string | number | boolean }[];\n\n /** Validation rules. */\n validation?: {\n min?: number;\n max?: number;\n pattern?: string;\n message?: string;\n };\n}\n\nexport type PropEditorType =\n | 'text'\n | 'textarea'\n | 'richtext'\n | 'number'\n | 'boolean'\n | 'select'\n | 'color'\n | 'image'\n | 'url'\n | 'json';\n\n/**\n * Vue prop type helper for builderOptions.\n * Components expose this as a static property so the registry can read it.\n */\nexport const builderOptionsPropType = {\n type: Object as PropType<IComponentDefinition>,\n};\n"],"names":["PageBuilderError","code","message","options","__publicField","isPageBuilderError","error","createPageBuilderError","toErrorMessage","_registry","getRegistrySnapshot","names","normalizeComponentName","name","createDuplicateComponentError","normalizeAndValidateDefinition","definition","action","normalizedName","normalizedDefinition","registerComponent","registerComponents","definitions","normalizedDefinitions","batchNames","replaceComponent","unregisterComponent","getComponent","resolveComponent","def","getRegisteredComponents","getComponentsByCategory","grouped","list","hasComponent","clearRegistry","builderOptions","props","__props","style","computed","_createElementBlock","_renderSlot","_ctx","SAFE_TEXT_CONTAINER_TAGS","SAFE_RICH_TEXT_TAGS","DROP_ENTIRELY_TAGS","SAFE_LINK_TARGETS","SAFE_LINK_REL_TOKENS","SAFE_DATA_IMAGE_URL_PATTERN","stripControlCharacters","value","normalizeProtocolProbe","sanitizeLinkRel","rel","safeTokens","token","withSafeBlankTargetRel","existingRel","safeRel","relTokens","createSanitizationDocument","_a","parsed","escapeHtml","rawHtml","sanitizeRichTextAttributes","source","target","tagName","attribute","attrName","attrValue","sanitizedHref","sanitizeUrlByKind","normalizedTarget","sanitizedRel","sanitizeRichTextChildren","doc","node","sourceElement","sourceTagName","unwrappedChildren","sanitizedElement","safeChildren","sanitizeRichTextHtml","html","output","normalizeSafeHtmlTag","tag","fallback","normalizedFallback","safeFallback","normalizedTag","url","kind","sanitizedInput","protocolProbe","schemeMatch","scheme","safeTag","safeHtmlContent","_openBlock","_createBlock","_resolveDynamicComponent","safeSrc","safePoster","safeBackgroundImage","cssBackgroundImage","outerStyle","innerStyle","_createElementVNode","withComponent","component","builtInComponents","pbColumnOptions","PbColumn","pbRowOptions","PbRow","pbTextOptions","PbText","pbImageOptions","PbImage","pbVideoOptions","PbVideo","pbSectionOptions","PbSection","pbContainerOptions","PbContainer","PAGE_STATUSES","MAX_VALIDATION_DEPTH","MAX_VALIDATION_NODE_COUNT","isRecord","addError","context","path","validatePbTextProps","validatePbImageProps","validatePbVideoProps","poster","validatePbSectionProps","backgroundImage","validateKnownComponentPropsInto","validateNodeInto","depth","id","slot","children","readonly","index","validateNode","validatePageData","pageData","meta","content","layout","maxId","variables","key","DEFAULT_LOCALE","defaultTranslations","interpolate","params","match","paramName","mergeTranslations","dictionaries","merged","dictionary","locale","messages","translate","fallbackLocale","localeMessages","fallbackMessages","createTranslator","localeSource","dictionarySource","getLocale","getDictionary","PAGE_BUILDER_I18N_OPTIONS_KEY","PAGE_BUILDER_I18N_KEY","fallbackI18nContext","usePageBuilderI18n","inject","getChildren","clampIndex","length","normalized","cloneTree","findNodeById","root","child","found","findParent","childId","i","removeNode","result","insertNode","parentId","parent","targetIndex","insertedNode","moveNode","nodeId","newParentId","sourceParentResult","sourceChildren","rollbackIndex","createNode","walkTree","visitor","visited","visitNode","currentDepth","countNodes","count","getMaxId","max","interpolateProps","safeVariables","_","varName","hasError","ref","capturedError","errorInfo","shouldShowDetails","errorDetails","errorDebugText","segment","onErrorCaptured","_instance","info","_hoisted_1","_hoisted_2","_toDisplayString","_hoisted_3","reportedDiagnostics","reportOnce","details","isNodeObject","maybeNode","sanitizeVariables","rawVariables","entry","safeNode","NodeRenderCrash","defineComponent","localProps","resolutionResult","resolvedComponent","resolvedProps","markerAttrs","renderedAttrs","slotGroups","groups","slotName","ErrorBoundary","_normalizeProps","_guardReactiveProps","_createSlots","_Fragment","_renderList","_component_NodeRenderer","pageValidationResult","contentValidationResult","layoutValidationResult","watch","readerRoot","contentRoot","layoutChildren","_createVNode","NodeRenderer","VIEWPORT_PRESETS","PAGE_BUILDER_KEY","EDITOR_KEY","NODE_TREE_KEY","DRAG_DROP_KEY","isPlainObject","isPositiveInteger","isNonNegativeInteger","createFallbackNode","isNode","variableValue","sanitizeInitialData","initialData","issues","fallbackContent","fallbackLayout","rawMaxId","computedMaxId","hasValidMaxId","parseSnapshot","snapshot","normalizedMaxId","usePageBuilder","initialMode","_initial","mode","isDirty","_initialDirtySnapshot","_serializeDirtyState","_serializeSnapshot","state","_syncDirtyFromCurrentState","setMode","newMode","updateContent","newContent","updateLayout","newLayout","nextId","getSnapshot","restoreSnapshot","reset","original","useEditor","initialSnapshot","initialLabel","initialHistory","baselineSnapshot","reactive","canUndo","canRedo","selectNode","hoverNode","toggleLeftDrawer","toggleRightDrawer","setViewport","preset","syncDirtyWithHistory","currentSnapshot","setHistoryBaseline","label","pushHistory","undo","redo","toRefs","useNodeTree","onUpdate","onSnapshot","_mutate","mutator","currentTree","toRaw","cloned","addNode","componentName","defaultProps","createdNodeId","tree","deleteNode","moveNodeTo","updateNodeProps","duplicateNode","parentResult","_deepCloneWithNewIds","canMoveNodeUp","canMoveNodeDown","moveNodeUp","moveNodeDown","DEFAULT_DROP_SLOT","createInitialDragState","useDragDrop","resetDragState","startDragExisting","startDragNew","updateDropTarget","targetId","endDrag","cancelDrag","MIN_VIEWPORT_WIDTH","MIN_VIEWPORT_HEIGHT","MAX_VIEWPORT_WIDTH","MAX_VIEWPORT_HEIGHT","emit","__emit","t","VIEWPORT_LABEL_KEYS","VIEWPORT_ORDER","viewportButtonRefs","getViewportLabel","getViewportSwitchAriaLabel","setViewportButtonRef","element","maybeElement","getViewportIndex","focusViewportButton","handleViewportKeydown","event","currentPreset","currentIndex","nextIndex","nextPreset","nextTick","clampViewportSize","min","parseViewportSize","updateCustomViewportSize","dimension","rawValue","width","height","_unref","$emit","_hoisted_4","_normalizeClass","$event","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_10","_hoisted_12","_hoisted_14","_hoisted_15","getAllowedDropSlots","parentNode","allowedComponents","normalizeDropSlot","preferredSlot","allowedSlots","preferred","defaultSlot","toSafeInteger","createStableNodeKey","flattenTree","createKey","rows","stack","current","computeWindowRange","total","startIndex","windowSize","overscan","safeTotal","safeWindowSize","safeOverscan","maxStart","safeStartIndex","start","end","sliceWindow","range","createVirtualTreeIndexMaps","keyByIndex","indexByKey","indexByNodeId","row","nodeTree","dragDrop","dropHandled","dropTargetRowId","dropZone","rootId","getDropZoneFromEvent","rowElement","dropZoneEl","_b","zoneAttr","rect","y","third","getSiblingDropTarget","rowId","zone","rowNode","isNodeInSubtree","getDraggedComponentName","isValidDropTarget","targetNodeId","sourceName","targetNode","sourceNode","isValidSiblingDropTarget","rowButtonRefs","setRowButtonRef","getRowIdFromEventTarget","getActiveRowIndex","fallbackToFirst","selectedIndex","focusRowById","selectRowByIndex","isRowTabStop","activeIndex","canDragDrop","isDropTargetOn","isDropTargetAbove","isDropTargetBelow","isRowDraggable","handleTreeDragStart","handleTreeDragOver","siblingTarget","handleTreeDrop","newNodeId","insertIndex","sourceParent","handleTreeDragEnd","handleTreeKeydown","currentRowId","selectedNodeId","_normalizeStyle","_hoisted_9","DRAWER_CONTENT_ID","TREE_PANEL_REGION_ID","categorizedComponents","searchQuery","treeOpen","drawerRef","drawerToggleRef","searchInputRef","focusContentOnNextOpen","filteredCategorizedComponents","query","filtered","category","components","matching","comp","handleDragStart","handleDragEnd","handleComponentAdd","toggleTree","getFirstFocusableDrawerControl","drawer","focusDrawerContent","handleDrawerToggle","getCategoryAriaLabel","getDragAriaLabel","isOpen","wasOpen","activeElement","_hoisted_5","_hoisted_13","_hoisted_16","_hoisted_17","_hoisted_18","TreePanel","_cache","handleInput","inputValue","handleChange","attrs","useAttrs","checkboxAttrs","_class","_style","rest","_mergeProps","idx","option","pickerValue","char","handlePickerInput","handleTextInput","inputAttrs","editorRef","lastEmittedValue","getSanitizedHtml","syncEditorHtml","editor","sanitizedHtml","emitCurrentHtml","focusEditor","executeCommand","command","runCommand","insertLink","rawUrl","safeUrl","onMounted","nextValue","contentAttrs","editorAriaLabel","ariaLabelledBy","ariaLabel","safePreviewUrl","hasValue","canPreview","handleClear","handleUploadPlaceholder","DEFAULT_PROP_EDITOR","PropTextEditor","PROP_EDITORS","RichTextEditor","PropNumberEditor","PropBooleanEditor","PropSelectEditor","PropColorEditor","MediaPicker","selectedNode","componentDef","getPropValue","propDef","getEditorComponent","type","getEditorBindings","modelValue","handlePropUpdate","propKey","getPropLabelId","getFirstFocusableContentControl","_hoisted_11","IFRAME_BRIDGE_NAMESPACE","IFRAME_BRIDGE_VERSION","createIframeBridgeEnvelope","channel","payload","sessionToken","createIframeBridgeSessionToken","bytes","byte","createIframeBridgeReadyMessage","createIframeBridgePointerMessage","createIframeBridgeKeydownMessage","parsePointerPayload","interaction","maybeNodeId","clientX","clientY","parseKeydownPayload","parseIframeBridgeMessage","sessionTokenCandidate","hasValidSessionToken","createIframeBridgeParent","onMessage","_c","createIframeBridgeChild","shouldAutoPreventShortcut","hasModifier","mountIframeBridgeDomListeners","handleClick","handleMouseMove","handleMouseLeave","handleContextMenu","handleKeydown","menuStyle","menuItems","handleAction","disabled","menuRootRef","previousFocusedElement","getFocusableItems","item","focusFirstMenuItem","firstItem","restorePreviousFocus","handleMenuKeydown","items","_d","handleMenuFocusOut","nextTarget","onBeforeUnmount","IFRAME_CONTENT_ROOT_ID","IFRAME_BASE_STYLE_ID","iframeRef","stageRef","fallbackContentRef","useFallbackDom","contentRef","iframeDocumentRef","iframeWindowRef","teardownBridgeParentRef","teardownBridgeDomRef","resizeObserverRef","currentViewportSize","hasViewportSizeReport","selectedRect","hoveredRect","dropRect","contextMenuOpen","contextMenuNodeId","contextMenuX","contextMenuY","canDeleteFromMenu","canMoveUpFromMenu","canMoveDownFromMenu","resolvedViewportDimensions","canvasStyle","selectedOverlayStyle","hoveredOverlayStyle","dropOverlayStyle","isElementTarget","parseNodeId","getNodeIdFromEventTarget","marker","findMarkedElement","getOverlayRect","nodeRect","contentRect","frameScrollTop","frameScrollLeft","resolveDropLocation","directSlot","targetChild","rootSlot","canMoveNode","sourceNodeId","proposedIndex","normalizedSlot","targetChildrenCount","ensureIframeBaseStyle","styleEl","ensureIframeContentRoot","renderIframeNodeTree","render","h","unmountIframeNodeTree","syncDraggableMarkers","syncOverlayRects","dropTargetId","getStageViewportSize","syncViewportSize","nextSize","handleCanvasResize","disconnectResizeObserver","setupResizeObserver","observer","syncOverlayRectsAfterRender","clearDropTargetOverlay","hideContextMenu","handleCanvasClick","handleContentClick","handleContentMouseMove","handleContentMouseLeave","handleContentDragStart","handleContentDragOver","location","handleContentDragLeave","handleContentDrop","finalState","moveResult","handleContentDragEnd","updateContextMenuCapabilities","handleContentContextMenu","handleContextMenuAction","isEditableTarget","handleBridgePointer","handleBridgeKeydown","getWindowOrigin","targetWindow","teardownIframeBridge","setupIframeBridge","frameWindow","frameDocument","bridgeParent","bridgeChild","handleWindowResize","teardownIframeListeners","setupIframeListeners","initializeFallbackContent","initializeIframeDocument","iframe","frameRoot","isDragging","NodeContextMenu","pb","customViewportWidth","customViewportHeight","activeViewportWidth","activeViewportHeight","handleSave","restoreSnapshotAndEmit","handleUndo","handleRedo","handleDeleteNode","handleDuplicateNode","handleMoveNodeUp","handleMoveNodeDown","handleNodeContextAction","handleDeleteSelected","handleShortcut","handleEditorKeydown","handleIframeKeydown","getViewportDimensions","dimensions","handleViewportChange","currentViewport","handleCustomViewportChange","handleViewportSizeChange","handlePaletteDragStart","handlePaletteDragEnd","handlePaletteAdd","onUnmounted","provide","EditorToolbar","LeftDrawer","IframeCanvas","RightDrawer","canRenderEditor","contentResult","layoutResult","showEditModeFallback","pluginI18nOptions","resolvedLocale","mergedMessages","PageReader","PageEditor","INSTALLED_APPS","registerComponentsIdempotently","pendingDefinitions","existing","PageBuilderPlugin","app","registerBuiltIn","globalName","PageBuilder","builderOptionsPropType"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/core/registry.ts","../src/built-in/PbColumn.vue","../src/built-in/PbRow.vue","../src/built-in/PbText.vue","../src/built-in/PbImage.vue","../src/built-in/PbVideo.vue","../src/built-in/PbSection.vue","../src/built-in/PbContainer.vue","../src/built-in/index.ts","../src/i18n/messages.ts","../src/i18n/translator.ts","../src/i18n/context.ts","../src/components/shared/ErrorBoundary.vue","../src/components/reader/NodeRenderer.vue","../src/components/reader/PageReader.vue","../src/types/editor.ts","../src/types/keys.ts","../src/composables/use-page-builder.ts","../src/composables/use-editor.ts","../src/composables/use-node-tree.ts","../src/composables/use-drag-drop.ts","../src/components/editor/EditorToolbar.vue","../src/core/drop-slot.ts","../src/components/editor/TreePanel.vue","../src/components/editor/LeftDrawer.vue","../src/components/editor/prop-editors/PropTextEditor.vue","../src/components/editor/prop-editors/PropNumberEditor.vue","../src/components/editor/prop-editors/PropBooleanEditor.vue","../src/components/editor/prop-editors/PropSelectEditor.vue","../src/components/editor/prop-editors/PropColorEditor.vue","../src/components/editor/prop-editors/RichTextEditor.vue","../src/components/editor/prop-editors/MediaPicker.vue","../src/components/editor/prop-editors/index.ts","../src/components/editor/RightDrawer.vue","../src/core/iframe-bridge.ts","../src/components/editor/NodeContextMenu.vue","../src/components/editor/IframeCanvas.vue","../src/components/editor/PageEditor.vue","../src/components/PageBuilder.vue","../src/plugin.ts","../src/types/component.ts"],"sourcesContent":["import type { Component } from 'vue';\nimport type { IComponentDefinition } from '@/types/component';\nimport { createPageBuilderError } from '@/core/errors';\n\n// Core registry intentionally uses a plain Map to preserve reference identity\n// and avoid coupling core logic to Vue reactivity internals.\nconst _registry = new Map<string, IComponentDefinition>();\n\nfunction getRegistrySnapshot(): string {\n const names = [..._registry.keys()];\n return names.length > 0 ? names.join(', ') : '(none)';\n}\n\nfunction normalizeComponentName(name: string): string {\n return name.trim();\n}\n\nfunction createDuplicateComponentError(name: string, message: string) {\n return createPageBuilderError(\n 'DUPLICATE_COMPONENT',\n message,\n {\n details: {\n componentName: name,\n },\n },\n );\n}\n\nfunction normalizeAndValidateDefinition(\n definition: IComponentDefinition,\n action: 'register' | 'replace',\n): IComponentDefinition {\n const normalizedName = normalizeComponentName(definition.name);\n const normalizedDefinition =\n normalizedName === definition.name ? definition : { ...definition, name: normalizedName };\n if (!normalizedName) {\n throw createPageBuilderError(\n 'INVALID_PAGE_DATA',\n `[PageBuilder] Cannot ${action} a component without a name.`,\n );\n }\n\n if (!normalizedDefinition.component) {\n throw createPageBuilderError(\n 'INVALID_PAGE_DATA',\n `[PageBuilder] Component \"${normalizedName}\" is missing a Vue component instance.`,\n );\n }\n\n return normalizedDefinition;\n}\n\n/**\n * Register a component for use in the page builder.\n * Throws if a component with the same name is already registered.\n */\nexport function registerComponent(definition: IComponentDefinition): void {\n const normalizedDefinition = normalizeAndValidateDefinition(definition, 'register');\n const normalizedName = normalizedDefinition.name;\n\n if (_registry.has(normalizedName)) {\n throw createDuplicateComponentError(\n normalizedName,\n `[PageBuilder] Component \"${normalizedName}\" is already registered. Use replaceComponent() to override.`,\n );\n }\n\n _registry.set(normalizedName, normalizedDefinition);\n}\n\n/**\n * Register multiple components at once.\n */\nexport function registerComponents(definitions: IComponentDefinition[]): void {\n const normalizedDefinitions = definitions.map((definition) =>\n normalizeAndValidateDefinition(definition, 'register'),\n );\n const batchNames = new Set<string>();\n\n for (const definition of normalizedDefinitions) {\n if (batchNames.has(definition.name)) {\n throw createDuplicateComponentError(\n definition.name,\n `[PageBuilder] Component \"${definition.name}\" appears multiple times in the registration batch.`,\n );\n }\n batchNames.add(definition.name);\n\n if (_registry.has(definition.name)) {\n throw createDuplicateComponentError(\n definition.name,\n `[PageBuilder] Component \"${definition.name}\" is already registered. Use replaceComponent() to override.`,\n );\n }\n }\n\n for (const definition of normalizedDefinitions) {\n _registry.set(definition.name, definition);\n }\n}\n\n/**\n * Replace an existing component registration.\n */\nexport function replaceComponent(definition: IComponentDefinition): void {\n const normalizedDefinition = normalizeAndValidateDefinition(definition, 'replace');\n const normalizedName = normalizedDefinition.name;\n\n _registry.set(normalizedName, normalizedDefinition);\n}\n\n/**\n * Unregister a component by name.\n */\nexport function unregisterComponent(name: string): boolean {\n return _registry.delete(normalizeComponentName(name));\n}\n\n/**\n * Retrieve a component definition by name. Returns undefined if not found.\n */\nexport function getComponent(name: string): IComponentDefinition | undefined {\n return _registry.get(normalizeComponentName(name));\n}\n\n/**\n * Retrieve the Vue component for rendering. Throws if not found.\n */\nexport function resolveComponent(name: string): Component {\n const normalizedName = normalizeComponentName(name);\n const def = _registry.get(normalizedName);\n if (!def) {\n throw createPageBuilderError(\n 'MISSING_COMPONENT',\n `[PageBuilder] Component \"${normalizedName}\" is not registered. Available: ${getRegistrySnapshot()}`,\n {\n details: {\n componentName: normalizedName,\n availableComponents: [..._registry.keys()],\n },\n },\n );\n }\n return def.component;\n}\n\n/**\n * Get all registered component definitions.\n */\nexport function getRegisteredComponents(): IComponentDefinition[] {\n return [..._registry.values()];\n}\n\n/**\n * Get all registered component definitions grouped by category.\n */\nexport function getComponentsByCategory(): Map<string, IComponentDefinition[]> {\n const grouped = new Map<string, IComponentDefinition[]>();\n for (const def of _registry.values()) {\n if (def.hidden) continue;\n const list = grouped.get(def.category) ?? [];\n list.push(def);\n grouped.set(def.category, list);\n }\n return grouped;\n}\n\n/**\n * Check if a component is registered.\n */\nexport function hasComponent(name: string): boolean {\n return _registry.has(normalizeComponentName(name));\n}\n\n/**\n * Clear all registered components. Mainly useful for testing.\n */\nexport function clearRegistry(): void {\n _registry.clear();\n}\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbColumn',\n label: 'Column',\n description: 'Vertical flex container for stacking components.',\n category: 'layout',\n icon: '⬜',\n component: {} as any, // self-reference set at registration\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'gap', label: 'Gap', type: 'text', defaultValue: '16px' },\n { key: 'padding', label: 'Padding', type: 'text', defaultValue: '0' },\n { key: 'align', label: 'Align Items', type: 'select', defaultValue: 'stretch', options: [\n { label: 'Stretch', value: 'stretch' },\n { label: 'Start', value: 'flex-start' },\n { label: 'Center', value: 'center' },\n { label: 'End', value: 'flex-end' },\n ]},\n ],\n defaultProps: { gap: '16px', padding: '0', align: 'stretch' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n gap: { type: String, default: '16px' },\n padding: { type: String, default: '0' },\n align: { type: String, default: 'stretch' },\n });\n\n const style = computed(() => ({\n display: 'flex',\n flexDirection: 'column' as const,\n gap: props.gap,\n padding: props.padding,\n alignItems: props.align,\n width: '100%',\n }));\n</script>\n\n<template>\n <div :style=\"style\">\n <slot />\n </div>\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbRow',\n label: 'Row',\n description: 'Horizontal flex container for side-by-side components.',\n category: 'layout',\n icon: '⬛',\n component: {} as any,\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'gap', label: 'Gap', type: 'text', defaultValue: '16px' },\n { key: 'wrap', label: 'Wrap', type: 'boolean', defaultValue: true },\n { key: 'justify', label: 'Justify', type: 'select', defaultValue: 'flex-start', options: [\n { label: 'Start', value: 'flex-start' },\n { label: 'Center', value: 'center' },\n { label: 'End', value: 'flex-end' },\n { label: 'Space Between', value: 'space-between' },\n { label: 'Space Around', value: 'space-around' },\n ]},\n ],\n defaultProps: { gap: '16px', wrap: true, justify: 'flex-start' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n gap: { type: String, default: '16px' },\n wrap: { type: Boolean, default: true },\n justify: { type: String, default: 'flex-start' },\n });\n\n const style = computed(() => ({\n display: 'flex',\n flexDirection: 'row' as const,\n gap: props.gap,\n flexWrap: props.wrap ? ('wrap' as const) : ('nowrap' as const),\n justifyContent: props.justify,\n width: '100%',\n }));\n</script>\n\n<template>\n <div :style=\"style\">\n <slot />\n </div>\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbText',\n label: 'Text',\n description: 'A text block with HTML support.',\n category: 'content',\n icon: 'T',\n component: {} as any,\n slots: [],\n editableProps: [\n { key: 'content', label: 'Content', type: 'richtext', defaultValue: '<p>Enter text here</p>' },\n { key: 'tag', label: 'HTML Tag', type: 'select', defaultValue: 'div', options: [\n { label: 'div', value: 'div' },\n { label: 'p', value: 'p' },\n { label: 'span', value: 'span' },\n { label: 'h1', value: 'h1' },\n { label: 'h2', value: 'h2' },\n { label: 'h3', value: 'h3' },\n ]},\n ],\n defaultProps: { content: '<p>Enter text here</p>', tag: 'div' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { normalizeSafeHtmlTag, sanitizeRichTextHtml } from '@/core/sanitize';\n\n const props = defineProps({\n content: { type: String, default: '' },\n tag: { type: String, default: 'div' },\n });\n\n const safeTag = computed(() => normalizeSafeHtmlTag(props.tag));\n const safeHtmlContent = computed(() => sanitizeRichTextHtml(props.content));\n</script>\n\n<template>\n <component :is=\"safeTag\" v-html=\"safeHtmlContent\" />\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbImage',\n label: 'Image',\n description: 'Displays an image with optional alt text.',\n category: 'media',\n icon: '🖼',\n component: {} as any,\n slots: [],\n editableProps: [\n { key: 'src', label: 'Image URL', type: 'image', required: true },\n { key: 'alt', label: 'Alt Text', type: 'text', defaultValue: '' },\n { key: 'width', label: 'Width', type: 'text', defaultValue: '100%' },\n { key: 'objectFit', label: 'Object Fit', type: 'select', defaultValue: 'cover', options: [\n { label: 'Cover', value: 'cover' },\n { label: 'Contain', value: 'contain' },\n { label: 'Fill', value: 'fill' },\n { label: 'None', value: 'none' },\n ]},\n ],\n defaultProps: { src: '', alt: '', width: '100%', objectFit: 'cover' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n\n const props = defineProps({\n src: { type: String, required: true },\n alt: { type: String, default: '' },\n width: { type: String, default: '100%' },\n objectFit: { type: String, default: 'cover' },\n });\n\n const style = computed(() => ({\n width: props.width,\n objectFit: props.objectFit as any,\n display: 'block',\n maxWidth: '100%',\n }));\n\n const safeSrc = computed(() => sanitizeUrlByKind(props.src, 'media'));\n</script>\n\n<template>\n <img v-if=\"safeSrc\" :src=\"safeSrc\" :alt=\"alt\" :style=\"style\" loading=\"lazy\" />\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbVideo',\n label: 'Vidéo',\n description: 'Affiche une vidéo avec URL, poster optionnel et options de lecture.',\n category: 'media',\n icon: '🎬',\n component: {} as any,\n slots: [],\n editableProps: [\n { key: 'src', label: 'URL de la vidéo', type: 'url', required: true },\n { key: 'poster', label: 'Image de couverture (poster)', type: 'image' },\n { key: 'width', label: 'Largeur', type: 'text', defaultValue: '100%' },\n { key: 'controls', label: 'Afficher les contrôles', type: 'boolean', defaultValue: true },\n { key: 'autoplay', label: 'Lecture automatique', type: 'boolean', defaultValue: false },\n { key: 'muted', label: 'Muet', type: 'boolean', defaultValue: false },\n { key: 'loop', label: 'Boucle', type: 'boolean', defaultValue: false },\n ],\n defaultProps: {\n src: '',\n poster: '',\n width: '100%',\n controls: true,\n autoplay: false,\n muted: false,\n loop: false,\n },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n\n const props = withDefaults(\n defineProps<{\n src: string;\n poster?: string;\n width?: string;\n controls?: boolean;\n autoplay?: boolean;\n muted?: boolean;\n loop?: boolean;\n }>(),\n {\n poster: '',\n width: '100%',\n controls: true,\n autoplay: false,\n muted: false,\n loop: false,\n },\n );\n\n const style = computed(() => ({\n width: props.width,\n maxWidth: '100%',\n display: 'block',\n }));\n\n const safeSrc = computed(() => sanitizeUrlByKind(props.src, 'media'));\n const safePoster = computed(() =>\n props.poster?.trim() ? sanitizeUrlByKind(props.poster, 'media') : undefined,\n );\n</script>\n\n<template>\n <video\n v-if=\"safeSrc\"\n :src=\"safeSrc\"\n :poster=\"safePoster\"\n :controls=\"controls\"\n :autoplay=\"autoplay\"\n :muted=\"muted\"\n :loop=\"loop\"\n :style=\"style\"\n playsinline\n />\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbSection',\n label: 'Section',\n description: 'A full-width section with optional background.',\n category: 'layout',\n icon: '▬',\n component: {} as any,\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'backgroundColor', label: 'Background Color', type: 'color', defaultValue: 'transparent' },\n { key: 'backgroundImage', label: 'Background Image', type: 'image' },\n { key: 'padding', label: 'Padding', type: 'text', defaultValue: '48px 24px' },\n { key: 'maxWidth', label: 'Max Content Width', type: 'text', defaultValue: '1200px' },\n ],\n defaultProps: { backgroundColor: 'transparent', padding: '48px 24px', maxWidth: '1200px' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n\n const props = defineProps({\n backgroundColor: { type: String, default: 'transparent' },\n backgroundImage: { type: String, default: '' },\n padding: { type: String, default: '48px 24px' },\n maxWidth: { type: String, default: '1200px' },\n });\n\n const safeBackgroundImage = computed(() => sanitizeUrlByKind(props.backgroundImage, 'background'));\n const cssBackgroundImage = computed(() => {\n if (!safeBackgroundImage.value) return undefined;\n const escapedUrl = safeBackgroundImage.value.replace(/[\"\\\\]/g, '\\\\$&');\n return `url(\"${escapedUrl}\")`;\n });\n\n const outerStyle = computed(() => ({\n width: '100%',\n backgroundColor: props.backgroundColor,\n backgroundImage: cssBackgroundImage.value,\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n padding: props.padding,\n }));\n\n const innerStyle = computed(() => ({\n maxWidth: props.maxWidth,\n margin: '0 auto',\n width: '100%',\n }));\n</script>\n\n<template>\n <section :style=\"outerStyle\">\n <div :style=\"innerStyle\">\n <slot />\n </div>\n </section>\n</template>\n","<script lang=\"ts\">\n import type { IComponentDefinition } from '@/types/component';\n\n export const builderOptions: IComponentDefinition = {\n name: 'PbContainer',\n label: 'Container',\n description: 'A centered container with max width.',\n category: 'layout',\n icon: '☐',\n component: {} as any,\n slots: [{ name: 'default', label: 'Content' }],\n editableProps: [\n { key: 'maxWidth', label: 'Max Width', type: 'text', defaultValue: '100%' },\n { key: 'padding', label: 'Padding', type: 'text', defaultValue: '0 24px' },\n ],\n defaultProps: { maxWidth: '100%', padding: '0 24px' },\n };\n</script>\n\n<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n maxWidth: { type: String, default: '100%' },\n padding: { type: String, default: '0 24px' },\n });\n\n const style = computed(() => ({\n maxWidth: props.maxWidth,\n margin: '0 auto',\n padding: props.padding,\n width: '100%',\n boxSizing: 'border-box' as const,\n }));\n</script>\n\n<template>\n <div :style=\"style\">\n <slot />\n </div>\n</template>\n","import type { IComponentDefinition } from '@/types/component';\n\nimport PbColumn, { builderOptions as pbColumnOptions } from './PbColumn.vue';\nimport PbRow, { builderOptions as pbRowOptions } from './PbRow.vue';\nimport PbText, { builderOptions as pbTextOptions } from './PbText.vue';\nimport PbImage, { builderOptions as pbImageOptions } from './PbImage.vue';\nimport PbVideo, { builderOptions as pbVideoOptions } from './PbVideo.vue';\nimport PbSection, { builderOptions as pbSectionOptions } from './PbSection.vue';\nimport PbContainer, { builderOptions as pbContainerOptions } from './PbContainer.vue';\n\nfunction withComponent(options: IComponentDefinition, component: any): IComponentDefinition {\n return { ...options, component };\n}\n\nexport const builtInComponents: IComponentDefinition[] = [\n withComponent(pbColumnOptions, PbColumn),\n withComponent(pbRowOptions, PbRow),\n withComponent(pbTextOptions, PbText),\n withComponent(pbImageOptions, PbImage),\n withComponent(pbVideoOptions, PbVideo),\n withComponent(pbSectionOptions, PbSection),\n withComponent(pbContainerOptions, PbContainer),\n];\n\nexport {\n PbColumn,\n PbRow,\n PbText,\n PbImage,\n PbVideo,\n PbSection,\n PbContainer,\n};\n","import type { TranslationDictionary } from './translator';\n\nexport const DEFAULT_LOCALE = 'en';\n\nexport const defaultTranslations: TranslationDictionary = {\n en: {\n 'toolbar.undo.title': 'Undo (Ctrl/Cmd+Z)',\n 'toolbar.undo.ariaLabel': 'Undo',\n 'toolbar.redo.title': 'Redo (Ctrl/Cmd+Y or Shift+Ctrl/Cmd+Z)',\n 'toolbar.redo.ariaLabel': 'Redo',\n 'toolbar.save': 'Save',\n 'toolbar.save.title': 'Save (Ctrl/Cmd+S)',\n 'toolbar.save.ariaLabel': 'Save page',\n 'toolbar.aria.toolbar': 'Editor toolbar',\n 'toolbar.aria.historyControls': 'History controls',\n 'toolbar.aria.viewportControls': 'Viewport controls',\n 'toolbar.aria.saveControls': 'Save controls',\n 'toolbar.aria.unsavedChanges': 'Unsaved changes',\n 'toolbar.viewport.desktop': 'Desktop',\n 'toolbar.viewport.tablet': 'Tablet',\n 'toolbar.viewport.mobile': 'Mobile',\n 'toolbar.viewport.custom': 'Custom',\n 'toolbar.viewport.switchAriaLabel': 'Switch viewport to {viewport}',\n 'toolbar.viewport.width.short': 'W',\n 'toolbar.viewport.height.short': 'H',\n 'toolbar.viewport.width.ariaLabel': 'Custom viewport width',\n 'toolbar.viewport.height.ariaLabel': 'Custom viewport height',\n 'leftDrawer.title': 'Components',\n 'leftDrawer.aria.componentPalette': 'Component palette',\n 'leftDrawer.toggle.ariaLabel': 'Toggle component drawer',\n 'leftDrawer.section.components': 'Components',\n 'leftDrawer.search.placeholder': 'Search components...',\n 'leftDrawer.search.ariaLabel': 'Search components',\n 'leftDrawer.category.ariaLabel': '{category} components',\n 'leftDrawer.component.dragAriaLabel': 'Add or drag {label}',\n 'leftDrawer.empty': 'No matching components',\n 'leftDrawer.section.tree': 'Tree',\n 'leftDrawer.tree.toggle.ariaLabel': 'Toggle node tree',\n 'rightDrawer.title': 'Properties',\n 'rightDrawer.aria.componentProperties': 'Component properties',\n 'rightDrawer.toggle.ariaLabel': 'Toggle properties drawer',\n 'rightDrawer.section.properties': 'Properties',\n 'rightDrawer.actions.duplicate': 'Duplicate',\n 'rightDrawer.actions.duplicate.ariaLabel': 'Duplicate selected component',\n 'rightDrawer.actions.delete': 'Delete',\n 'rightDrawer.actions.delete.ariaLabel': 'Delete selected component',\n 'rightDrawer.empty': 'Select a component to edit its properties.',\n 'treePanel.ariaLabel': 'Node tree',\n 'treePanel.readonly': 'readonly',\n 'contextMenu.ariaLabel': 'Node context menu',\n 'contextMenu.duplicate': 'Duplicate',\n 'contextMenu.moveUp': 'Move up',\n 'contextMenu.moveDown': 'Move down',\n 'contextMenu.delete': 'Delete',\n 'iframeCanvas.title': 'Editor canvas',\n 'propBoolean.enabled': 'Enabled',\n 'propBoolean.disabled': 'Disabled',\n 'propSelect.noOptions': 'No options',\n 'mediaPicker.input.placeholder': 'https://example.com/image.jpg',\n 'mediaPicker.clear': 'Clear',\n 'mediaPicker.upload': 'Upload',\n 'mediaPicker.preview.alt': 'Media preview',\n 'mediaPicker.empty': 'Paste an image URL to preview.',\n 'richText.action.link': 'Link',\n 'richText.action.bold': 'Bold',\n 'richText.action.italic': 'Italic',\n 'richText.action.unorderedList': 'Bulleted list',\n 'richText.action.orderedList': 'Numbered list',\n 'richText.aria.toolbar': 'Rich text formatting toolbar',\n 'richText.aria.editor': 'Rich text editor',\n 'richText.prompt.enterUrl': 'Enter URL',\n 'richText.prompt.defaultUrl': 'https://',\n 'pageBuilder.warning.invalidEditMode': 'Invalid `pageData` for edit mode. Rendering in read mode.',\n },\n};\n","export type TranslationParams = Record<string, string | number>;\nexport type TranslationDictionary = Record<string, Record<string, string>>;\nexport type Translator = (key: string, params?: TranslationParams) => string;\n\ninterface TranslateOptions {\n locale: string;\n dictionary: TranslationDictionary;\n key: string;\n params?: TranslationParams;\n fallbackLocale?: string;\n}\n\nfunction interpolate(message: string, params?: TranslationParams): string {\n if (!params) return message;\n\n return message.replace(/\\{(\\w+)\\}/g, (match, paramName: string) => {\n const value = params[paramName];\n return value === undefined ? match : String(value);\n });\n}\n\nexport function mergeTranslations(\n ...dictionaries: Array<TranslationDictionary | undefined | null>\n): TranslationDictionary {\n const merged: TranslationDictionary = {};\n\n for (const dictionary of dictionaries) {\n if (!dictionary) continue;\n\n for (const [locale, messages] of Object.entries(dictionary)) {\n merged[locale] = {\n ...(merged[locale] ?? {}),\n ...messages,\n };\n }\n }\n\n return merged;\n}\n\nexport function translate(options: TranslateOptions): string {\n const fallbackLocale = options.fallbackLocale ?? 'en';\n const localeMessages = options.dictionary[options.locale] ?? {};\n const fallbackMessages = options.dictionary[fallbackLocale] ?? {};\n const message = localeMessages[options.key] ?? fallbackMessages[options.key] ?? options.key;\n return interpolate(message, options.params);\n}\n\nexport function createTranslator(\n localeSource: string | (() => string),\n dictionarySource: TranslationDictionary | (() => TranslationDictionary),\n fallbackLocale = 'en',\n): Translator {\n const getLocale = typeof localeSource === 'function' ? localeSource : () => localeSource;\n const getDictionary = typeof dictionarySource === 'function' ? dictionarySource : () => dictionarySource;\n\n return (key, params) =>\n translate({\n locale: getLocale(),\n dictionary: getDictionary(),\n key,\n params,\n fallbackLocale,\n });\n}\n","import { computed, inject, type ComputedRef, type InjectionKey } from 'vue';\nimport { DEFAULT_LOCALE, defaultTranslations } from './messages';\nimport { createTranslator, type TranslationDictionary, type Translator } from './translator';\n\nexport interface PageBuilderI18nOptions {\n locale?: string;\n messages?: TranslationDictionary;\n}\n\nexport interface PageBuilderI18nContext {\n locale: ComputedRef<string>;\n t: Translator;\n}\n\nexport const PAGE_BUILDER_I18N_OPTIONS_KEY: InjectionKey<PageBuilderI18nOptions> = Symbol('pageBuilderI18nOptions');\nexport const PAGE_BUILDER_I18N_KEY: InjectionKey<PageBuilderI18nContext> = Symbol('pageBuilderI18n');\n\nconst fallbackI18nContext: PageBuilderI18nContext = {\n locale: computed(() => DEFAULT_LOCALE),\n t: createTranslator(DEFAULT_LOCALE, defaultTranslations),\n};\n\nexport function usePageBuilderI18n(): PageBuilderI18nContext {\n return inject(PAGE_BUILDER_I18N_KEY, fallbackI18nContext);\n}\n","<script setup lang=\"ts\">\n import { computed, onErrorCaptured, ref } from 'vue';\n import { createPageBuilderError, reportDevDiagnostic, toErrorMessage } from '@/core/errors';\n\n const props = withDefaults(\n defineProps<{\n fallbackMessage?: string;\n showDetailsInDev?: boolean;\n diagnosticContext?: string;\n }>(),\n {\n fallbackMessage: 'Something went wrong while rendering this section.',\n showDetailsInDev: false,\n diagnosticContext: 'ErrorBoundary',\n },\n );\n\n const hasError = ref(false);\n const capturedError = ref<unknown>(null);\n const errorInfo = ref('');\n\n const shouldShowDetails = computed(() => import.meta.env.DEV && props.showDetailsInDev);\n const errorDetails = computed(() => {\n if (!capturedError.value) return '';\n if (capturedError.value instanceof Error) return capturedError.value.message;\n return String(capturedError.value);\n });\n const errorDebugText = computed(() =>\n [errorDetails.value, errorInfo.value].filter((segment) => Boolean(segment)).join('\\n'),\n );\n\n onErrorCaptured((error, _instance, info) => {\n hasError.value = true;\n capturedError.value = error;\n errorInfo.value = info;\n\n reportDevDiagnostic(\n props.diagnosticContext,\n createPageBuilderError(\n 'RENDER_FAILURE',\n `[PageBuilder] ${props.diagnosticContext} captured a render error: ${toErrorMessage(error)}`,\n {\n cause: error,\n details: {\n info,\n },\n },\n ),\n );\n\n return false;\n });\n</script>\n\n<template>\n <slot v-if=\"!hasError\" />\n <div v-else class=\"ipb-error-boundary\" role=\"alert\">\n <p class=\"ipb-error-boundary__message\">\n {{ fallbackMessage }}\n </p>\n\n <pre v-if=\"shouldShowDetails && errorDebugText\" class=\"ipb-error-boundary__details\">\n {{ errorDebugText }}\n </pre>\n </div>\n</template>\n\n<style scoped>\n .ipb-error-boundary {\n width: 100%;\n padding: 0.75rem;\n border: 1px solid #f3d1d1;\n border-radius: 0.375rem;\n background-color: #fff5f5;\n color: #7a1f1f;\n }\n\n .ipb-error-boundary__message {\n margin: 0;\n font-size: 0.9rem;\n line-height: 1.4;\n }\n\n .ipb-error-boundary__details {\n margin: 0.5rem 0 0;\n font-size: 0.75rem;\n line-height: 1.4;\n white-space: pre-wrap;\n word-break: break-word;\n color: #5f1b1b;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, defineComponent, type PropType } from 'vue';\n import type { INode } from '@/types/node';\n import { resolveComponent } from '@/core/registry';\n import { interpolateProps } from '@/core/tree';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import ErrorBoundary from '@/components/shared/ErrorBoundary.vue';\n\n const props = defineProps({\n node: {\n type: Object as PropType<INode>,\n required: true,\n },\n variables: {\n type: Object as PropType<Record<string, string>>,\n default: () => ({}),\n },\n markNodes: {\n type: Boolean,\n default: false,\n },\n });\n\n const reportedDiagnostics = new Set<string>();\n\n function reportOnce(key: string, message: string, details?: Record<string, unknown>) {\n if (reportedDiagnostics.has(key)) return;\n reportedDiagnostics.add(key);\n reportDevDiagnostic('NodeRenderer', createPageBuilderError('RENDER_FAILURE', message, { details }));\n }\n\n function isNodeObject(value: unknown): value is INode {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const maybeNode = value as Partial<INode>;\n if (typeof maybeNode.id !== 'number' || !Number.isFinite(maybeNode.id)) return false;\n if (typeof maybeNode.name !== 'string' || maybeNode.name.trim().length === 0) return false;\n if (!(maybeNode.slot === null || typeof maybeNode.slot === 'string')) return false;\n if (\n typeof maybeNode.props !== 'object' ||\n maybeNode.props === null ||\n Array.isArray(maybeNode.props)\n ) {\n return false;\n }\n return Array.isArray(maybeNode.children);\n }\n\n function sanitizeVariables(rawVariables: unknown): Record<string, string> {\n if (!rawVariables || typeof rawVariables !== 'object' || Array.isArray(rawVariables)) {\n return {};\n }\n\n return Object.fromEntries(\n Object.entries(rawVariables).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n }\n\n const safeNode = computed<INode | null>(() => {\n if (isNodeObject(props.node)) return props.node;\n reportOnce('invalid-node', '[PageBuilder] NodeRenderer received an invalid node payload.', {\n node: props.node,\n });\n return null;\n });\n\n const safeVariables = computed<Record<string, string>>(() => sanitizeVariables(props.variables));\n\n const NodeRenderCrash = defineComponent({\n name: 'NodeRenderCrash',\n props: {\n error: {\n type: null as unknown as PropType<unknown>,\n required: true,\n },\n },\n setup(localProps) {\n return () => {\n const reason =\n localProps.error instanceof Error ? localProps.error : new Error(String(localProps.error));\n throw reason;\n };\n },\n });\n\n const resolutionResult = computed(() => {\n if (!safeNode.value) {\n return {\n component: NodeRenderCrash,\n error: createPageBuilderError(\n 'INVALID_NODE',\n '[PageBuilder] Cannot render node because its payload is invalid.',\n ),\n };\n }\n\n try {\n return { component: resolveComponent(safeNode.value.name), error: null as unknown };\n } catch (error) {\n reportOnce(\n `missing-component:${safeNode.value.name}`,\n `[PageBuilder] Component \"${safeNode.value.name}\" could not be resolved.`,\n { nodeId: safeNode.value.id },\n );\n return { component: NodeRenderCrash, error };\n }\n });\n\n const resolvedComponent = computed(() => resolutionResult.value.component);\n const resolvedProps = computed(() => {\n if (resolutionResult.value.error !== null) {\n return { error: resolutionResult.value.error };\n }\n\n if (!safeNode.value) {\n return {\n error: createPageBuilderError(\n 'INVALID_NODE',\n '[PageBuilder] Cannot render props for an invalid node payload.',\n ),\n };\n }\n\n try {\n return interpolateProps(safeNode.value.props, safeVariables.value);\n } catch (error) {\n reportOnce(\n `prop-interpolation:${safeNode.value.id}`,\n `[PageBuilder] Failed to interpolate props for node \"${safeNode.value.name}\".`,\n { nodeId: safeNode.value.id },\n );\n return { error };\n }\n });\n const markerAttrs = computed(() => {\n if (!props.markNodes || !safeNode.value) return {};\n return {\n 'data-ipb-node-id': String(safeNode.value.id),\n 'data-ipb-component': safeNode.value.name,\n ...(safeNode.value.readonly ? { 'data-ipb-readonly': 'true' } : {}),\n };\n });\n const renderedAttrs = computed(() => ({\n ...resolvedProps.value,\n ...markerAttrs.value,\n }));\n\n const slotGroups = computed(() => {\n const groups: Record<string, INode[]> = {};\n if (!safeNode.value) return groups;\n\n for (const child of safeNode.value.children) {\n if (!isNodeObject(child)) {\n reportOnce(\n `invalid-child:${safeNode.value.id}`,\n `[PageBuilder] Ignoring invalid child node while rendering \"${safeNode.value.name}\".`,\n { parentNodeId: safeNode.value.id },\n );\n continue;\n }\n const slotName = child.slot ?? 'default';\n if (!groups[slotName]) groups[slotName] = [];\n groups[slotName].push(child);\n }\n return groups;\n });\n</script>\n\n<template>\n <div v-if=\"!safeNode\" class=\"ipb-node-renderer__invalid\" role=\"alert\">\n This block is invalid and could not be rendered.\n </div>\n <ErrorBoundary\n v-else\n fallback-message=\"This block could not be rendered.\"\n :show-details-in-dev=\"true\"\n diagnostic-context=\"NodeRenderer\"\n >\n <component :is=\"resolvedComponent\" v-bind=\"renderedAttrs\">\n <template v-for=\"(children, slotName) in slotGroups\" :key=\"slotName\" #[slotName]>\n <NodeRenderer\n v-for=\"child in children\"\n :key=\"child.id\"\n :node=\"child\"\n :variables=\"safeVariables\"\n :mark-nodes=\"markNodes\"\n />\n </template>\n </component>\n </ErrorBoundary>\n</template>\n\n<style scoped>\n .ipb-node-renderer__invalid {\n width: 100%;\n padding: 0.75rem;\n border: 1px solid #f3d1d1;\n border-radius: 0.375rem;\n background-color: #fff5f5;\n color: #7a1f1f;\n font-size: 0.825rem;\n line-height: 1.35;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, type PropType, watch } from 'vue';\n import type { IPageData, INode } from '@/types/node';\n import { validateNode, validatePageData } from '@/core/validation';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import NodeRenderer from './NodeRenderer.vue';\n import ErrorBoundary from '@/components/shared/ErrorBoundary.vue';\n\n const props = defineProps({\n pageData: {\n type: Object as PropType<IPageData>,\n required: true,\n },\n });\n\n const pageValidationResult = computed(() => validatePageData(props.pageData));\n const contentValidationResult = computed(() => validateNode(props.pageData.content, 'content'));\n const layoutValidationResult = computed(() => validateNode(props.pageData.layout, 'layout'));\n const reportedDiagnostics = new Set<string>();\n\n function reportOnce(key: string, message: string, details?: Record<string, unknown>) {\n if (reportedDiagnostics.has(key)) return;\n reportedDiagnostics.add(key);\n reportDevDiagnostic('PageReader', createPageBuilderError('INVALID_PAGE_DATA', message, { details }));\n }\n\n watch(\n pageValidationResult,\n (result) => {\n if (result.isValid) return;\n reportOnce(\n 'invalid-page-data',\n '[PageReader] Invalid pageData payload detected. Rendering continues with degraded behavior.',\n { errors: result.errors },\n );\n },\n { immediate: true },\n );\n\n function isNodeObject(value: unknown): value is INode {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n }\n\n const safeVariables = computed<Record<string, string>>(() => {\n const rawVariables = props.pageData.variables;\n if (!rawVariables || typeof rawVariables !== 'object' || Array.isArray(rawVariables)) {\n reportOnce(\n 'invalid-variables-shape',\n '[PageReader] Invalid variables payload. Falling back to an empty variable map.',\n );\n return {};\n }\n\n const hasInvalidEntries = Object.values(rawVariables).some((value) => typeof value !== 'string');\n if (hasInvalidEntries) {\n reportOnce(\n 'invalid-variables-values',\n '[PageReader] Variables payload contains non-string values. Invalid entries were ignored.',\n );\n }\n\n return Object.fromEntries(\n Object.entries(rawVariables).filter((entry): entry is [string, string] => typeof entry[1] === 'string'),\n );\n });\n\n const readerRoot = computed<INode | null>(() => {\n if (!isNodeObject(props.pageData.content) || !contentValidationResult.value.isValid) {\n reportOnce(\n 'invalid-content',\n '[PageReader] Invalid content node. Nothing can be rendered.',\n { errors: contentValidationResult.value.errors },\n );\n return null;\n }\n\n // Backward-compatible fallback for legacy payloads that don't include layout.\n if (!isNodeObject(props.pageData.layout) || !layoutValidationResult.value.isValid) {\n reportOnce(\n 'invalid-layout',\n '[PageReader] Invalid layout node. Falling back to content-only rendering.',\n { errors: layoutValidationResult.value.errors },\n );\n return props.pageData.content;\n }\n\n const contentRoot: INode = {\n ...props.pageData.content,\n slot: props.pageData.content.slot ?? 'default',\n };\n\n const layoutChildren = Array.isArray(props.pageData.layout.children)\n ? props.pageData.layout.children\n : [];\n\n return {\n ...props.pageData.layout,\n children: [...layoutChildren, contentRoot],\n };\n });\n</script>\n\n<template>\n <div class=\"ipb-page-reader\">\n <ErrorBoundary\n v-if=\"readerRoot\"\n fallback-message=\"This page could not be fully rendered.\"\n :show-details-in-dev=\"true\"\n diagnostic-context=\"PageReader\"\n >\n <NodeRenderer :node=\"readerRoot\" :variables=\"safeVariables\" />\n </ErrorBoundary>\n <div v-else class=\"ipb-page-reader__invalid\" role=\"alert\">\n This page data is invalid and cannot be rendered safely.\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-page-reader {\n width: 100%;\n min-height: 100%;\n }\n\n .ipb-page-reader__invalid {\n padding: 0.75rem;\n border: 1px solid #f3d1d1;\n border-radius: 0.375rem;\n background-color: #fff5f5;\n color: #7a1f1f;\n font-size: 0.875rem;\n }\n</style>\n","import type { INode, IPageSavePayload } from './node';\n\n/** Operating mode for the page builder. */\nexport type PageBuilderMode = 'read' | 'edit';\n\n/**\n * Editor UI state managed by the useEditor composable.\n * Drag-and-drop state is managed separately by useDragDrop.\n */\nexport interface IEditorState {\n /** Currently selected node, or null. */\n selectedNodeId: number | null;\n\n /** Currently hovered node, or null. */\n hoveredNodeId: number | null;\n\n /** Whether the left drawer (component palette) is open. */\n leftDrawerOpen: boolean;\n\n /** Whether the right drawer (property editor) is open. */\n rightDrawerOpen: boolean;\n\n /** Undo/redo history stack. */\n history: IEditorHistoryEntry[];\n\n /** Current position in the history stack. */\n historyIndex: number;\n\n /** Dirty flag — true if unsaved changes exist. */\n isDirty: boolean;\n\n /** Viewport scale for the canvas iframe. */\n canvasScale: number;\n\n /** Viewport preset. */\n viewport: ViewportPreset;\n}\n\nexport interface IEditorHistoryEntry {\n timestamp: number;\n label: string;\n snapshot: string;\n}\n\nexport type ViewportPreset = 'desktop' | 'tablet' | 'mobile' | 'custom';\n\nexport interface IViewportDimensions {\n width: number;\n height: number;\n label: string;\n}\n\nexport interface IViewportSize {\n width: number;\n height: number;\n}\n\nexport const VIEWPORT_PRESETS: Record<ViewportPreset, IViewportDimensions> = {\n desktop: { width: 1440, height: 900, label: 'Desktop' },\n tablet: { width: 768, height: 1024, label: 'Tablet' },\n mobile: { width: 375, height: 812, label: 'Mobile' },\n custom: { width: 0, height: 0, label: 'Custom' },\n};\n\n/**\n * Events emitted by the page builder in edit mode.\n */\nexport interface IPageBuilderEvents {\n /** Emitted when the user saves (Ctrl+S or save button). */\n save: [payload: IPageSavePayload];\n\n /** Emitted when the tree structure changes. */\n change: [tree: INode];\n\n /** Emitted when a node is selected. */\n select: [nodeId: number | null];\n}\n","import type { InjectionKey } from 'vue';\nimport type { UsePageBuilderReturn } from '@/composables/use-page-builder';\nimport type { useEditor } from '@/composables/use-editor';\nimport type { useNodeTree } from '@/composables/use-node-tree';\nimport type { useDragDrop } from '@/composables/use-drag-drop';\n\n/**\n * Typed injection keys for provide/inject across the editor component tree.\n * Use these instead of raw strings for type-safe inject() calls.\n */\nexport const PAGE_BUILDER_KEY: InjectionKey<UsePageBuilderReturn> = Symbol('pageBuilder');\nexport const EDITOR_KEY: InjectionKey<ReturnType<typeof useEditor>> = Symbol('editor');\nexport const NODE_TREE_KEY: InjectionKey<ReturnType<typeof useNodeTree>> = Symbol('nodeTree');\nexport const DRAG_DROP_KEY: InjectionKey<ReturnType<typeof useDragDrop>> = Symbol('dragDrop');\n","import { ref, computed, type Ref, type ComputedRef } from 'vue';\nimport type { IPageData, INode } from '@/types/node';\nimport type { PageBuilderMode } from '@/types/editor';\nimport { getMaxId } from '@/core/tree';\nimport {\n createPageBuilderError,\n reportDevDiagnostic,\n toErrorMessage,\n} from '@/core/errors';\n\nexport interface UsePageBuilderOptions {\n initialData: IPageData;\n mode?: PageBuilderMode;\n}\n\nexport interface UsePageBuilderReturn {\n mode: Ref<PageBuilderMode>;\n pageData: ComputedRef<IPageData>;\n content: Ref<INode>;\n layout: Ref<INode>;\n maxId: Ref<number>;\n variables: Ref<Record<string, string>>;\n isDirty: Ref<boolean>;\n\n setMode: (newMode: PageBuilderMode) => void;\n updateContent: (newContent: INode) => void;\n updateLayout: (newLayout: INode) => void;\n nextId: () => number;\n getSnapshot: () => string;\n restoreSnapshot: (snapshot: string) => void;\n reset: () => void;\n}\n\ninterface SnapshotShape {\n content: INode;\n layout: INode;\n maxId: number;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isPositiveInteger(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0;\n}\n\nfunction createFallbackNode(id: number, name: string, slot: string | null): INode {\n return {\n id,\n name,\n slot,\n props: {},\n children: [],\n };\n}\n\nfunction isNode(value: unknown, visited = new WeakSet<object>()): value is INode {\n if (!isPlainObject(value)) return false;\n if (visited.has(value)) return false;\n visited.add(value);\n\n if (!isPositiveInteger(value.id)) return false;\n if (typeof value.name !== 'string' || value.name.trim().length === 0) return false;\n if (!(value.slot === null || typeof value.slot === 'string')) return false;\n if (!isPlainObject(value.props)) return false;\n if (!Array.isArray(value.children)) return false;\n if (typeof value.readonly !== 'undefined' && typeof value.readonly !== 'boolean') return false;\n\n return value.children.every((child) => isNode(child, visited));\n}\n\nfunction sanitizeVariables(value: unknown): Record<string, string> {\n if (!isPlainObject(value)) return {};\n const result: Record<string, string> = {};\n for (const [key, variableValue] of Object.entries(value)) {\n if (typeof variableValue === 'string') {\n result[key] = variableValue;\n }\n }\n return result;\n}\n\nfunction sanitizeInitialData(initialData: IPageData): IPageData {\n const issues: string[] = [];\n const fallbackContent = createFallbackNode(1, 'PbSection', null);\n const fallbackLayout = createFallbackNode(100, 'PbContainer', null);\n const source = isPlainObject(initialData) ? initialData : ({} as Record<string, unknown>);\n\n let content = fallbackContent;\n if (isNode(source.content)) {\n content = structuredClone(source.content);\n } else {\n issues.push('content node is invalid');\n }\n\n let layout = fallbackLayout;\n if (isNode(source.layout)) {\n layout = structuredClone(source.layout);\n } else {\n issues.push('layout node is invalid');\n }\n\n const rawMaxId = source.maxId;\n const computedMaxId = Math.max(getMaxId(content), getMaxId(layout));\n const hasValidMaxId = isNonNegativeInteger(rawMaxId);\n const maxId = hasValidMaxId ? Math.max(Math.trunc(rawMaxId), computedMaxId) : computedMaxId;\n\n if (!hasValidMaxId) {\n issues.push('maxId is invalid');\n }\n\n const variables = sanitizeVariables(source.variables);\n if (!isPlainObject(source.variables)) {\n issues.push('variables map is invalid');\n }\n\n const meta = isPlainObject(source.meta) ? source.meta : {};\n if (!isPlainObject(source.meta)) {\n issues.push('meta object is invalid');\n }\n\n const pageData: IPageData = {\n meta: {\n id: typeof meta.id === 'string' ? meta.id : 'unknown-page',\n name: typeof meta.name === 'string' ? meta.name : 'Untitled page',\n url: typeof meta.url === 'string' ? meta.url : '/',\n status:\n meta.status === 'draft' || meta.status === 'published' || meta.status === 'archived'\n ? meta.status\n : 'draft',\n updatedAt: typeof meta.updatedAt === 'string' ? meta.updatedAt : undefined,\n createdAt: typeof meta.createdAt === 'string' ? meta.createdAt : undefined,\n },\n content,\n layout,\n maxId,\n variables,\n };\n\n if (issues.length > 0) {\n reportDevDiagnostic(\n 'usePageBuilder.sanitizeInitialData',\n createPageBuilderError(\n 'INVALID_PAGE_DATA',\n `[PageBuilder] Invalid page data detected. Falling back to safe defaults for: ${issues.join(', ')}.`,\n ),\n { issues },\n );\n }\n\n return pageData;\n}\n\nfunction parseSnapshot(snapshot: string): SnapshotShape {\n let parsed: unknown;\n try {\n parsed = JSON.parse(snapshot);\n } catch (error) {\n throw createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Snapshot JSON is invalid.',\n {\n cause: error,\n details: {\n snapshotPreview: snapshot.slice(0, 200),\n },\n },\n );\n }\n\n if (!isPlainObject(parsed) || !isNode(parsed.content) || !isNode(parsed.layout) || !isNonNegativeInteger(parsed.maxId)) {\n throw createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Snapshot payload shape is invalid.',\n {\n details: {\n contentValid: isPlainObject(parsed) ? isNode(parsed.content) : false,\n layoutValid: isPlainObject(parsed) ? isNode(parsed.layout) : false,\n maxIdValid: isPlainObject(parsed) ? isNonNegativeInteger(parsed.maxId) : false,\n },\n },\n );\n }\n\n const normalizedMaxId = Math.max(\n Math.trunc(parsed.maxId),\n getMaxId(parsed.content),\n getMaxId(parsed.layout),\n );\n\n return {\n content: parsed.content,\n layout: parsed.layout,\n maxId: normalizedMaxId,\n };\n}\n\n/**\n * Main composable for managing page builder state.\n * Used internally by the PageBuilder component.\n */\nexport function usePageBuilder(options: UsePageBuilderOptions): UsePageBuilderReturn {\n const { initialData, mode: initialMode = 'read' } = options;\n\n const _initial = sanitizeInitialData(initialData);\n const mode = ref<PageBuilderMode>(initialMode);\n const meta = ref(_initial.meta);\n const content = ref<INode>(_initial.content);\n const layout = ref<INode>(_initial.layout);\n const maxId = ref(_initial.maxId);\n const variables = ref<Record<string, string>>(_initial.variables);\n const isDirty = ref(false);\n\n const pageData = computed<IPageData>(() => ({\n meta: meta.value,\n content: content.value,\n layout: layout.value,\n maxId: maxId.value,\n variables: variables.value,\n }));\n\n const _initialDirtySnapshot = _serializeDirtyState({\n content: _initial.content,\n layout: _initial.layout,\n });\n\n function _serializeSnapshot(snapshot: Pick<IPageData, 'content' | 'layout' | 'maxId'>): string {\n return JSON.stringify(snapshot);\n }\n\n function _serializeDirtyState(state: Pick<IPageData, 'content' | 'layout'>): string {\n return JSON.stringify(state);\n }\n\n function _syncDirtyFromCurrentState() {\n isDirty.value = _serializeDirtyState({\n content: content.value,\n layout: layout.value,\n }) !== _initialDirtySnapshot;\n }\n\n function setMode(newMode: PageBuilderMode) {\n mode.value = newMode;\n }\n\n function updateContent(newContent: INode) {\n content.value = newContent;\n maxId.value = Math.max(maxId.value, getMaxId(newContent));\n _syncDirtyFromCurrentState();\n }\n\n function updateLayout(newLayout: INode) {\n layout.value = newLayout;\n maxId.value = Math.max(maxId.value, getMaxId(newLayout));\n _syncDirtyFromCurrentState();\n }\n\n function nextId(): number {\n maxId.value++;\n return maxId.value;\n }\n\n function getSnapshot(): string {\n return _serializeSnapshot({\n content: content.value,\n layout: layout.value,\n maxId: maxId.value,\n });\n }\n\n function restoreSnapshot(snapshot: string) {\n try {\n const parsed = parseSnapshot(snapshot);\n content.value = parsed.content;\n layout.value = parsed.layout;\n maxId.value = parsed.maxId;\n _syncDirtyFromCurrentState();\n } catch (error) {\n throw createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Unable to restore snapshot.',\n {\n cause: error,\n details: {\n reason: toErrorMessage(error),\n },\n },\n );\n }\n }\n\n function reset() {\n const original = parseSnapshot(\n JSON.stringify({\n content: _initial.content,\n layout: _initial.layout,\n maxId: _initial.maxId,\n }),\n );\n content.value = structuredClone(original.content);\n layout.value = structuredClone(original.layout);\n maxId.value = original.maxId;\n variables.value = structuredClone(_initial.variables);\n isDirty.value = false;\n }\n\n return {\n mode,\n pageData,\n content,\n layout,\n maxId,\n variables,\n isDirty,\n setMode,\n updateContent,\n updateLayout,\n nextId,\n getSnapshot,\n restoreSnapshot,\n reset,\n };\n}\n","import { reactive, computed, toRefs } from 'vue';\nimport type { ViewportPreset } from '@/types/editor';\n\ninterface UseEditorOptions {\n initialSnapshot?: string;\n initialLabel?: string;\n}\n\ninterface EditorUIState {\n selectedNodeId: number | null;\n hoveredNodeId: number | null;\n leftDrawerOpen: boolean;\n rightDrawerOpen: boolean;\n history: { timestamp: number; label: string; snapshot: string }[];\n historyIndex: number;\n isDirty: boolean;\n canvasScale: number;\n viewport: ViewportPreset;\n}\n\n/**\n * Composable managing the editor UI state (selection, drawers, history, viewport).\n * Drag-and-drop state is handled separately by useDragDrop.\n */\nexport function useEditor(options: UseEditorOptions = {}) {\n const { initialSnapshot, initialLabel = 'Initial state' } = options;\n const initialHistory = initialSnapshot\n ? [{ timestamp: Date.now(), label: initialLabel, snapshot: initialSnapshot }]\n : [];\n let baselineSnapshot: string | null = initialSnapshot ?? null;\n\n const state = reactive<EditorUIState>({\n selectedNodeId: null,\n hoveredNodeId: null,\n leftDrawerOpen: true,\n rightDrawerOpen: false,\n history: initialHistory,\n historyIndex: initialHistory.length > 0 ? 0 : -1,\n isDirty: false,\n canvasScale: 1,\n viewport: 'desktop',\n });\n\n const canUndo = computed(() => state.historyIndex > 0);\n const canRedo = computed(() => state.historyIndex < state.history.length - 1);\n\n function selectNode(id: number | null) {\n state.selectedNodeId = id;\n if (id !== null) {\n state.rightDrawerOpen = true;\n }\n }\n\n function hoverNode(id: number | null) {\n state.hoveredNodeId = id;\n }\n\n function toggleLeftDrawer() {\n state.leftDrawerOpen = !state.leftDrawerOpen;\n }\n\n function toggleRightDrawer() {\n state.rightDrawerOpen = !state.rightDrawerOpen;\n }\n\n function setViewport(preset: ViewportPreset) {\n state.viewport = preset;\n }\n\n function syncDirtyWithHistory() {\n if (baselineSnapshot === null || state.historyIndex < 0) {\n state.isDirty = false;\n return;\n }\n const currentSnapshot = state.history[state.historyIndex]?.snapshot;\n state.isDirty = currentSnapshot !== baselineSnapshot;\n }\n\n function setHistoryBaseline(snapshot: string, label = initialLabel) {\n baselineSnapshot = snapshot;\n state.history = [{ timestamp: Date.now(), label, snapshot }];\n state.historyIndex = 0;\n state.isDirty = false;\n }\n\n function pushHistory(label: string, snapshot: string) {\n if (baselineSnapshot === null) {\n setHistoryBaseline(snapshot);\n return;\n }\n\n const currentSnapshot = state.history[state.historyIndex]?.snapshot;\n if (currentSnapshot === snapshot) return;\n\n if (state.historyIndex < state.history.length - 1) {\n state.history.splice(state.historyIndex + 1);\n }\n state.history.push({\n timestamp: Date.now(),\n label,\n snapshot,\n });\n state.historyIndex = state.history.length - 1;\n syncDirtyWithHistory();\n }\n\n function undo(): string | undefined {\n if (!canUndo.value) return undefined;\n state.historyIndex--;\n syncDirtyWithHistory();\n return state.history[state.historyIndex]?.snapshot;\n }\n\n function redo(): string | undefined {\n if (!canRedo.value) return undefined;\n state.historyIndex++;\n syncDirtyWithHistory();\n return state.history[state.historyIndex]?.snapshot;\n }\n\n return {\n ...toRefs(state),\n canUndo,\n canRedo,\n selectNode,\n hoverNode,\n toggleLeftDrawer,\n toggleRightDrawer,\n setViewport,\n setHistoryBaseline,\n pushHistory,\n undo,\n redo,\n };\n}\n","import type { Ref } from 'vue';\nimport { toRaw } from 'vue';\nimport type { INode } from '@/types/node';\nimport {\n cloneTree,\n findNodeById,\n findParent,\n removeNode,\n insertNode,\n moveNode,\n createNode,\n} from '@/core/tree';\n\nexport interface UseNodeTreeOptions {\n content: Ref<INode>;\n nextId: () => number;\n onUpdate: (newContent: INode) => void;\n onSnapshot?: (label: string) => void;\n}\n\n/**\n * Composable for manipulating the node tree (add, remove, move, update props).\n * All mutations clone before modifying to preserve immutability for history.\n */\nexport function useNodeTree({ content, nextId, onUpdate, onSnapshot }: UseNodeTreeOptions) {\n function _mutate(label: string, mutator: (tree: INode) => boolean | void): boolean {\n // `content.value` may be a Vue proxy; clone the raw node tree.\n const currentTree = toRaw(content.value);\n const currentSnapshot = JSON.stringify(currentTree);\n const cloned = cloneTree(currentTree);\n const shouldCommit = mutator(cloned);\n if (shouldCommit === false) return false;\n if (JSON.stringify(cloned) === currentSnapshot) return false;\n onUpdate(cloned);\n onSnapshot?.(label);\n return true;\n }\n\n function addNode(\n parentId: number,\n componentName: string,\n index: number,\n slot = 'default',\n defaultProps?: Record<string, unknown>,\n ): number | null {\n let createdNodeId: number | null = null;\n const didInsert = _mutate(`Add ${componentName}`, (tree) => {\n const parentNode = findNodeById(tree, parentId);\n if (!parentNode) return false;\n\n createdNodeId = nextId();\n const node = createNode(createdNodeId, componentName, { slot, props: defaultProps });\n return insertNode(tree, parentId, node, index, slot);\n });\n\n if (!didInsert || createdNodeId === null) return null;\n return createdNodeId;\n }\n\n function deleteNode(nodeId: number) {\n _mutate('Delete node', (tree) => {\n removeNode(tree, nodeId);\n });\n }\n\n function moveNodeTo(nodeId: number, newParentId: number, index: number, slot = 'default') {\n _mutate('Move node', (tree) => {\n return moveNode(tree, nodeId, newParentId, index, slot);\n });\n }\n\n function updateNodeProps(nodeId: number, props: Record<string, unknown>) {\n _mutate('Update props', (tree) => {\n const node = findNodeById(tree, nodeId);\n if (node) {\n node.props = { ...node.props, ...props };\n }\n });\n }\n\n function duplicateNode(nodeId: number) {\n _mutate('Duplicate node', (tree) => {\n const original = findNodeById(tree, nodeId);\n if (!original) return;\n\n const parentResult = findParent(tree, nodeId);\n if (!parentResult) return;\n\n const cloned = _deepCloneWithNewIds(original);\n parentResult.parent.children.splice(parentResult.index + 1, 0, cloned);\n });\n }\n\n function canMoveNodeUp(nodeId: number): boolean {\n const node = findNodeById(content.value, nodeId);\n if (!node || node.readonly) return false;\n const parentResult = findParent(content.value, nodeId);\n if (!parentResult) return false;\n return parentResult.index > 0;\n }\n\n function canMoveNodeDown(nodeId: number): boolean {\n const node = findNodeById(content.value, nodeId);\n if (!node || node.readonly) return false;\n const parentResult = findParent(content.value, nodeId);\n if (!parentResult) return false;\n return parentResult.index < parentResult.parent.children.length - 1;\n }\n\n function moveNodeUp(nodeId: number) {\n if (!canMoveNodeUp(nodeId)) return;\n _mutate('Move node up', (tree) => {\n const parentResult = findParent(tree, nodeId);\n if (!parentResult || parentResult.index <= 0) return;\n const [node] = parentResult.parent.children.splice(parentResult.index, 1);\n parentResult.parent.children.splice(parentResult.index - 1, 0, node);\n });\n }\n\n function moveNodeDown(nodeId: number) {\n if (!canMoveNodeDown(nodeId)) return;\n _mutate('Move node down', (tree) => {\n const parentResult = findParent(tree, nodeId);\n if (!parentResult || parentResult.index >= parentResult.parent.children.length - 1) return;\n const [node] = parentResult.parent.children.splice(parentResult.index, 1);\n parentResult.parent.children.splice(parentResult.index + 1, 0, node);\n });\n }\n\n function _deepCloneWithNewIds(node: INode): INode {\n return {\n ...node,\n id: nextId(),\n props: { ...node.props },\n children: node.children.map((child) => _deepCloneWithNewIds(child)),\n };\n }\n\n return {\n addNode,\n deleteNode,\n moveNodeTo,\n updateNodeProps,\n duplicateNode,\n canMoveNodeUp,\n canMoveNodeDown,\n moveNodeUp,\n moveNodeDown,\n };\n}\n","import { ref, type Ref } from 'vue';\n\nexport interface DragState {\n isDragging: boolean;\n sourceNodeId: number | null;\n sourceComponentName: string | null;\n isNewComponent: boolean;\n dropTargetId: number | null;\n dropIndex: number;\n dropSlot: string;\n}\n\nexport interface DragDropApi {\n dragState: Ref<DragState>;\n startDragExisting: (nodeId: number) => void;\n startDragNew: (componentName: string) => void;\n updateDropTarget: (targetId: number, index: number, slot?: string) => void;\n endDrag: () => DragState;\n cancelDrag: () => void;\n}\n\nconst DEFAULT_DROP_SLOT = 'default';\n\nfunction createInitialDragState(): DragState {\n return {\n isDragging: false,\n sourceNodeId: null,\n sourceComponentName: null,\n isNewComponent: false,\n dropTargetId: null,\n dropIndex: 0,\n dropSlot: DEFAULT_DROP_SLOT,\n };\n}\n\n/**\n * Composable for drag-and-drop interactions in the editor.\n * Handles both dragging existing nodes and new components from the palette.\n */\nexport function useDragDrop(): DragDropApi {\n const state = ref<DragState>(createInitialDragState());\n\n function resetDragState() {\n state.value = createInitialDragState();\n }\n\n function startDragExisting(nodeId: number) {\n state.value = {\n ...createInitialDragState(),\n isDragging: true,\n sourceNodeId: nodeId,\n };\n }\n\n function startDragNew(componentName: string) {\n state.value = {\n ...createInitialDragState(),\n isDragging: true,\n sourceComponentName: componentName,\n isNewComponent: true,\n };\n }\n\n function updateDropTarget(targetId: number, index: number, slot = DEFAULT_DROP_SLOT) {\n if (!state.value.isDragging) return;\n state.value.dropTargetId = targetId;\n state.value.dropIndex = index;\n state.value.dropSlot = slot;\n }\n\n function endDrag() {\n const result = { ...state.value };\n resetDragState();\n return result;\n }\n\n function cancelDrag() {\n resetDragState();\n }\n\n return {\n dragState: state,\n startDragExisting,\n startDragNew,\n updateDropTarget,\n endDrag,\n cancelDrag,\n };\n}\n","<script setup lang=\"ts\">\n import { nextTick, ref, type ComponentPublicInstance, type PropType } from 'vue';\n import type { ViewportPreset } from '@/types/editor';\n import { VIEWPORT_PRESETS } from '@/types/editor';\n import { usePageBuilderI18n } from '@/i18n';\n\n const MIN_VIEWPORT_WIDTH = 240;\n const MIN_VIEWPORT_HEIGHT = 320;\n const MAX_VIEWPORT_WIDTH = 3840;\n const MAX_VIEWPORT_HEIGHT = 4320;\n\n const props = defineProps({\n canUndo: { type: Boolean, default: false },\n canRedo: { type: Boolean, default: false },\n isDirty: { type: Boolean, default: false },\n viewport: { type: String as PropType<ViewportPreset>, default: 'desktop' },\n customViewportWidth: { type: Number, default: 1024 },\n customViewportHeight: { type: Number, default: 768 },\n activeViewportWidth: { type: Number as PropType<number | null>, default: null },\n activeViewportHeight: { type: Number as PropType<number | null>, default: null },\n });\n\n const emit = defineEmits<{\n undo: [];\n redo: [];\n save: [];\n 'viewport-change': [preset: ViewportPreset];\n 'custom-viewport-change': [payload: { width: number; height: number }];\n }>();\n\n const { t } = usePageBuilderI18n();\n\n const VIEWPORT_LABEL_KEYS: Record<ViewportPreset, string> = {\n desktop: 'toolbar.viewport.desktop',\n tablet: 'toolbar.viewport.tablet',\n mobile: 'toolbar.viewport.mobile',\n custom: 'toolbar.viewport.custom',\n };\n const VIEWPORT_ORDER: ViewportPreset[] = ['desktop', 'tablet', 'mobile', 'custom'];\n const viewportButtonRefs = ref(new Map<ViewportPreset, HTMLButtonElement>());\n\n function getViewportLabel(preset: ViewportPreset): string {\n return t(VIEWPORT_LABEL_KEYS[preset]);\n }\n\n function getViewportSwitchAriaLabel(preset: ViewportPreset): string {\n return t('toolbar.viewport.switchAriaLabel', { viewport: getViewportLabel(preset) });\n }\n\n function setViewportButtonRef(preset: ViewportPreset, element: Element | ComponentPublicInstance | null) {\n const maybeElement =\n element instanceof HTMLButtonElement\n ? element\n : element && '$el' in element && element.$el instanceof HTMLButtonElement\n ? element.$el\n : null;\n\n if (maybeElement) {\n viewportButtonRefs.value.set(preset, maybeElement);\n return;\n }\n\n viewportButtonRefs.value.delete(preset);\n }\n\n function getViewportIndex(preset: ViewportPreset): number {\n return VIEWPORT_ORDER.indexOf(preset);\n }\n\n function focusViewportButton(preset: ViewportPreset) {\n viewportButtonRefs.value.get(preset)?.focus();\n }\n\n function handleViewportKeydown(event: KeyboardEvent, currentPreset: ViewportPreset) {\n const currentIndex = getViewportIndex(currentPreset);\n if (currentIndex < 0) return;\n\n if (\n event.key !== 'ArrowLeft' &&\n event.key !== 'ArrowRight' &&\n event.key !== 'ArrowUp' &&\n event.key !== 'ArrowDown' &&\n event.key !== 'Home' &&\n event.key !== 'End'\n ) {\n return;\n }\n\n event.preventDefault();\n\n let nextIndex = currentIndex;\n if (event.key === 'ArrowLeft' || event.key === 'ArrowUp') {\n nextIndex = (currentIndex - 1 + VIEWPORT_ORDER.length) % VIEWPORT_ORDER.length;\n } else if (event.key === 'ArrowRight' || event.key === 'ArrowDown') {\n nextIndex = (currentIndex + 1) % VIEWPORT_ORDER.length;\n } else if (event.key === 'Home') {\n nextIndex = 0;\n } else if (event.key === 'End') {\n nextIndex = VIEWPORT_ORDER.length - 1;\n }\n\n const nextPreset = VIEWPORT_ORDER[nextIndex];\n emit('viewport-change', nextPreset);\n void nextTick(() => {\n focusViewportButton(nextPreset);\n });\n }\n\n function clampViewportSize(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n }\n\n function parseViewportSize(value: string): number | null {\n if (!value.trim()) return null;\n const parsed = Number(value);\n if (!Number.isFinite(parsed)) return null;\n return Math.round(parsed);\n }\n\n function updateCustomViewportSize(dimension: 'width' | 'height', rawValue: string) {\n const parsed = parseViewportSize(rawValue);\n if (parsed === null) return;\n\n const width =\n dimension === 'width'\n ? clampViewportSize(parsed, MIN_VIEWPORT_WIDTH, MAX_VIEWPORT_WIDTH)\n : clampViewportSize(props.customViewportWidth, MIN_VIEWPORT_WIDTH, MAX_VIEWPORT_WIDTH);\n\n const height =\n dimension === 'height'\n ? clampViewportSize(parsed, MIN_VIEWPORT_HEIGHT, MAX_VIEWPORT_HEIGHT)\n : clampViewportSize(props.customViewportHeight, MIN_VIEWPORT_HEIGHT, MAX_VIEWPORT_HEIGHT);\n\n emit('custom-viewport-change', { width, height });\n }\n</script>\n\n<template>\n <header class=\"ipb-toolbar\" role=\"toolbar\" :aria-label=\"t('toolbar.aria.toolbar')\">\n <div class=\"ipb-toolbar__left\" role=\"group\" :aria-label=\"t('toolbar.aria.historyControls')\">\n <button\n type=\"button\"\n class=\"ipb-toolbar__btn\"\n :disabled=\"!canUndo\"\n :aria-label=\"t('toolbar.undo.ariaLabel')\"\n :title=\"t('toolbar.undo.title')\"\n aria-keyshortcuts=\"Control+Z Meta+Z\"\n @click=\"$emit('undo')\"\n >\n ↩\n </button>\n <button\n type=\"button\"\n class=\"ipb-toolbar__btn\"\n :disabled=\"!canRedo\"\n :aria-label=\"t('toolbar.redo.ariaLabel')\"\n :title=\"t('toolbar.redo.title')\"\n aria-keyshortcuts=\"Control+Y Meta+Y Control+Shift+Z Meta+Shift+Z\"\n @click=\"$emit('redo')\"\n >\n ↪\n </button>\n </div>\n\n <div class=\"ipb-toolbar__center\" role=\"group\" :aria-label=\"t('toolbar.aria.viewportControls')\">\n <button\n v-for=\"(_, key) in VIEWPORT_PRESETS\"\n :key=\"key\"\n :ref=\"(element) => setViewportButtonRef(key as ViewportPreset, element)\"\n type=\"button\"\n class=\"ipb-toolbar__btn\"\n :class=\"{ 'ipb-toolbar__btn--active': viewport === key }\"\n :title=\"getViewportLabel(key as ViewportPreset)\"\n :aria-label=\"getViewportSwitchAriaLabel(key as ViewportPreset)\"\n :aria-pressed=\"viewport === key ? 'true' : 'false'\"\n :data-viewport-preset=\"key\"\n @click=\"$emit('viewport-change', key as ViewportPreset)\"\n @keydown=\"handleViewportKeydown($event, key as ViewportPreset)\"\n >\n {{ getViewportLabel(key as ViewportPreset) }}\n </button>\n <div v-if=\"viewport === 'custom'\" class=\"ipb-toolbar__custom-size\">\n <label class=\"ipb-toolbar__size-control\">\n <span>{{ t('toolbar.viewport.width.short') }}</span>\n <input\n class=\"ipb-toolbar__size-input\"\n type=\"number\"\n inputmode=\"numeric\"\n :aria-label=\"t('toolbar.viewport.width.ariaLabel')\"\n :min=\"MIN_VIEWPORT_WIDTH\"\n :max=\"MAX_VIEWPORT_WIDTH\"\n :value=\"customViewportWidth\"\n @input=\"updateCustomViewportSize('width', ($event.target as HTMLInputElement).value)\"\n />\n </label>\n <label class=\"ipb-toolbar__size-control\">\n <span>{{ t('toolbar.viewport.height.short') }}</span>\n <input\n class=\"ipb-toolbar__size-input\"\n type=\"number\"\n inputmode=\"numeric\"\n :aria-label=\"t('toolbar.viewport.height.ariaLabel')\"\n :min=\"MIN_VIEWPORT_HEIGHT\"\n :max=\"MAX_VIEWPORT_HEIGHT\"\n :value=\"customViewportHeight\"\n @input=\"updateCustomViewportSize('height', ($event.target as HTMLInputElement).value)\"\n />\n </label>\n </div>\n <span\n v-if=\"activeViewportWidth !== null && activeViewportHeight !== null\"\n class=\"ipb-toolbar__viewport-size\"\n aria-live=\"polite\"\n >\n {{ activeViewportWidth }}×{{ activeViewportHeight }}\n </span>\n </div>\n\n <div class=\"ipb-toolbar__right\" role=\"group\" :aria-label=\"t('toolbar.aria.saveControls')\">\n <span\n v-if=\"isDirty\"\n class=\"ipb-toolbar__dirty-indicator\"\n role=\"status\"\n :aria-label=\"t('toolbar.aria.unsavedChanges')\"\n >\n ●\n </span>\n <button\n type=\"button\"\n class=\"ipb-toolbar__btn ipb-toolbar__btn--primary\"\n :aria-label=\"t('toolbar.save.ariaLabel')\"\n :title=\"t('toolbar.save.title')\"\n aria-keyshortcuts=\"Control+S Meta+S\"\n @click=\"$emit('save')\"\n >\n {{ t('toolbar.save') }}\n </button>\n </div>\n </header>\n</template>\n\n<style scoped>\n .ipb-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n height: 48px;\n padding: 0 16px;\n background: var(--ipb-toolbar-bg, #fff);\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n flex-shrink: 0;\n }\n\n .ipb-toolbar__left,\n .ipb-toolbar__center,\n .ipb-toolbar__right {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .ipb-toolbar__btn {\n padding: 6px 12px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: transparent;\n cursor: pointer;\n font-size: 13px;\n transition: background 0.15s;\n }\n\n .ipb-toolbar__btn:focus-visible,\n .ipb-toolbar__size-input:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-toolbar__custom-size {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: 8px;\n padding-left: 8px;\n border-left: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-toolbar__size-control {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--ipb-text-secondary, #4b5563);\n }\n\n .ipb-toolbar__size-input {\n width: 72px;\n padding: 4px 6px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 12px;\n }\n\n .ipb-toolbar__viewport-size {\n margin-left: 8px;\n color: var(--ipb-text-secondary, #6b7280);\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n }\n\n .ipb-toolbar__btn:hover:not(:disabled) {\n background: var(--ipb-hover-bg, #f5f5f5);\n }\n\n .ipb-toolbar__btn:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n\n .ipb-toolbar__btn--active {\n background: var(--ipb-active-bg, #e8f0fe);\n border-color: var(--ipb-primary-color, #1a73e8);\n color: var(--ipb-primary-color, #1a73e8);\n }\n\n .ipb-toolbar__btn--primary {\n background: var(--ipb-primary-color, #1a73e8);\n color: #fff;\n border-color: var(--ipb-primary-color, #1a73e8);\n }\n\n .ipb-toolbar__btn--primary:hover {\n background: var(--ipb-primary-hover, #1557b0);\n }\n\n .ipb-toolbar__dirty-indicator {\n color: var(--ipb-warning-color, #f59e0b);\n font-size: 10px;\n }\n</style>\n","import { getComponent } from '@/core/registry';\nimport type { INode } from '@/types/node';\nimport type { ISlotDefinition } from '@/types/component';\n\n/**\n * Slots of the parent component that accept the given child component name.\n * Used to validate drop targets (canvas and tree panel).\n */\nexport function getAllowedDropSlots(parentNode: INode, componentName: string): ISlotDefinition[] {\n const definition = getComponent(parentNode.name);\n if (!definition || definition.slots.length === 0) return [];\n return definition.slots.filter((slot) => {\n const allowedComponents = slot.allowedComponents;\n return (\n !allowedComponents ||\n allowedComponents.length === 0 ||\n allowedComponents.includes(componentName)\n );\n });\n}\n\n/**\n * Resolve a valid slot name for dropping the given component into the parent,\n * or null if the parent does not accept this component in any slot.\n */\nexport function normalizeDropSlot(\n parentNode: INode,\n preferredSlot: string | null | undefined,\n componentName: string,\n): string | null {\n const allowedSlots = getAllowedDropSlots(parentNode, componentName);\n if (allowedSlots.length === 0) return null;\n\n if (preferredSlot) {\n const preferred = allowedSlots.find((slot) => slot.name === preferredSlot);\n if (preferred) return preferred.name;\n }\n\n const defaultSlot = allowedSlots.find((slot) => slot.name === 'default');\n return defaultSlot?.name ?? allowedSlots[0].name;\n}\n","<script setup lang=\"ts\">\n import { computed, inject, nextTick, ref, watch, type ComponentPublicInstance, type PropType } from 'vue';\n import { normalizeDropSlot } from '@/core/drop-slot';\n import { getComponent } from '@/core/registry';\n import { findNodeById, findParent } from '@/core/tree';\n import { flattenTree } from '@/core/virtual-tree';\n import type { INode } from '@/types/node';\n import { NODE_TREE_KEY, DRAG_DROP_KEY } from '@/types/keys';\n import { usePageBuilderI18n } from '@/i18n';\n\n type DropZone = 'above' | 'on' | 'below';\n\n interface TreeRow {\n id: number;\n key: string;\n name: string;\n depth: number;\n readonly: boolean;\n }\n\n const props = defineProps({\n content: { type: Object as PropType<INode>, required: true },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n });\n\n const emit = defineEmits<{\n select: [nodeId: number];\n }>();\n const { t } = usePageBuilderI18n();\n\n const nodeTree = inject(NODE_TREE_KEY, null);\n const dragDrop = inject(DRAG_DROP_KEY, null);\n const dropHandled = ref(false);\n const dropTargetRowId = ref<number | null>(null);\n const dropZone = ref<DropZone | null>(null);\n\n const rootId = computed(() => props.content.id);\n\n /** Get drop zone from mouse position relative to the row button, or from drop-line element. */\n function getDropZoneFromEvent(\n event: DragEvent,\n rowElement: HTMLElement | undefined,\n fallback: DropZone = 'on',\n ): DropZone {\n const dropZoneEl = (event.target as HTMLElement)?.closest?.('[data-drop-zone]');\n const zoneAttr = dropZoneEl?.getAttribute('data-drop-zone');\n if (zoneAttr === 'above') return 'above';\n if (zoneAttr === 'below') return 'below';\n if (!rowElement) return fallback;\n const rect = rowElement.getBoundingClientRect();\n const y = event.clientY - rect.top;\n const third = rect.height / 3;\n if (y < third) return 'above';\n if (y > 2 * third) return 'below';\n return 'on';\n }\n\n /** Resolve parent id, index and slot when dropping above or below a row (sibling position). */\n function getSiblingDropTarget(rowId: number, zone: 'above' | 'below'): { parentId: number; index: number; slot: string } | null {\n const rowNode = findNodeById(props.content, rowId);\n if (!rowNode) return null;\n const slot = rowNode.slot ?? 'default';\n const parentResult = findParent(props.content, rowId);\n if (!parentResult) {\n // Row is root: above = index 0, below = last\n const parentId = props.content.id;\n const index = zone === 'above' ? 0 : props.content.children.length;\n return { parentId, index, slot: 'default' };\n }\n const index = zone === 'above' ? parentResult.index : parentResult.index + 1;\n return { parentId: parentResult.parent.id, index, slot };\n }\n\n function isNodeInSubtree(node: INode, nodeId: number): boolean {\n if (node.id === nodeId) return true;\n return node.children.some((child) => isNodeInSubtree(child, nodeId));\n }\n\n function getDraggedComponentName(state: {\n sourceNodeId: number | null;\n sourceComponentName: string | null;\n isNewComponent: boolean;\n }): string | null {\n if (state.sourceComponentName) return state.sourceComponentName;\n if (state.sourceNodeId === null) return null;\n return findNodeById(props.content, state.sourceNodeId)?.name ?? null;\n }\n\n function isValidDropTarget(\n state: { sourceNodeId: number | null; sourceComponentName: string | null; isNewComponent: boolean },\n targetNodeId: number,\n ): boolean {\n if (state.sourceNodeId === targetNodeId) return false;\n const sourceName = getDraggedComponentName(state);\n if (!sourceName) return false;\n const targetNode = findNodeById(props.content, targetNodeId);\n if (!targetNode || targetNode.readonly) return false;\n if (!state.isNewComponent && state.sourceNodeId !== null) {\n const sourceNode = findNodeById(props.content, state.sourceNodeId);\n if (!sourceNode || sourceNode.readonly) return false;\n if (isNodeInSubtree(sourceNode, targetNodeId)) return false;\n }\n return normalizeDropSlot(targetNode, 'default', sourceName) !== null;\n }\n\n function isValidSiblingDropTarget(\n state: { sourceNodeId: number | null; sourceComponentName: string | null; isNewComponent: boolean },\n parentId: number,\n slot: string,\n ): boolean {\n const sourceName = getDraggedComponentName(state);\n if (!sourceName) return false;\n const parentNode = findNodeById(props.content, parentId);\n if (!parentNode || parentNode.readonly) return false;\n if (normalizeDropSlot(parentNode, slot, sourceName) === null) return false;\n if (!state.isNewComponent && state.sourceNodeId !== null) {\n const sourceNode = findNodeById(props.content, state.sourceNodeId);\n if (!sourceNode || sourceNode.readonly) return false;\n if (isNodeInSubtree(sourceNode, parentId)) return false;\n }\n return true;\n }\n\n const rows = computed<TreeRow[]>(() => {\n return flattenTree(props.content).map((row) => ({\n id: row.id,\n key: row.key,\n name: row.node.name,\n depth: row.depth,\n readonly: Boolean(row.node.readonly),\n }));\n });\n\n const rowButtonRefs = ref(new Map<number, HTMLButtonElement>());\n\n function setRowButtonRef(nodeId: number, element: Element | ComponentPublicInstance | null) {\n const maybeElement =\n element instanceof HTMLButtonElement\n ? element\n : element && '$el' in element && element.$el instanceof HTMLButtonElement\n ? element.$el\n : null;\n\n if (maybeElement) {\n rowButtonRefs.value.set(nodeId, maybeElement);\n return;\n }\n rowButtonRefs.value.delete(nodeId);\n }\n\n function getRowIdFromEventTarget(target: EventTarget | null): number | null {\n if (!(target instanceof HTMLElement)) return null;\n const nodeId = target.dataset.nodeId;\n if (!nodeId) return null;\n const parsed = Number(nodeId);\n return Number.isInteger(parsed) ? parsed : null;\n }\n\n function getActiveRowIndex(fallbackToFirst = true): number {\n if (rows.value.length === 0) return -1;\n if (props.selectedNodeId !== null) {\n const selectedIndex = rows.value.findIndex((row) => row.id === props.selectedNodeId);\n if (selectedIndex >= 0) return selectedIndex;\n }\n return fallbackToFirst ? 0 : -1;\n }\n\n function focusRowById(nodeId: number) {\n rowButtonRefs.value.get(nodeId)?.focus();\n }\n\n function selectRowByIndex(index: number) {\n const row = rows.value[index];\n if (!row) return;\n emit('select', row.id);\n void nextTick(() => {\n focusRowById(row.id);\n });\n }\n\n function isRowTabStop(rowId: number): boolean {\n const activeIndex = getActiveRowIndex();\n return rows.value[activeIndex]?.id === rowId;\n }\n\n const canDragDrop = computed(() => Boolean(nodeTree && dragDrop));\n\n const isDropTargetOn = (rowId: number) =>\n Boolean(\n dragDrop?.dragState.value.isDragging &&\n dropTargetRowId.value === rowId &&\n dropZone.value === 'on',\n );\n const isDropTargetAbove = (rowId: number) =>\n Boolean(\n dragDrop?.dragState.value.isDragging &&\n dropTargetRowId.value === rowId &&\n dropZone.value === 'above',\n );\n const isDropTargetBelow = (rowId: number) =>\n Boolean(\n dragDrop?.dragState.value.isDragging &&\n dropTargetRowId.value === rowId &&\n dropZone.value === 'below',\n );\n\n function isRowDraggable(row: TreeRow): boolean {\n if (!canDragDrop.value || row.readonly) return false;\n return row.id !== rootId.value;\n }\n\n function handleTreeDragStart(row: TreeRow, event: DragEvent) {\n if (!dragDrop || !isRowDraggable(row)) return;\n dropHandled.value = false;\n dragDrop.startDragExisting(row.id);\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n event.dataTransfer.setData('application/x-ipb-node-id', String(row.id));\n event.dataTransfer.setData('text/plain', String(row.id));\n }\n }\n\n function handleTreeDragOver(row: TreeRow, event: DragEvent) {\n if (!dragDrop || !dragDrop.dragState.value.isDragging) return;\n const state = dragDrop.dragState.value;\n const zone = getDropZoneFromEvent(event, rowButtonRefs.value.get(row.id));\n\n if (zone === 'on') {\n if (!isValidDropTarget(state, row.id)) return;\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = state.isNewComponent ? 'copy' : 'move';\n }\n dropTargetRowId.value = row.id;\n dropZone.value = 'on';\n dragDrop.updateDropTarget(row.id, 0, 'default');\n return;\n }\n\n const siblingTarget = getSiblingDropTarget(row.id, zone);\n if (!siblingTarget || !isValidSiblingDropTarget(state, siblingTarget.parentId, siblingTarget.slot)) return;\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = state.isNewComponent ? 'copy' : 'move';\n }\n dropTargetRowId.value = row.id;\n dropZone.value = zone;\n dragDrop.updateDropTarget(siblingTarget.parentId, siblingTarget.index, siblingTarget.slot);\n }\n\n function handleTreeDrop(row: TreeRow, event: DragEvent) {\n event.preventDefault();\n if (!nodeTree || !dragDrop || !dragDrop.dragState.value.isDragging) return;\n const state = dragDrop.dragState.value;\n // Prefer stored zone when we're dropping on the row we were hovering (line was visible)\n const storedZone =\n dropTargetRowId.value === row.id && dropZone.value ? dropZone.value : null;\n const zone = storedZone ?? getDropZoneFromEvent(event, rowButtonRefs.value.get(row.id), 'on');\n\n if (zone === 'on') {\n const targetNode = findNodeById(props.content, row.id);\n if (!targetNode || !isValidDropTarget(state, row.id)) {\n dragDrop.cancelDrag();\n return;\n }\n const sourceName = getDraggedComponentName(state);\n const slot = sourceName ? normalizeDropSlot(targetNode, 'default', sourceName) ?? 'default' : 'default';\n\n if (state.isNewComponent && state.sourceComponentName) {\n const defaultProps = getComponent(state.sourceComponentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(row.id, state.sourceComponentName, 0, slot, defaultProps);\n dropHandled.value = true;\n dragDrop.endDrag();\n if (newNodeId !== null) emit('select', newNodeId);\n return;\n }\n if (state.sourceNodeId === null) return;\n nodeTree.moveNodeTo(state.sourceNodeId, row.id, 0, slot);\n dropHandled.value = true;\n dragDrop.endDrag();\n emit('select', state.sourceNodeId);\n return;\n }\n\n const siblingTarget = getSiblingDropTarget(row.id, zone);\n if (!siblingTarget || !isValidSiblingDropTarget(state, siblingTarget.parentId, siblingTarget.slot)) {\n dragDrop.cancelDrag();\n return;\n }\n const parentNode = findNodeById(props.content, siblingTarget.parentId);\n const sourceName = getDraggedComponentName(state);\n const slot =\n parentNode && sourceName\n ? normalizeDropSlot(parentNode, siblingTarget.slot, sourceName) ?? siblingTarget.slot\n : siblingTarget.slot;\n\n if (state.isNewComponent && state.sourceComponentName) {\n const defaultProps = getComponent(state.sourceComponentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(\n siblingTarget.parentId,\n state.sourceComponentName,\n siblingTarget.index,\n slot,\n defaultProps,\n );\n dropHandled.value = true;\n dragDrop.endDrag();\n if (newNodeId !== null) emit('select', newNodeId);\n return;\n }\n if (state.sourceNodeId === null) return;\n // When moving within same parent, removal shifts indices: insert index must be adjusted\n let insertIndex = siblingTarget.index;\n const sourceParent = findParent(props.content, state.sourceNodeId);\n if (\n sourceParent &&\n sourceParent.parent.id === siblingTarget.parentId &&\n sourceParent.index < siblingTarget.index\n ) {\n insertIndex = siblingTarget.index - 1;\n }\n nodeTree.moveNodeTo(state.sourceNodeId, siblingTarget.parentId, insertIndex, slot);\n dropHandled.value = true;\n dragDrop.endDrag();\n emit('select', state.sourceNodeId);\n }\n\n function handleTreeDragEnd() {\n dropTargetRowId.value = null;\n dropZone.value = null;\n if (!dropHandled.value && dragDrop?.dragState.value.isDragging) {\n dragDrop.cancelDrag();\n }\n }\n\n function handleTreeKeydown(event: KeyboardEvent) {\n if (rows.value.length === 0) return;\n\n const currentRowId = getRowIdFromEventTarget(event.target);\n const currentIndex =\n currentRowId === null ? getActiveRowIndex() : rows.value.findIndex((row) => row.id === currentRowId);\n if (currentIndex < 0) return;\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n const nextIndex = Math.min(rows.value.length - 1, currentIndex + 1);\n selectRowByIndex(nextIndex);\n return;\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n const nextIndex = Math.max(0, currentIndex - 1);\n selectRowByIndex(nextIndex);\n return;\n }\n\n if (event.key === 'Home') {\n event.preventDefault();\n selectRowByIndex(0);\n return;\n }\n\n if (event.key === 'End') {\n event.preventDefault();\n selectRowByIndex(rows.value.length - 1);\n return;\n }\n\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n selectRowByIndex(currentIndex);\n }\n }\n\n watch(\n () => props.selectedNodeId,\n (selectedNodeId) => {\n if (selectedNodeId === null) return;\n void nextTick(() => {\n focusRowById(selectedNodeId);\n });\n },\n );\n</script>\n\n<template>\n <div class=\"ipb-tree-panel\">\n <div class=\"ipb-tree-panel__list\" role=\"tree\" :aria-label=\"t('treePanel.ariaLabel')\" @keydown=\"handleTreeKeydown\">\n <div\n v-for=\"row in rows\"\n :key=\"row.key\"\n class=\"ipb-tree-panel__row-wrapper\"\n @dragover=\"handleTreeDragOver(row, $event)\"\n @drop=\"handleTreeDrop(row, $event)\"\n >\n <div\n v-if=\"isDropTargetAbove(row.id)\"\n class=\"ipb-tree-panel__drop-line\"\n data-drop-zone=\"above\"\n aria-hidden=\"true\"\n />\n <button\n :ref=\"(element) => setRowButtonRef(row.id, element)\"\n type=\"button\"\n class=\"ipb-tree-panel__item\"\n :class=\"{\n 'ipb-tree-panel__item--selected': selectedNodeId === row.id,\n 'ipb-tree-panel__item--readonly': row.readonly,\n 'ipb-tree-panel__item--drop-target': isDropTargetOn(row.id),\n 'ipb-tree-panel__item--draggable': isRowDraggable(row),\n }\"\n :style=\"{ paddingInlineStart: `${row.depth * 16 + 8}px` }\"\n :data-node-id=\"row.id\"\n :draggable=\"isRowDraggable(row)\"\n role=\"treeitem\"\n :aria-selected=\"selectedNodeId === row.id ? 'true' : 'false'\"\n :aria-level=\"row.depth + 1\"\n :aria-readonly=\"row.readonly ? 'true' : 'false'\"\n :tabindex=\"isRowTabStop(row.id) ? 0 : -1\"\n @click=\"emit('select', row.id)\"\n @dragstart=\"handleTreeDragStart(row, $event)\"\n @dragend=\"handleTreeDragEnd\"\n >\n <span class=\"ipb-tree-panel__name\">{{ row.name }}</span>\n <span class=\"ipb-tree-panel__id\">#{{ row.id }}</span>\n <span v-if=\"row.readonly\" class=\"ipb-tree-panel__readonly\">{{ t('treePanel.readonly') }}</span>\n </button>\n <div\n v-if=\"isDropTargetBelow(row.id)\"\n class=\"ipb-tree-panel__drop-line\"\n data-drop-zone=\"below\"\n aria-hidden=\"true\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-tree-panel {\n min-width: 0;\n }\n\n .ipb-tree-panel__list {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .ipb-tree-panel__row-wrapper {\n display: flex;\n flex-direction: column;\n gap: 0;\n }\n\n .ipb-tree-panel__drop-line {\n min-height: 8px;\n margin: 0 8px;\n padding: 3px 0;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n cursor: default;\n }\n\n .ipb-tree-panel__drop-line::before {\n content: '';\n display: block;\n width: 100%;\n height: 2px;\n border-radius: 1px;\n background: var(--ipb-primary-color, #1d4ed8);\n }\n\n .ipb-tree-panel__item {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n min-width: 0;\n padding: 6px 8px;\n border: 0;\n border-radius: 4px;\n background: transparent;\n color: inherit;\n text-align: left;\n cursor: pointer;\n font-size: 12px;\n line-height: 1.3;\n }\n\n .ipb-tree-panel__item:hover {\n background: var(--ipb-hover-bg, #f5f5f5);\n }\n\n .ipb-tree-panel__item:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: -1px;\n }\n\n .ipb-tree-panel__item--selected {\n background: var(--ipb-primary-soft, rgba(37, 99, 235, 0.14));\n color: var(--ipb-primary-color, #1d4ed8);\n }\n\n .ipb-tree-panel__item--readonly {\n opacity: 0.8;\n }\n\n .ipb-tree-panel__item--drop-target {\n background: var(--ipb-primary-soft, rgba(37, 99, 235, 0.2));\n outline: 2px dashed var(--ipb-primary-color, #1d4ed8);\n outline-offset: 2px;\n }\n\n .ipb-tree-panel__item--draggable {\n cursor: grab;\n }\n\n .ipb-tree-panel__item--draggable:active {\n cursor: grabbing;\n }\n\n .ipb-tree-panel__name {\n font-weight: 500;\n white-space: nowrap;\n }\n\n .ipb-tree-panel__id {\n color: var(--ipb-text-muted, #6b7280);\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;\n font-size: 11px;\n white-space: nowrap;\n }\n\n .ipb-tree-panel__readonly {\n margin-left: auto;\n font-size: 10px;\n text-transform: uppercase;\n letter-spacing: 0.03em;\n color: var(--ipb-text-muted, #6b7280);\n border: 1px solid var(--ipb-border-color, #d1d5db);\n border-radius: 3px;\n padding: 1px 4px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, nextTick, ref, watch, type PropType } from 'vue';\n import { getComponentsByCategory } from '@/core/registry';\n import type { IComponentDefinition } from '@/types/component';\n import type { INode } from '@/types/node';\n import { usePageBuilderI18n } from '@/i18n';\n import TreePanel from './TreePanel.vue';\n\n const props = defineProps({\n open: { type: Boolean, default: true },\n content: { type: Object as PropType<INode | null>, default: null },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n });\n\n const emit = defineEmits<{\n toggle: [];\n dragStart: [componentName: string];\n dragEnd: [];\n add: [componentName: string];\n select: [nodeId: number];\n }>();\n\n const categorizedComponents = computed(() => getComponentsByCategory());\n const { t } = usePageBuilderI18n();\n const searchQuery = ref('');\n const treeOpen = ref(true);\n const DRAWER_CONTENT_ID = 'ipb-left-drawer-content';\n const TREE_PANEL_REGION_ID = 'ipb-left-drawer-tree-panel';\n const drawerRef = ref<HTMLElement | null>(null);\n const drawerToggleRef = ref<HTMLButtonElement | null>(null);\n const searchInputRef = ref<HTMLInputElement | null>(null);\n const focusContentOnNextOpen = ref(false);\n\n const filteredCategorizedComponents = computed(() => {\n const query = searchQuery.value.trim().toLowerCase();\n if (!query) {\n return categorizedComponents.value;\n }\n\n const filtered = new Map<string, IComponentDefinition[]>();\n for (const [category, components] of categorizedComponents.value) {\n const matching = components.filter((comp) => {\n const searchable = [comp.name, comp.label, comp.description ?? '', category, comp.category];\n return searchable.some((value) => value.toLowerCase().includes(query));\n });\n if (matching.length > 0) {\n filtered.set(category, matching);\n }\n }\n\n return filtered;\n });\n\n function handleDragStart(componentName: string, event: DragEvent) {\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'copy';\n event.dataTransfer.setData('application/x-ipb-component', componentName);\n event.dataTransfer.setData('text/plain', componentName);\n }\n emit('dragStart', componentName);\n }\n\n function handleDragEnd() {\n emit('dragEnd');\n }\n\n function handleComponentAdd(componentName: string) {\n emit('add', componentName);\n }\n\n function toggleTree() {\n treeOpen.value = !treeOpen.value;\n }\n\n function getFirstFocusableDrawerControl(): HTMLElement | null {\n const drawer = drawerRef.value;\n if (!drawer) return null;\n\n return drawer.querySelector<HTMLElement>(\n `#${DRAWER_CONTENT_ID} button:not([disabled]), #${DRAWER_CONTENT_ID} input:not([disabled]), #${DRAWER_CONTENT_ID} select:not([disabled]), #${DRAWER_CONTENT_ID} textarea:not([disabled]), #${DRAWER_CONTENT_ID} [tabindex]:not([tabindex=\"-1\"])`,\n );\n }\n\n function focusDrawerContent() {\n searchInputRef.value?.focus();\n if (document.activeElement === searchInputRef.value) return;\n getFirstFocusableDrawerControl()?.focus();\n }\n\n function handleDrawerToggle() {\n focusContentOnNextOpen.value = !props.open;\n emit('toggle');\n }\n\n function getCategoryAriaLabel(category: string): string {\n return t('leftDrawer.category.ariaLabel', { category });\n }\n\n function getDragAriaLabel(label: string): string {\n return t('leftDrawer.component.dragAriaLabel', { label });\n }\n\n watch(\n () => props.open,\n (isOpen, wasOpen) => {\n if (isOpen && !wasOpen && focusContentOnNextOpen.value) {\n void nextTick(() => {\n focusDrawerContent();\n });\n }\n\n if (!isOpen && wasOpen) {\n const activeElement = document.activeElement;\n if (activeElement instanceof HTMLElement && drawerRef.value?.contains(activeElement)) {\n void nextTick(() => {\n drawerToggleRef.value?.focus();\n });\n }\n }\n\n if (isOpen !== wasOpen) {\n focusContentOnNextOpen.value = false;\n }\n },\n );\n</script>\n\n<template>\n <aside\n ref=\"drawerRef\"\n class=\"ipb-left-drawer\"\n :class=\"{ 'ipb-left-drawer--open': open }\"\n :aria-label=\"t('leftDrawer.aria.componentPalette')\"\n role=\"complementary\"\n >\n <div class=\"ipb-left-drawer__header\">\n <span class=\"ipb-left-drawer__title\" id=\"ipb-left-drawer-title\">{{ t('leftDrawer.title') }}</span>\n <button\n ref=\"drawerToggleRef\"\n type=\"button\"\n class=\"ipb-left-drawer__toggle\"\n :aria-label=\"t('leftDrawer.toggle.ariaLabel')\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :aria-controls=\"DRAWER_CONTENT_ID\"\n @click=\"handleDrawerToggle\"\n >\n {{ open ? '◀' : '▶' }}\n </button>\n </div>\n\n <div\n v-if=\"open\"\n :id=\"DRAWER_CONTENT_ID\"\n class=\"ipb-left-drawer__content\"\n role=\"region\"\n aria-labelledby=\"ipb-left-drawer-title\"\n >\n <div class=\"ipb-left-drawer__section\">\n <h3 class=\"ipb-left-drawer__section-title\" id=\"ipb-left-drawer-components-title\">\n {{ t('leftDrawer.section.components') }}\n </h3>\n <div class=\"ipb-left-drawer__search\" role=\"search\">\n <input\n ref=\"searchInputRef\"\n v-model=\"searchQuery\"\n type=\"search\"\n class=\"ipb-left-drawer__search-input\"\n :placeholder=\"t('leftDrawer.search.placeholder')\"\n :aria-label=\"t('leftDrawer.search.ariaLabel')\"\n />\n </div>\n <div\n v-for=\"[category, components] in filteredCategorizedComponents\"\n :key=\"category\"\n class=\"ipb-left-drawer__category\"\n >\n <h4 class=\"ipb-left-drawer__category-title\">{{ category }}</h4>\n <div class=\"ipb-left-drawer__component-list\" role=\"group\" :aria-label=\"getCategoryAriaLabel(category)\">\n <button\n v-for=\"comp in components\"\n :key=\"comp.name\"\n type=\"button\"\n class=\"ipb-left-drawer__component-item\"\n draggable=\"true\"\n :title=\"comp.description\"\n :aria-label=\"getDragAriaLabel(comp.label)\"\n :aria-keyshortcuts=\"'Enter Space'\"\n @click=\"handleComponentAdd(comp.name)\"\n @dragstart=\"handleDragStart(comp.name, $event)\"\n @dragend=\"handleDragEnd\"\n >\n <span class=\"ipb-left-drawer__component-icon\" aria-hidden=\"true\">{{ comp.icon ?? '◻' }}</span>\n <span class=\"ipb-left-drawer__component-label\">{{ comp.label }}</span>\n </button>\n </div>\n </div>\n <p v-if=\"filteredCategorizedComponents.size === 0\" class=\"ipb-left-drawer__empty\">\n {{ t('leftDrawer.empty') }}\n </p>\n </div>\n\n <div v-if=\"content\" class=\"ipb-left-drawer__section ipb-left-drawer__section--tree\">\n <div class=\"ipb-left-drawer__section-header\">\n <h3 class=\"ipb-left-drawer__section-title\">{{ t('leftDrawer.section.tree') }}</h3>\n <button\n type=\"button\"\n class=\"ipb-left-drawer__section-toggle\"\n :aria-expanded=\"treeOpen ? 'true' : 'false'\"\n :aria-controls=\"TREE_PANEL_REGION_ID\"\n :aria-label=\"t('leftDrawer.tree.toggle.ariaLabel')\"\n @click=\"toggleTree\"\n >\n {{ treeOpen ? '−' : '+' }}\n </button>\n </div>\n\n <div v-if=\"treeOpen\" :id=\"TREE_PANEL_REGION_ID\" role=\"region\" :aria-label=\"t('treePanel.ariaLabel')\">\n <TreePanel :content=\"content\" :selected-node-id=\"selectedNodeId\" @select=\"emit('select', $event)\" />\n </div>\n </div>\n </div>\n </aside>\n</template>\n\n<style scoped>\n .ipb-left-drawer {\n width: 48px;\n background: var(--ipb-drawer-bg, #fff);\n border-right: 1px solid var(--ipb-border-color, #e0e0e0);\n transition: width 0.2s ease;\n overflow: hidden;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n }\n\n .ipb-left-drawer--open {\n width: 260px;\n }\n\n .ipb-left-drawer__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n padding: 12px;\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-left-drawer__title {\n font-weight: 600;\n font-size: 14px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .ipb-left-drawer__toggle {\n flex-shrink: 0;\n background: none;\n border: none;\n cursor: pointer;\n font-size: 12px;\n padding: 4px;\n }\n\n .ipb-left-drawer__toggle:focus-visible,\n .ipb-left-drawer__section-toggle:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n border-radius: 4px;\n }\n\n .ipb-left-drawer__content {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .ipb-left-drawer__section {\n min-width: 0;\n }\n\n .ipb-left-drawer__search {\n margin-top: 8px;\n margin-bottom: 8px;\n }\n\n .ipb-left-drawer__search-input {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: var(--ipb-input-bg, #fff);\n color: var(--ipb-text-color, #111827);\n font-size: 12px;\n }\n\n .ipb-left-drawer__search-input:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-left-drawer__section--tree {\n padding-top: 8px;\n border-top: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-left-drawer__section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 8px;\n }\n\n .ipb-left-drawer__section-title {\n margin: 0;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--ipb-text-muted, #6b7280);\n }\n\n .ipb-left-drawer__section-toggle {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px 4px;\n font-size: 14px;\n line-height: 1;\n }\n\n .ipb-left-drawer__category-title {\n font-size: 11px;\n font-weight: 600;\n margin: 10px 0 8px;\n }\n\n .ipb-left-drawer__component-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n\n .ipb-left-drawer__component-item {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px;\n border-radius: 4px;\n cursor: grab;\n transition: background 0.15s;\n font-size: 13px;\n width: 100%;\n border: 0;\n background: transparent;\n color: inherit;\n text-align: left;\n }\n\n .ipb-left-drawer__component-item:hover {\n background: var(--ipb-hover-bg, #f5f5f5);\n }\n\n .ipb-left-drawer__component-item:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: -1px;\n }\n\n .ipb-left-drawer__component-icon {\n font-size: 16px;\n width: 24px;\n text-align: center;\n }\n\n .ipb-left-drawer__empty {\n margin: 8px 0 0;\n font-size: 12px;\n color: var(--ipb-text-muted, #6b7280);\n }\n</style>\n","<script setup lang=\"ts\">\n const props = defineProps({\n modelValue: { type: [String, Number, Boolean], default: '' },\n placeholder: { type: String, default: '' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n }>();\n\n function handleInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).value);\n }\n</script>\n\n<template>\n <input\n class=\"ipb-prop-editor ipb-prop-editor--text\"\n type=\"text\"\n :value=\"String(props.modelValue ?? '')\"\n :placeholder=\"placeholder\"\n @input=\"handleInput\"\n />\n</template>\n\n<style scoped>\n .ipb-prop-editor {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-prop-editor:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue';\n\n const props = defineProps({\n modelValue: { type: [String, Number], default: undefined },\n min: { type: Number, default: undefined },\n max: { type: Number, default: undefined },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: number | undefined];\n }>();\n\n const inputValue = computed(() => {\n if (typeof props.modelValue === 'number') return String(props.modelValue);\n if (typeof props.modelValue === 'string') return props.modelValue;\n return '';\n });\n\n function handleInput(event: Event) {\n const value = (event.target as HTMLInputElement).value.trim();\n if (value === '') {\n emit('update:modelValue', undefined);\n return;\n }\n\n const parsed = Number(value);\n emit('update:modelValue', Number.isNaN(parsed) ? undefined : parsed);\n }\n</script>\n\n<template>\n <input\n class=\"ipb-prop-editor ipb-prop-editor--number\"\n type=\"number\"\n :value=\"inputValue\"\n :min=\"min\"\n :max=\"max\"\n @input=\"handleInput\"\n />\n</template>\n\n<style scoped>\n .ipb-prop-editor {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-prop-editor:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useAttrs } from 'vue';\n import { usePageBuilderI18n } from '@/i18n';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n defineProps({\n modelValue: { type: Boolean, default: false },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: boolean];\n }>();\n\n function handleChange(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).checked);\n }\n\n const { t } = usePageBuilderI18n();\n const attrs = useAttrs();\n const checkboxAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n</script>\n\n<template>\n <label class=\"ipb-prop-editor ipb-prop-editor--boolean\" :class=\"attrs.class\" :style=\"attrs.style\">\n <input v-bind=\"checkboxAttrs\" type=\"checkbox\" :checked=\"modelValue\" @change=\"handleChange\" />\n <span>{{ modelValue ? t('propBoolean.enabled') : t('propBoolean.disabled') }}</span>\n </label>\n</template>\n\n<style scoped>\n .ipb-prop-editor--boolean {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n user-select: none;\n }\n\n .ipb-prop-editor--boolean input:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 2px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed } from 'vue';\n import type { IPropDefinition } from '@/types/component';\n import { usePageBuilderI18n } from '@/i18n';\n\n const props = defineProps({\n modelValue: { type: [String, Number, Boolean], default: undefined },\n options: {\n type: Array as () => IPropDefinition['options'],\n default: () => [],\n },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string | number | boolean | undefined];\n }>();\n\n const selectedIndex = computed(() => {\n if (!props.options || props.options.length === 0) return '';\n const idx = props.options.findIndex((option) => option.value === props.modelValue);\n if (idx >= 0) return String(idx);\n return '0';\n });\n\n function handleChange(event: Event) {\n const value = (event.target as HTMLSelectElement).value;\n if (value === '' || !props.options) {\n emit('update:modelValue', undefined);\n return;\n }\n\n const option = props.options[Number(value)];\n emit('update:modelValue', option?.value);\n }\n\n const { t } = usePageBuilderI18n();\n</script>\n\n<template>\n <select class=\"ipb-prop-editor ipb-prop-editor--select\" :value=\"selectedIndex\" @change=\"handleChange\">\n <option v-if=\"!options || options.length === 0\" value=\"\">{{ t('propSelect.noOptions') }}</option>\n <option v-for=\"(option, index) in options ?? []\" :key=\"`${option.label}-${index}`\" :value=\"String(index)\">\n {{ option.label }}\n </option>\n </select>\n</template>\n\n<style scoped>\n .ipb-prop-editor {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n background: var(--ipb-drawer-bg, #fff);\n }\n\n .ipb-prop-editor:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useAttrs } from 'vue';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n const props = defineProps({\n modelValue: { type: String, default: '' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n }>();\n\n const pickerValue = computed(() => {\n const value = props.modelValue.trim();\n if (/^#[0-9a-fA-F]{6}$/.test(value)) return value;\n if (/^#[0-9a-fA-F]{3}$/.test(value)) {\n const chars = value.slice(1).split('');\n return `#${chars.map((char) => `${char}${char}`).join('')}`;\n }\n return '#000000';\n });\n\n function handlePickerInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).value);\n }\n\n function handleTextInput(event: Event) {\n emit('update:modelValue', (event.target as HTMLInputElement).value);\n }\n\n const attrs = useAttrs();\n const inputAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n</script>\n\n<template>\n <div class=\"ipb-prop-editor ipb-prop-editor--color\" :class=\"attrs.class\" :style=\"attrs.style\">\n <input\n v-bind=\"inputAttrs\"\n class=\"ipb-prop-editor__picker\"\n type=\"color\"\n :value=\"pickerValue\"\n @input=\"handlePickerInput\"\n />\n <input\n v-bind=\"inputAttrs\"\n class=\"ipb-prop-editor__text\"\n type=\"text\"\n :value=\"modelValue\"\n placeholder=\"#000000\"\n @input=\"handleTextInput\"\n />\n </div>\n</template>\n\n<style scoped>\n .ipb-prop-editor--color {\n display: flex;\n align-items: center;\n gap: 8px;\n }\n\n .ipb-prop-editor__picker {\n width: 40px;\n height: 32px;\n padding: 2px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: var(--ipb-drawer-bg, #fff);\n }\n\n .ipb-prop-editor__text {\n flex: 1;\n min-width: 0;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-prop-editor__picker:focus-visible,\n .ipb-prop-editor__text:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, onMounted, ref, useAttrs, watch } from 'vue';\n import { sanitizeRichTextHtml, sanitizeUrlByKind } from '@/core/sanitize';\n import { usePageBuilderI18n } from '@/i18n';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n const props = defineProps({\n modelValue: { type: String, default: '' },\n placeholder: { type: String, default: 'Type text...' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n }>();\n\n const editorRef = ref<HTMLDivElement | null>(null);\n const lastEmittedValue = ref('');\n\n function getSanitizedHtml(value: unknown): string {\n if (typeof value !== 'string') return '';\n return sanitizeRichTextHtml(value);\n }\n\n function syncEditorHtml(value: string) {\n const editor = editorRef.value;\n if (!editor) return;\n\n const sanitizedHtml = getSanitizedHtml(value);\n if (editor.innerHTML !== sanitizedHtml) {\n editor.innerHTML = sanitizedHtml;\n }\n lastEmittedValue.value = sanitizedHtml;\n }\n\n function emitCurrentHtml() {\n const editor = editorRef.value;\n if (!editor) return;\n\n const sanitizedHtml = getSanitizedHtml(editor.innerHTML);\n if (editor.innerHTML !== sanitizedHtml) {\n editor.innerHTML = sanitizedHtml;\n }\n if (sanitizedHtml === lastEmittedValue.value) return;\n\n lastEmittedValue.value = sanitizedHtml;\n emit('update:modelValue', sanitizedHtml);\n }\n\n function focusEditor() {\n editorRef.value?.focus();\n }\n\n function executeCommand(command: string, value?: string) {\n if (typeof document.execCommand !== 'function') return;\n document.execCommand(command, false, value);\n }\n\n function runCommand(command: 'bold' | 'italic' | 'insertUnorderedList' | 'insertOrderedList') {\n focusEditor();\n executeCommand(command);\n emitCurrentHtml();\n }\n\n function insertLink() {\n focusEditor();\n const rawUrl = window.prompt(t('richText.prompt.enterUrl'), t('richText.prompt.defaultUrl'));\n if (!rawUrl) return;\n\n const safeUrl = sanitizeUrlByKind(rawUrl, 'link');\n if (!safeUrl) return;\n\n executeCommand('createLink', safeUrl);\n emitCurrentHtml();\n }\n\n onMounted(() => {\n syncEditorHtml(getSanitizedHtml(props.modelValue));\n });\n\n watch(\n () => props.modelValue,\n (nextValue) => {\n syncEditorHtml(getSanitizedHtml(nextValue));\n }\n );\n\n const { t } = usePageBuilderI18n();\n const attrs = useAttrs();\n const contentAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n const editorAriaLabel = computed(() => {\n const ariaLabelledBy = attrs['aria-labelledby'];\n const ariaLabel = attrs['aria-label'];\n if (ariaLabelledBy || ariaLabel) return undefined;\n return t('richText.aria.editor');\n });\n</script>\n\n<template>\n <div class=\"ipb-richtext-editor\" :class=\"attrs.class\" :style=\"attrs.style\">\n <div class=\"ipb-richtext-editor__toolbar\" role=\"toolbar\" :aria-label=\"t('richText.aria.toolbar')\">\n <button\n type=\"button\"\n data-command=\"bold\"\n :aria-label=\"t('richText.action.bold')\"\n :title=\"t('richText.action.bold')\"\n @click=\"runCommand('bold')\"\n >\n <strong>B</strong>\n </button>\n <button\n type=\"button\"\n data-command=\"italic\"\n :aria-label=\"t('richText.action.italic')\"\n :title=\"t('richText.action.italic')\"\n @click=\"runCommand('italic')\"\n >\n <em>I</em>\n </button>\n <button\n type=\"button\"\n data-command=\"ul\"\n :aria-label=\"t('richText.action.unorderedList')\"\n :title=\"t('richText.action.unorderedList')\"\n @click=\"runCommand('insertUnorderedList')\"\n >\n UL\n </button>\n <button\n type=\"button\"\n data-command=\"ol\"\n :aria-label=\"t('richText.action.orderedList')\"\n :title=\"t('richText.action.orderedList')\"\n @click=\"runCommand('insertOrderedList')\"\n >\n OL\n </button>\n <button\n type=\"button\"\n data-command=\"link\"\n :aria-label=\"t('richText.action.link')\"\n :title=\"t('richText.action.link')\"\n @click=\"insertLink\"\n >\n {{ t('richText.action.link') }}\n </button>\n </div>\n\n <div\n v-bind=\"contentAttrs\"\n ref=\"editorRef\"\n class=\"ipb-richtext-editor__content\"\n contenteditable=\"true\"\n role=\"textbox\"\n aria-multiline=\"true\"\n :aria-label=\"editorAriaLabel\"\n :data-placeholder=\"placeholder\"\n @input=\"emitCurrentHtml\"\n @blur=\"emitCurrentHtml\"\n />\n </div>\n</template>\n\n<style scoped>\n .ipb-richtext-editor {\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n overflow: hidden;\n }\n\n .ipb-richtext-editor__toolbar {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n padding: 6px;\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n background: var(--ipb-surface-muted, #f8fafc);\n }\n\n .ipb-richtext-editor__toolbar button {\n min-width: 30px;\n height: 28px;\n padding: 0 8px;\n border: 1px solid var(--ipb-border-color, #d1d5db);\n border-radius: 4px;\n background: var(--ipb-drawer-bg, #fff);\n cursor: pointer;\n font-size: 12px;\n }\n\n .ipb-richtext-editor__toolbar button:hover {\n background: var(--ipb-surface-hover, #f3f4f6);\n }\n\n .ipb-richtext-editor__toolbar button:focus-visible,\n .ipb-richtext-editor__content:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-richtext-editor__content {\n min-height: 120px;\n padding: 8px;\n font-size: 13px;\n line-height: 1.5;\n outline: none;\n }\n\n .ipb-richtext-editor__content:empty::before {\n content: attr(data-placeholder);\n color: var(--ipb-text-muted, #9ca3af);\n pointer-events: none;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, useAttrs } from 'vue';\n import { sanitizeUrlByKind } from '@/core/sanitize';\n import { usePageBuilderI18n } from '@/i18n';\n\n defineOptions({\n inheritAttrs: false,\n });\n\n const props = defineProps({\n modelValue: { type: String, default: '' },\n });\n\n const emit = defineEmits<{\n 'update:modelValue': [value: string];\n upload: [];\n }>();\n\n const rawValue = computed(() => props.modelValue.trim());\n const safePreviewUrl = computed(() => sanitizeUrlByKind(rawValue.value, 'media'));\n const hasValue = computed(() => rawValue.value.length > 0);\n const canPreview = computed(() => safePreviewUrl.value.length > 0);\n\n function handleInput(event: Event) {\n const inputValue = (event.target as HTMLInputElement).value;\n emit('update:modelValue', sanitizeUrlByKind(inputValue, 'media'));\n }\n\n function handleClear() {\n emit('update:modelValue', '');\n }\n\n function handleUploadPlaceholder() {\n emit('upload');\n }\n\n const { t } = usePageBuilderI18n();\n const attrs = useAttrs();\n const inputAttrs = computed(() => {\n const { class: _class, style: _style, ...rest } = attrs as Record<string, unknown>;\n return rest;\n });\n</script>\n\n<template>\n <div class=\"ipb-media-picker\" :class=\"attrs.class\" :style=\"attrs.style\">\n <div class=\"ipb-media-picker__controls\">\n <input\n v-bind=\"inputAttrs\"\n class=\"ipb-media-picker__input\"\n type=\"url\"\n :value=\"modelValue\"\n :placeholder=\"t('mediaPicker.input.placeholder')\"\n @input=\"handleInput\"\n />\n <button class=\"ipb-media-picker__btn\" type=\"button\" :disabled=\"!hasValue\" @click=\"handleClear\">\n {{ t('mediaPicker.clear') }}\n </button>\n <button class=\"ipb-media-picker__btn\" type=\"button\" @click=\"handleUploadPlaceholder\">\n {{ t('mediaPicker.upload') }}\n </button>\n </div>\n\n <div class=\"ipb-media-picker__preview\">\n <img\n v-if=\"hasValue && canPreview\"\n class=\"ipb-media-picker__image\"\n :src=\"safePreviewUrl\"\n :alt=\"t('mediaPicker.preview.alt')\"\n />\n <p v-else class=\"ipb-media-picker__empty\">{{ t('mediaPicker.empty') }}</p>\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-media-picker {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .ipb-media-picker__controls {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto auto;\n gap: 8px;\n align-items: center;\n }\n\n .ipb-media-picker__input {\n min-width: 0;\n width: 100%;\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n font-size: 13px;\n box-sizing: border-box;\n }\n\n .ipb-media-picker__btn {\n padding: 6px 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: var(--ipb-drawer-bg, #fff);\n cursor: pointer;\n font-size: 12px;\n }\n\n .ipb-media-picker__input:focus-visible,\n .ipb-media-picker__btn:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-media-picker__btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .ipb-media-picker__preview {\n border: 1px dashed var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n padding: 6px;\n min-height: 88px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ipb-bg-subtle, #fafafa);\n }\n\n .ipb-media-picker__image {\n max-width: 100%;\n max-height: 140px;\n object-fit: contain;\n display: block;\n }\n\n .ipb-media-picker__empty {\n margin: 0;\n font-size: 12px;\n color: var(--ipb-text-muted, #6b7280);\n text-align: center;\n }\n</style>\n","import type { Component } from 'vue';\nimport type { PropEditorType } from '@/types/component';\nimport PropTextEditor from './PropTextEditor.vue';\nimport PropNumberEditor from './PropNumberEditor.vue';\nimport PropBooleanEditor from './PropBooleanEditor.vue';\nimport PropSelectEditor from './PropSelectEditor.vue';\nimport PropColorEditor from './PropColorEditor.vue';\nimport RichTextEditor from './RichTextEditor.vue';\nimport MediaPicker from './MediaPicker.vue';\n\nexport const DEFAULT_PROP_EDITOR = PropTextEditor;\n\nexport const PROP_EDITORS: Partial<Record<PropEditorType, Component>> = {\n text: PropTextEditor,\n textarea: PropTextEditor,\n richtext: RichTextEditor,\n number: PropNumberEditor,\n boolean: PropBooleanEditor,\n select: PropSelectEditor,\n color: PropColorEditor,\n image: MediaPicker,\n url: MediaPicker,\n json: PropTextEditor,\n};\n","<script setup lang=\"ts\">\n import { computed, nextTick, ref, watch, type PropType, type Component } from 'vue';\n import type { IPropDefinition, PropEditorType } from '@/types/component';\n import type { INode } from '@/types/node';\n import { findNodeById } from '@/core/tree';\n import { getComponent } from '@/core/registry';\n import { usePageBuilderI18n } from '@/i18n';\n import { DEFAULT_PROP_EDITOR, PROP_EDITORS } from './prop-editors';\n\n const props = defineProps({\n open: { type: Boolean, default: false },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n content: { type: Object as PropType<INode>, required: true },\n });\n\n const emit = defineEmits<{\n toggle: [];\n 'update-props': [nodeId: number, props: Record<string, unknown>];\n delete: [nodeId: number];\n duplicate: [nodeId: number];\n }>();\n const { t } = usePageBuilderI18n();\n const drawerRef = ref<HTMLElement | null>(null);\n const drawerToggleRef = ref<HTMLButtonElement | null>(null);\n const focusContentOnNextOpen = ref(false);\n\n const selectedNode = computed(() => {\n if (props.selectedNodeId === null) return null;\n return findNodeById(props.content, props.selectedNodeId) ?? null;\n });\n\n const componentDef = computed(() => {\n if (!selectedNode.value) return null;\n return getComponent(selectedNode.value.name) ?? null;\n });\n\n function getPropValue(propDef: IPropDefinition): unknown {\n if (!selectedNode.value) return propDef.defaultValue ?? '';\n return selectedNode.value.props[propDef.key] ?? propDef.defaultValue ?? '';\n }\n\n function getEditorComponent(type: PropEditorType): Component {\n return PROP_EDITORS[type] ?? DEFAULT_PROP_EDITOR;\n }\n\n function getEditorBindings(propDef: IPropDefinition): Record<string, unknown> {\n const modelValue = getPropValue(propDef);\n\n if (propDef.type === 'number') {\n return {\n modelValue,\n min: propDef.validation?.min,\n max: propDef.validation?.max,\n };\n }\n\n if (propDef.type === 'select') {\n return {\n modelValue,\n options: propDef.options ?? [],\n };\n }\n\n if (propDef.type === 'image' || propDef.type === 'url') {\n return { modelValue };\n }\n\n if (\n propDef.type === 'text' ||\n propDef.type === 'textarea' ||\n propDef.type === 'richtext' ||\n propDef.type === 'json'\n ) {\n return {\n modelValue,\n placeholder: propDef.label,\n };\n }\n\n return { modelValue };\n }\n\n function handlePropUpdate(propKey: string, value: unknown) {\n if (!selectedNode.value) return;\n emit('update-props', selectedNode.value.id, { [propKey]: value });\n }\n\n const DRAWER_CONTENT_ID = 'ipb-right-drawer-content';\n\n function getPropLabelId(propKey: string): string {\n return `ipb-right-drawer-prop-label-${propKey}`;\n }\n\n function getFirstFocusableContentControl(): HTMLElement | null {\n const drawer = drawerRef.value;\n if (!drawer) return null;\n\n return drawer.querySelector<HTMLElement>(\n `#${DRAWER_CONTENT_ID} input:not([disabled]), #${DRAWER_CONTENT_ID} select:not([disabled]), #${DRAWER_CONTENT_ID} textarea:not([disabled]), #${DRAWER_CONTENT_ID} button:not([disabled]), #${DRAWER_CONTENT_ID} [contenteditable]:not([contenteditable=\"false\"]), #${DRAWER_CONTENT_ID} [tabindex]:not([tabindex=\"-1\"])`,\n );\n }\n\n function focusDrawerContent() {\n getFirstFocusableContentControl()?.focus();\n }\n\n function handleDrawerToggle() {\n focusContentOnNextOpen.value = !props.open;\n emit('toggle');\n }\n\n watch(\n () => props.open,\n (isOpen, wasOpen) => {\n if (isOpen && !wasOpen && focusContentOnNextOpen.value) {\n void nextTick(() => {\n focusDrawerContent();\n });\n }\n\n if (!isOpen && wasOpen) {\n const activeElement = document.activeElement;\n if (activeElement instanceof HTMLElement && drawerRef.value?.contains(activeElement)) {\n void nextTick(() => {\n drawerToggleRef.value?.focus();\n });\n }\n }\n\n if (isOpen !== wasOpen) {\n focusContentOnNextOpen.value = false;\n }\n },\n );\n</script>\n\n<template>\n <aside\n ref=\"drawerRef\"\n class=\"ipb-right-drawer\"\n :class=\"{ 'ipb-right-drawer--open': open }\"\n role=\"complementary\"\n :aria-label=\"t('rightDrawer.aria.componentProperties')\"\n >\n <div class=\"ipb-right-drawer__header\">\n <span class=\"ipb-right-drawer__title\" id=\"ipb-right-drawer-title\">{{ t('rightDrawer.title') }}</span>\n <button\n ref=\"drawerToggleRef\"\n type=\"button\"\n class=\"ipb-right-drawer__toggle\"\n :aria-label=\"t('rightDrawer.toggle.ariaLabel')\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :aria-controls=\"DRAWER_CONTENT_ID\"\n @click=\"handleDrawerToggle\"\n >\n {{ open ? '▶' : '◀' }}\n </button>\n </div>\n\n <div\n v-if=\"open && selectedNode && componentDef\"\n :id=\"DRAWER_CONTENT_ID\"\n class=\"ipb-right-drawer__content\"\n role=\"region\"\n aria-labelledby=\"ipb-right-drawer-title\"\n >\n <div class=\"ipb-right-drawer__section\">\n <h3 class=\"ipb-right-drawer__section-title\">{{ componentDef.label }}</h3>\n <p v-if=\"componentDef.description\" class=\"ipb-right-drawer__description\">\n {{ componentDef.description }}\n </p>\n </div>\n\n <div class=\"ipb-right-drawer__section\">\n <h4 class=\"ipb-right-drawer__section-subtitle\">{{ t('rightDrawer.section.properties') }}</h4>\n <!-- Property editors will be rendered here based on editableProps -->\n <div\n v-for=\"propDef in componentDef.editableProps\"\n :key=\"propDef.key\"\n class=\"ipb-right-drawer__prop\"\n :data-prop-key=\"propDef.key\"\n >\n <label :id=\"getPropLabelId(propDef.key)\" class=\"ipb-right-drawer__prop-label\">{{ propDef.label }}</label>\n <component\n :is=\"getEditorComponent(propDef.type)\"\n class=\"ipb-right-drawer__prop-editor\"\n v-bind=\"getEditorBindings(propDef)\"\n :aria-labelledby=\"getPropLabelId(propDef.key)\"\n @update:model-value=\"handlePropUpdate(propDef.key, $event)\"\n />\n </div>\n </div>\n\n <div class=\"ipb-right-drawer__actions\">\n <button\n type=\"button\"\n class=\"ipb-right-drawer__btn\"\n :aria-label=\"t('rightDrawer.actions.duplicate.ariaLabel')\"\n @click=\"emit('duplicate', selectedNode!.id)\"\n >\n {{ t('rightDrawer.actions.duplicate') }}\n </button>\n <button\n type=\"button\"\n class=\"ipb-right-drawer__btn ipb-right-drawer__btn--danger\"\n :disabled=\"selectedNode!.readonly\"\n :aria-label=\"t('rightDrawer.actions.delete.ariaLabel')\"\n @click=\"emit('delete', selectedNode!.id)\"\n >\n {{ t('rightDrawer.actions.delete') }}\n </button>\n </div>\n </div>\n\n <div v-else-if=\"open\" class=\"ipb-right-drawer__empty\">\n <p>{{ t('rightDrawer.empty') }}</p>\n </div>\n </aside>\n</template>\n\n<style scoped>\n .ipb-right-drawer {\n width: 48px;\n background: var(--ipb-drawer-bg, #fff);\n border-left: 1px solid var(--ipb-border-color, #e0e0e0);\n transition: width 0.2s ease;\n overflow: hidden;\n flex-shrink: 0;\n display: flex;\n flex-direction: column;\n }\n\n .ipb-right-drawer--open {\n width: 320px;\n }\n\n .ipb-right-drawer__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n padding: 12px;\n border-bottom: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-right-drawer__title {\n font-weight: 600;\n font-size: 14px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .ipb-right-drawer__toggle {\n flex-shrink: 0;\n background: none;\n border: none;\n cursor: pointer;\n font-size: 12px;\n padding: 4px;\n }\n\n .ipb-right-drawer__toggle:focus-visible,\n .ipb-right-drawer__btn:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: 1px;\n }\n\n .ipb-right-drawer__content {\n flex: 1;\n overflow-y: auto;\n padding: 16px;\n }\n\n .ipb-right-drawer__section {\n margin-bottom: 20px;\n }\n\n .ipb-right-drawer__section-title {\n font-size: 16px;\n font-weight: 600;\n margin: 0 0 4px;\n }\n\n .ipb-right-drawer__section-subtitle {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--ipb-text-muted, #6b7280);\n margin: 0 0 12px;\n }\n\n .ipb-right-drawer__description {\n font-size: 13px;\n color: var(--ipb-text-muted, #6b7280);\n margin: 0;\n }\n\n .ipb-right-drawer__prop {\n margin-bottom: 12px;\n }\n\n .ipb-right-drawer__prop-label {\n display: block;\n font-size: 12px;\n font-weight: 500;\n margin-bottom: 4px;\n }\n\n .ipb-right-drawer__prop-editor {\n width: 100%;\n }\n\n .ipb-right-drawer__actions {\n display: flex;\n gap: 8px;\n padding-top: 16px;\n border-top: 1px solid var(--ipb-border-color, #e0e0e0);\n }\n\n .ipb-right-drawer__btn {\n flex: 1;\n padding: 8px;\n border: 1px solid var(--ipb-border-color, #e0e0e0);\n border-radius: 4px;\n background: transparent;\n cursor: pointer;\n font-size: 13px;\n }\n\n .ipb-right-drawer__btn--danger {\n color: var(--ipb-danger-color, #dc2626);\n border-color: var(--ipb-danger-color, #dc2626);\n }\n\n .ipb-right-drawer__btn--danger:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n\n .ipb-right-drawer__empty {\n padding: 24px 16px;\n text-align: center;\n color: var(--ipb-text-muted, #6b7280);\n font-size: 13px;\n }\n</style>\n","export const IFRAME_BRIDGE_NAMESPACE = '@improba/page-builder/iframe-bridge';\nexport const IFRAME_BRIDGE_VERSION = 1 as const;\n\ntype IframeBridgeChannel = 'keydown' | 'pointer' | 'lifecycle';\nexport type IframeBridgeSessionToken = string;\n\ninterface IframeBridgeEnvelope<TChannel extends IframeBridgeChannel, TPayload> {\n namespace: typeof IFRAME_BRIDGE_NAMESPACE;\n version: typeof IFRAME_BRIDGE_VERSION;\n sessionToken: IframeBridgeSessionToken;\n channel: TChannel;\n payload: TPayload;\n}\n\nexport interface IframeBridgeKeydownPayload {\n key: string;\n code: string;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n defaultPrevented: boolean;\n isEditable: boolean;\n}\n\nexport type IframeBridgePointerInteraction = 'hover' | 'select' | 'context';\n\ninterface IframeBridgePointerBasePayload {\n interaction: IframeBridgePointerInteraction;\n nodeId: number | null;\n}\n\ninterface IframeBridgePointerContextPayload extends IframeBridgePointerBasePayload {\n interaction: 'context';\n clientX: number;\n clientY: number;\n}\n\ninterface IframeBridgePointerHoverOrSelectPayload extends IframeBridgePointerBasePayload {\n interaction: 'hover' | 'select';\n}\n\nexport type IframeBridgePointerPayload = IframeBridgePointerContextPayload | IframeBridgePointerHoverOrSelectPayload;\n\nexport interface IframeBridgeLifecyclePayload {\n state: 'ready';\n}\n\nexport type IframeBridgeKeydownMessage = IframeBridgeEnvelope<'keydown', IframeBridgeKeydownPayload>;\nexport type IframeBridgePointerMessage = IframeBridgeEnvelope<'pointer', IframeBridgePointerPayload>;\nexport type IframeBridgeLifecycleMessage = IframeBridgeEnvelope<'lifecycle', IframeBridgeLifecyclePayload>;\n\nexport type IframeBridgeMessage = IframeBridgeKeydownMessage | IframeBridgePointerMessage | IframeBridgeLifecycleMessage;\n\nfunction createIframeBridgeEnvelope<TChannel extends IframeBridgeChannel, TPayload>(\n channel: TChannel,\n payload: TPayload,\n sessionToken: IframeBridgeSessionToken,\n): IframeBridgeEnvelope<TChannel, TPayload> {\n return {\n namespace: IFRAME_BRIDGE_NAMESPACE,\n version: IFRAME_BRIDGE_VERSION,\n sessionToken,\n channel,\n payload,\n };\n}\n\nexport function createIframeBridgeSessionToken(): IframeBridgeSessionToken {\n if (typeof globalThis.crypto?.randomUUID === 'function') {\n return globalThis.crypto.randomUUID();\n }\n\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n const bytes = new Uint8Array(16);\n globalThis.crypto.getRandomValues(bytes);\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');\n }\n\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;\n}\n\nexport function createIframeBridgeReadyMessage(sessionToken: IframeBridgeSessionToken): IframeBridgeLifecycleMessage {\n return createIframeBridgeEnvelope('lifecycle', { state: 'ready' }, sessionToken);\n}\n\nexport function createIframeBridgePointerMessage(\n payload: IframeBridgePointerPayload,\n sessionToken: IframeBridgeSessionToken,\n): IframeBridgePointerMessage {\n return createIframeBridgeEnvelope('pointer', payload, sessionToken);\n}\n\nexport function createIframeBridgeKeydownMessage(\n payload: IframeBridgeKeydownPayload,\n sessionToken: IframeBridgeSessionToken,\n): IframeBridgeKeydownMessage {\n return createIframeBridgeEnvelope('keydown', payload, sessionToken);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object';\n}\n\nfunction parsePointerPayload(payload: unknown): IframeBridgePointerPayload | null {\n if (!isRecord(payload)) return null;\n\n const interaction = payload.interaction;\n const maybeNodeId = payload.nodeId;\n if (interaction !== 'hover' && interaction !== 'select' && interaction !== 'context') return null;\n if (maybeNodeId !== null && typeof maybeNodeId !== 'number') return null;\n if (typeof maybeNodeId === 'number' && !Number.isInteger(maybeNodeId)) return null;\n\n const nodeId: number | null = maybeNodeId;\n\n if (interaction === 'context') {\n const clientX = payload.clientX;\n const clientY = payload.clientY;\n if (typeof clientX !== 'number' || typeof clientY !== 'number') return null;\n return { interaction, nodeId, clientX, clientY };\n }\n\n return { interaction, nodeId };\n}\n\nfunction parseKeydownPayload(payload: unknown): IframeBridgeKeydownPayload | null {\n if (!isRecord(payload)) return null;\n\n if (typeof payload.key !== 'string') return null;\n if (typeof payload.code !== 'string') return null;\n if (typeof payload.ctrlKey !== 'boolean') return null;\n if (typeof payload.metaKey !== 'boolean') return null;\n if (typeof payload.shiftKey !== 'boolean') return null;\n if (typeof payload.altKey !== 'boolean') return null;\n if (typeof payload.defaultPrevented !== 'boolean') return null;\n if (typeof payload.isEditable !== 'boolean') return null;\n\n return {\n key: payload.key,\n code: payload.code,\n ctrlKey: payload.ctrlKey,\n metaKey: payload.metaKey,\n shiftKey: payload.shiftKey,\n altKey: payload.altKey,\n defaultPrevented: payload.defaultPrevented,\n isEditable: payload.isEditable,\n };\n}\n\nexport interface ParseIframeBridgeMessageOptions {\n expectedSessionToken?: IframeBridgeSessionToken;\n allowLegacyNoSessionToken?: boolean;\n}\n\nexport function parseIframeBridgeMessage(\n value: unknown,\n options: ParseIframeBridgeMessageOptions = {},\n): IframeBridgeMessage | null {\n if (!isRecord(value)) return null;\n if (value.namespace !== IFRAME_BRIDGE_NAMESPACE) return null;\n if (value.version !== IFRAME_BRIDGE_VERSION) return null;\n if (value.channel !== 'keydown' && value.channel !== 'pointer' && value.channel !== 'lifecycle') return null;\n\n const sessionTokenCandidate = value.sessionToken;\n const hasValidSessionToken = typeof sessionTokenCandidate === 'string' && sessionTokenCandidate.length > 0;\n if (options.expectedSessionToken) {\n if (!hasValidSessionToken || sessionTokenCandidate !== options.expectedSessionToken) return null;\n } else if (!hasValidSessionToken && !options.allowLegacyNoSessionToken) {\n return null;\n }\n\n const sessionToken = hasValidSessionToken ? sessionTokenCandidate : '';\n\n if (value.channel === 'lifecycle') {\n if (!isRecord(value.payload) || value.payload.state !== 'ready') return null;\n return createIframeBridgeReadyMessage(sessionToken);\n }\n\n if (value.channel === 'pointer') {\n const payload = parsePointerPayload(value.payload);\n if (!payload) return null;\n return createIframeBridgePointerMessage(payload, sessionToken);\n }\n\n const payload = parseKeydownPayload(value.payload);\n if (!payload) return null;\n return createIframeBridgeKeydownMessage(payload, sessionToken);\n}\n\nexport interface IframeBridgeParentOptions {\n hostWindow: Window;\n expectedSource: Window;\n expectedOrigin: string;\n expectedSessionToken?: IframeBridgeSessionToken;\n allowLegacyNoSessionToken?: boolean;\n onReady?: () => void;\n onPointer?: (payload: IframeBridgePointerPayload) => void;\n onKeydown?: (payload: IframeBridgeKeydownPayload) => void;\n}\n\nexport interface IframeBridgeParent {\n dispose: () => void;\n}\n\nexport function createIframeBridgeParent(options: IframeBridgeParentOptions): IframeBridgeParent {\n const onMessage = (event: MessageEvent) => {\n if (event.source !== options.expectedSource) return;\n if (event.origin !== options.expectedOrigin) return;\n\n const message = parseIframeBridgeMessage(event.data, {\n expectedSessionToken: options.expectedSessionToken,\n allowLegacyNoSessionToken: options.allowLegacyNoSessionToken ?? !options.expectedSessionToken,\n });\n if (!message) return;\n\n if (message.channel === 'lifecycle') {\n options.onReady?.();\n return;\n }\n\n if (message.channel === 'pointer') {\n options.onPointer?.(message.payload);\n return;\n }\n\n options.onKeydown?.(message.payload);\n };\n\n options.hostWindow.addEventListener('message', onMessage);\n return {\n dispose: () => {\n options.hostWindow.removeEventListener('message', onMessage);\n },\n };\n}\n\nexport interface IframeBridgeChild {\n postReady: () => void;\n postPointer: (payload: IframeBridgePointerPayload) => void;\n postKeydown: (payload: IframeBridgeKeydownPayload) => void;\n}\n\nexport interface IframeBridgeChildOptions {\n targetWindow: Window;\n targetOrigin: string;\n sessionToken: IframeBridgeSessionToken;\n}\n\nexport function createIframeBridgeChild(options: IframeBridgeChildOptions): IframeBridgeChild {\n return {\n postReady: () => {\n options.targetWindow.postMessage(createIframeBridgeReadyMessage(options.sessionToken), options.targetOrigin);\n },\n postPointer: (payload) => {\n options.targetWindow.postMessage(\n createIframeBridgePointerMessage(payload, options.sessionToken),\n options.targetOrigin,\n );\n },\n postKeydown: (payload) => {\n options.targetWindow.postMessage(\n createIframeBridgeKeydownMessage(payload, options.sessionToken),\n options.targetOrigin,\n );\n },\n };\n}\n\nexport interface MountIframeBridgeDomListenersOptions {\n frameDocument: Document;\n contentRoot: HTMLElement;\n bridge: IframeBridgeChild;\n resolveNodeId: (target: EventTarget | null) => number | null;\n isEditableTarget: (target: EventTarget | null) => boolean;\n}\n\nfunction shouldAutoPreventShortcut(payload: IframeBridgeKeydownPayload): boolean {\n if (payload.defaultPrevented || payload.isEditable) return false;\n\n const hasModifier = payload.ctrlKey || payload.metaKey;\n const key = payload.key.toLowerCase();\n const code = payload.code.toLowerCase();\n\n if (hasModifier && (key === 'z' || key === 'y' || key === 's')) return true;\n\n const isDeleteKey = key === 'delete' || key === 'backspace' || code === 'delete' || code === 'backspace';\n return isDeleteKey && !payload.ctrlKey && !payload.metaKey && !payload.altKey;\n}\n\nexport function mountIframeBridgeDomListeners(options: MountIframeBridgeDomListenersOptions): () => void {\n const handleClick = (event: MouseEvent) => {\n options.bridge.postPointer({\n interaction: 'select',\n nodeId: options.resolveNodeId(event.target),\n });\n };\n\n const handleMouseMove = (event: MouseEvent) => {\n options.bridge.postPointer({\n interaction: 'hover',\n nodeId: options.resolveNodeId(event.target),\n });\n };\n\n const handleMouseLeave = () => {\n options.bridge.postPointer({\n interaction: 'hover',\n nodeId: null,\n });\n };\n\n const handleContextMenu = (event: MouseEvent) => {\n event.preventDefault();\n options.bridge.postPointer({\n interaction: 'context',\n nodeId: options.resolveNodeId(event.target),\n clientX: event.clientX,\n clientY: event.clientY,\n });\n };\n\n const handleKeydown = (event: KeyboardEvent) => {\n const payload: IframeBridgeKeydownPayload = {\n key: event.key,\n code: event.code,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n defaultPrevented: event.defaultPrevented,\n isEditable:\n options.isEditableTarget(event.target) ||\n options.isEditableTarget(options.frameDocument.activeElement),\n };\n\n if (shouldAutoPreventShortcut(payload)) {\n event.preventDefault();\n }\n\n options.bridge.postKeydown(payload);\n };\n\n options.contentRoot.addEventListener('click', handleClick);\n options.contentRoot.addEventListener('mousemove', handleMouseMove);\n options.contentRoot.addEventListener('mouseleave', handleMouseLeave);\n options.contentRoot.addEventListener('contextmenu', handleContextMenu);\n options.frameDocument.addEventListener('keydown', handleKeydown);\n\n options.bridge.postReady();\n\n return () => {\n options.contentRoot.removeEventListener('click', handleClick);\n options.contentRoot.removeEventListener('mousemove', handleMouseMove);\n options.contentRoot.removeEventListener('mouseleave', handleMouseLeave);\n options.contentRoot.removeEventListener('contextmenu', handleContextMenu);\n options.frameDocument.removeEventListener('keydown', handleKeydown);\n };\n}\n","<script setup lang=\"ts\">\n import { computed, nextTick, onBeforeUnmount, ref, watch, type CSSProperties, type PropType } from 'vue';\n import { usePageBuilderI18n } from '@/i18n';\n\n export type NodeContextMenuAction = 'duplicate' | 'delete' | 'move-up' | 'move-down';\n\n const props = defineProps({\n open: { type: Boolean, default: false },\n x: { type: Number, default: 0 },\n y: { type: Number, default: 0 },\n canDelete: { type: Boolean, default: true },\n canMoveUp: { type: Boolean, default: false },\n canMoveDown: { type: Boolean, default: false },\n });\n\n const emit = defineEmits<{\n action: [action: NodeContextMenuAction];\n close: [];\n }>();\n const { t } = usePageBuilderI18n();\n\n interface MenuItem {\n key: NodeContextMenuAction;\n label: string;\n danger?: boolean;\n disabled?: boolean;\n }\n\n const menuStyle = computed<CSSProperties>(() => ({\n top: `${props.y}px`,\n left: `${props.x}px`,\n }));\n\n const menuItems = computed<MenuItem[]>(() => [\n { key: 'duplicate', label: t('contextMenu.duplicate') },\n { key: 'move-up', label: t('contextMenu.moveUp'), disabled: !props.canMoveUp },\n { key: 'move-down', label: t('contextMenu.moveDown'), disabled: !props.canMoveDown },\n { key: 'delete', label: t('contextMenu.delete'), danger: true, disabled: !props.canDelete },\n ]);\n\n function handleAction(action: NodeContextMenuAction, disabled?: boolean) {\n if (disabled) return;\n emit('action', action);\n }\n\n const menuRootRef = ref<HTMLElement | null>(null);\n const previousFocusedElement = ref<HTMLElement | null>(null);\n\n function getFocusableItems(): HTMLButtonElement[] {\n if (!menuRootRef.value) return [];\n return Array.from(menuRootRef.value.querySelectorAll<HTMLButtonElement>('.ipb-node-context-menu__item')).filter(\n (item) => !item.disabled,\n );\n }\n\n function focusFirstMenuItem() {\n const [firstItem] = getFocusableItems();\n firstItem?.focus();\n }\n\n function restorePreviousFocus() {\n if (previousFocusedElement.value instanceof HTMLElement) {\n previousFocusedElement.value.focus();\n }\n previousFocusedElement.value = null;\n }\n\n function handleMenuKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault();\n emit('close');\n return;\n }\n\n if (event.key === 'Tab') {\n event.preventDefault();\n emit('close');\n return;\n }\n\n const items = getFocusableItems();\n if (items.length === 0) return;\n\n const activeElement = document.activeElement instanceof HTMLButtonElement ? document.activeElement : null;\n const activeIndex = activeElement ? items.indexOf(activeElement) : -1;\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n const nextIndex = activeIndex < 0 ? 0 : (activeIndex + 1) % items.length;\n items[nextIndex]?.focus();\n return;\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n const nextIndex = activeIndex < 0 ? items.length - 1 : (activeIndex - 1 + items.length) % items.length;\n items[nextIndex]?.focus();\n return;\n }\n\n if (event.key === 'Home') {\n event.preventDefault();\n items[0]?.focus();\n return;\n }\n\n if (event.key === 'End') {\n event.preventDefault();\n items[items.length - 1]?.focus();\n }\n }\n\n function handleMenuFocusOut(event: FocusEvent) {\n const nextTarget = event.relatedTarget;\n if (!(nextTarget instanceof Node)) {\n emit('close');\n return;\n }\n if (!menuRootRef.value?.contains(nextTarget)) {\n emit('close');\n }\n }\n\n watch(\n () => props.open,\n (isOpen) => {\n if (isOpen) {\n previousFocusedElement.value = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n void nextTick(() => {\n focusFirstMenuItem();\n });\n return;\n }\n\n restorePreviousFocus();\n },\n { immediate: true },\n );\n\n onBeforeUnmount(() => {\n restorePreviousFocus();\n });\n</script>\n\n<template>\n <div\n v-if=\"open\"\n ref=\"menuRootRef\"\n class=\"ipb-node-context-menu\"\n :style=\"menuStyle\"\n role=\"menu\"\n :aria-label=\"t('contextMenu.ariaLabel')\"\n aria-orientation=\"vertical\"\n tabindex=\"-1\"\n @click.stop\n @contextmenu.prevent\n @keydown=\"handleMenuKeydown\"\n @focusout=\"handleMenuFocusOut\"\n >\n <button\n v-for=\"item in menuItems\"\n :key=\"item.key\"\n type=\"button\"\n class=\"ipb-node-context-menu__item\"\n :class=\"{ 'ipb-node-context-menu__item--danger': item.danger }\"\n :disabled=\"item.disabled\"\n :data-action=\"item.key\"\n role=\"menuitem\"\n :aria-disabled=\"item.disabled ? 'true' : undefined\"\n @click=\"handleAction(item.key, item.disabled)\"\n >\n {{ item.label }}\n </button>\n </div>\n</template>\n\n<style scoped>\n .ipb-node-context-menu {\n position: absolute;\n z-index: 30;\n display: flex;\n flex-direction: column;\n min-width: 148px;\n padding: 6px;\n border: 1px solid var(--ipb-border-color, #d1d5db);\n border-radius: 8px;\n background: #fff;\n box-shadow: 0 8px 24px rgba(15, 23, 42, 0.16);\n }\n\n .ipb-node-context-menu__item {\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--ipb-text-color, #111827);\n font-size: 13px;\n line-height: 1.4;\n text-align: left;\n padding: 7px 10px;\n cursor: pointer;\n }\n\n .ipb-node-context-menu__item:hover:not(:disabled) {\n background: rgba(59, 130, 246, 0.1);\n }\n\n .ipb-node-context-menu__item:focus-visible {\n outline: 2px solid var(--ipb-focus-color, #2563eb);\n outline-offset: -1px;\n }\n\n .ipb-node-context-menu__item--danger {\n color: var(--ipb-danger-color, #dc2626);\n }\n\n .ipb-node-context-menu__item:disabled {\n opacity: 0.45;\n cursor: not-allowed;\n }\n</style>\n","<script setup lang=\"ts\">\n import {\n computed,\n h,\n inject,\n nextTick,\n onBeforeUnmount,\n onMounted,\n ref,\n render,\n watch,\n type CSSProperties,\n type PropType,\n } from 'vue';\n import { getComponent } from '@/core/registry';\n import {\n createIframeBridgeChild,\n createIframeBridgeParent,\n createIframeBridgeSessionToken,\n mountIframeBridgeDomListeners,\n type IframeBridgeKeydownPayload,\n type IframeBridgePointerPayload,\n } from '@/core/iframe-bridge';\n import { normalizeDropSlot } from '@/core/drop-slot';\n import { findNodeById, findParent } from '@/core/tree';\n import { DRAG_DROP_KEY, NODE_TREE_KEY } from '@/types/keys';\n import type { INode } from '@/types/node';\n import type { IViewportSize, ViewportPreset } from '@/types/editor';\n import { VIEWPORT_PRESETS } from '@/types/editor';\n import { usePageBuilderI18n } from '@/i18n';\n import NodeRenderer from '../reader/NodeRenderer.vue';\n import NodeContextMenu, { type NodeContextMenuAction } from './NodeContextMenu.vue';\n\n const props = defineProps({\n content: { type: Object as PropType<INode>, required: true },\n layout: { type: Object as PropType<INode | null>, default: null },\n variables: { type: Object as PropType<Record<string, string>>, default: () => ({}) },\n selectedNodeId: { type: Number as PropType<number | null>, default: null },\n hoveredNodeId: { type: Number as PropType<number | null>, default: null },\n viewport: { type: String as PropType<ViewportPreset>, default: 'desktop' },\n viewportWidth: { type: Number as PropType<number | null>, default: null },\n viewportHeight: { type: Number as PropType<number | null>, default: null },\n });\n\n interface IframeCanvasKeydownPayload extends IframeBridgeKeydownPayload {\n preventDefault: () => void;\n }\n\n const emit = defineEmits<{\n select: [nodeId: number | null];\n hover: [nodeId: number | null];\n 'context-action': [payload: { action: NodeContextMenuAction; nodeId: number }];\n 'iframe-keydown': [payload: IframeCanvasKeydownPayload];\n 'viewport-size-change': [payload: IViewportSize];\n }>();\n\n interface OverlayRect {\n top: number;\n left: number;\n width: number;\n height: number;\n }\n\n interface DropLocation {\n targetId: number;\n index: number;\n slot: string;\n }\n\n const IFRAME_CONTENT_ROOT_ID = 'ipb-iframe-canvas-content';\n const IFRAME_BASE_STYLE_ID = 'ipb-iframe-canvas-base-style';\n const MIN_VIEWPORT_WIDTH = 240;\n const MIN_VIEWPORT_HEIGHT = 320;\n\n const nodeTree = inject(NODE_TREE_KEY, null);\n const dragDrop = inject(DRAG_DROP_KEY, null);\n const { t } = usePageBuilderI18n();\n\n const iframeRef = ref<HTMLIFrameElement | null>(null);\n const stageRef = ref<HTMLElement | null>(null);\n const fallbackContentRef = ref<HTMLElement | null>(null);\n const useFallbackDom = ref(false);\n const contentRef = ref<HTMLElement | null>(null);\n const iframeDocumentRef = ref<Document | null>(null);\n const iframeWindowRef = ref<Window | null>(null);\n const teardownBridgeParentRef = ref<(() => void) | null>(null);\n const teardownBridgeDomRef = ref<(() => void) | null>(null);\n const resizeObserverRef = ref<ResizeObserver | null>(null);\n const currentViewportSize = ref<IViewportSize>({ width: 0, height: 0 });\n const hasViewportSizeReport = ref(false);\n\n const selectedRect = ref<OverlayRect | null>(null);\n const hoveredRect = ref<OverlayRect | null>(null);\n const dropRect = ref<OverlayRect | null>(null);\n const contextMenuOpen = ref(false);\n const contextMenuNodeId = ref<number | null>(null);\n const contextMenuX = ref(0);\n const contextMenuY = ref(0);\n const canDeleteFromMenu = ref(false);\n const canMoveUpFromMenu = ref(false);\n const canMoveDownFromMenu = ref(false);\n\n const resolvedViewportDimensions = computed<IViewportSize>(() => {\n if (props.viewport === 'custom') {\n return {\n width: Math.max(MIN_VIEWPORT_WIDTH, Math.round(props.viewportWidth ?? VIEWPORT_PRESETS.desktop.width)),\n height: Math.max(MIN_VIEWPORT_HEIGHT, Math.round(props.viewportHeight ?? VIEWPORT_PRESETS.desktop.height)),\n };\n }\n\n const preset = VIEWPORT_PRESETS[props.viewport];\n return { width: preset.width, height: preset.height };\n });\n\n const canvasStyle = computed(() => {\n return {\n width: `min(100%, ${resolvedViewportDimensions.value.width}px)`,\n height: `${resolvedViewportDimensions.value.height}px`,\n };\n });\n\n const selectedOverlayStyle = computed<CSSProperties | null>(() =>\n selectedRect.value\n ? {\n top: `${selectedRect.value.top}px`,\n left: `${selectedRect.value.left}px`,\n width: `${selectedRect.value.width}px`,\n height: `${selectedRect.value.height}px`,\n }\n : null,\n );\n\n const hoveredOverlayStyle = computed<CSSProperties | null>(() =>\n hoveredRect.value && props.hoveredNodeId !== props.selectedNodeId\n ? {\n top: `${hoveredRect.value.top}px`,\n left: `${hoveredRect.value.left}px`,\n width: `${hoveredRect.value.width}px`,\n height: `${hoveredRect.value.height}px`,\n }\n : null,\n );\n\n const dropOverlayStyle = computed<CSSProperties | null>(() =>\n dropRect.value\n ? {\n top: `${dropRect.value.top}px`,\n left: `${dropRect.value.left}px`,\n width: `${dropRect.value.width}px`,\n height: `${dropRect.value.height}px`,\n }\n : null,\n );\n\n function isElementTarget(target: EventTarget | null): target is Element {\n if (!target || typeof target !== 'object') return false;\n const maybeNode = target as { nodeType?: number };\n return maybeNode.nodeType === 1;\n }\n\n function parseNodeId(value: string | null): number | null {\n if (value === null) return null;\n const parsed = Number(value);\n return Number.isInteger(parsed) ? parsed : null;\n }\n\n function getNodeIdFromEventTarget(target: EventTarget | null): number | null {\n if (!isElementTarget(target)) return null;\n const marker = target.closest('[data-ipb-node-id]');\n return parseNodeId(marker?.getAttribute('data-ipb-node-id') ?? null);\n }\n\n function mergeLayoutAndContent(layout: INode, content: INode): INode {\n const contentRoot: INode = {\n ...content,\n slot: content.slot ?? 'default',\n };\n return {\n ...layout,\n children: [...(layout.children ?? []), contentRoot],\n };\n }\n\n function findMarkedElement(nodeId: number | null): Element | null {\n if (nodeId === null || !contentRef.value) return null;\n return contentRef.value.querySelector(`[data-ipb-node-id=\"${nodeId}\"]`);\n }\n\n function getOverlayRect(element: Element | null): OverlayRect | null {\n if (!element || !contentRef.value) return null;\n const nodeRect = element.getBoundingClientRect();\n const contentRect = contentRef.value.getBoundingClientRect();\n const frameScrollTop = iframeWindowRef.value?.scrollY ?? 0;\n const frameScrollLeft = iframeWindowRef.value?.scrollX ?? 0;\n\n return {\n top: nodeRect.top - contentRect.top + frameScrollTop,\n left: nodeRect.left - contentRect.left + frameScrollLeft,\n width: nodeRect.width,\n height: nodeRect.height,\n };\n }\n\n function clampIndex(index: number, max: number): number {\n return Math.max(0, Math.min(index, max));\n }\n\n function isNodeInSubtree(root: INode, maybeNodeId: number): boolean {\n if (root.id === maybeNodeId) return true;\n return root.children.some((child) => isNodeInSubtree(child, maybeNodeId));\n }\n\n function getDraggedComponentName(state: { sourceNodeId: number | null; sourceComponentName: string | null }): string | null {\n if (state.sourceComponentName) return state.sourceComponentName;\n if (state.sourceNodeId === null) return null;\n return findNodeById(props.content, state.sourceNodeId)?.name ?? null;\n }\n\n function resolveDropLocation(\n targetNodeId: number | null,\n state: { sourceNodeId: number | null; sourceComponentName: string | null },\n ): DropLocation | null {\n const sourceName = getDraggedComponentName(state);\n if (!sourceName) return null;\n\n const targetNode = targetNodeId === null ? null : findNodeById(props.content, targetNodeId);\n if (targetNode && !targetNode.readonly) {\n const directSlot = normalizeDropSlot(targetNode, 'default', sourceName);\n if (directSlot) {\n return {\n targetId: targetNode.id,\n index: targetNode.children.length,\n slot: directSlot,\n };\n }\n }\n\n if (targetNodeId !== null) {\n const parentResult = findParent(props.content, targetNodeId);\n if (parentResult && !parentResult.parent.readonly) {\n const targetChild = parentResult.parent.children[parentResult.index];\n const slot = normalizeDropSlot(parentResult.parent, targetChild?.slot ?? 'default', sourceName);\n if (slot) {\n return {\n targetId: parentResult.parent.id,\n index: parentResult.index + 1,\n slot,\n };\n }\n }\n }\n\n if (props.content.readonly) return null;\n const rootSlot = normalizeDropSlot(props.content, 'default', sourceName);\n if (!rootSlot) return null;\n\n return {\n targetId: props.content.id,\n index: props.content.children.length,\n slot: rootSlot,\n };\n }\n\n function canMoveNode(\n sourceNodeId: number,\n targetId: number,\n slot: string,\n proposedIndex: number,\n ): { valid: true; index: number; slot: string } | { valid: false } {\n const sourceNode = findNodeById(props.content, sourceNodeId);\n const sourceParentResult = findParent(props.content, sourceNodeId);\n const targetNode = findNodeById(props.content, targetId);\n\n if (!sourceNode || !sourceParentResult || sourceNode.readonly) return { valid: false };\n if (!targetNode || targetNode.readonly) return { valid: false };\n if (sourceNodeId === targetId) return { valid: false };\n if (isNodeInSubtree(sourceNode, targetId)) return { valid: false };\n\n const normalizedSlot = normalizeDropSlot(targetNode, slot, sourceNode.name);\n if (!normalizedSlot) return { valid: false };\n\n const targetChildrenCount = targetNode.children.length;\n if (sourceParentResult.parent.id === targetId && sourceParentResult.index < proposedIndex) {\n return { valid: true, index: clampIndex(proposedIndex - 1, targetChildrenCount), slot: normalizedSlot };\n }\n\n return { valid: true, index: clampIndex(proposedIndex, targetChildrenCount), slot: normalizedSlot };\n }\n\n function ensureIframeBaseStyle(doc: Document) {\n if (doc.getElementById(IFRAME_BASE_STYLE_ID)) return;\n const styleEl = doc.createElement('style');\n styleEl.id = IFRAME_BASE_STYLE_ID;\n styleEl.textContent = `\n html, body {\n margin: 0;\n padding: 0;\n min-height: 100%;\n overflow-x: hidden;\n }\n\n body {\n background: #fff;\n }\n\n #${IFRAME_CONTENT_ROOT_ID} {\n position: relative;\n width: 100%;\n max-width: 100%;\n min-height: 100%;\n overflow-x: hidden;\n box-sizing: border-box;\n }\n\n /* Minimum size for layout containers so empty columns/rows remain droppable in the editor */\n [data-ipb-component=\"PbColumn\"] {\n min-width: 80px;\n min-height: 80px;\n }\n [data-ipb-component=\"PbRow\"] {\n min-height: 80px;\n }\n\n [data-ipb-readonly=\"true\"] {\n opacity: 0.6;\n user-select: none;\n }\n `;\n doc.head.appendChild(styleEl);\n }\n\n function ensureIframeContentRoot(doc: Document): HTMLElement | null {\n if (!doc.body) return null;\n ensureIframeBaseStyle(doc);\n\n let root = doc.getElementById(IFRAME_CONTENT_ROOT_ID) as HTMLElement | null;\n if (!root) {\n root = doc.createElement('div');\n root.id = IFRAME_CONTENT_ROOT_ID;\n doc.body.innerHTML = '';\n doc.body.appendChild(root);\n }\n return root;\n }\n\n function renderIframeNodeTree() {\n if (!contentRef.value) return;\n\n const rootNode = props.layout\n ? mergeLayoutAndContent(props.layout, props.content)\n : props.content;\n\n render(\n h(NodeRenderer, {\n node: rootNode,\n variables: props.variables,\n markNodes: true,\n }),\n contentRef.value,\n );\n }\n\n function unmountIframeNodeTree() {\n if (!contentRef.value) return;\n render(null, contentRef.value);\n }\n\n function syncDraggableMarkers() {\n if (!contentRef.value) return;\n\n const markers = contentRef.value.querySelectorAll<HTMLElement>('[data-ipb-node-id]');\n markers.forEach((element) => {\n const nodeId = parseNodeId(element.getAttribute('data-ipb-node-id'));\n const node = nodeId === null ? null : findNodeById(props.content, nodeId);\n element.draggable = Boolean(node && !node.readonly && node.id !== props.content.id);\n });\n }\n\n function syncOverlayRects() {\n selectedRect.value = getOverlayRect(findMarkedElement(props.selectedNodeId));\n hoveredRect.value = getOverlayRect(findMarkedElement(props.hoveredNodeId));\n const dropTargetId = dragDrop ? dragDrop.dragState.value.dropTargetId : null;\n dropRect.value = dropTargetId === null ? null : getOverlayRect(findMarkedElement(dropTargetId));\n }\n\n function getStageViewportSize(): IViewportSize {\n if (stageRef.value) {\n return {\n width: Math.round(stageRef.value.clientWidth),\n height: Math.round(stageRef.value.clientHeight),\n };\n }\n\n return {\n width: 0,\n height: 0,\n };\n }\n\n function syncViewportSize() {\n const nextSize = getStageViewportSize();\n if (\n hasViewportSizeReport.value &&\n nextSize.width === currentViewportSize.value.width &&\n nextSize.height === currentViewportSize.value.height\n ) {\n return;\n }\n\n currentViewportSize.value = nextSize;\n hasViewportSizeReport.value = true;\n emit('viewport-size-change', nextSize);\n }\n\n function handleCanvasResize() {\n syncOverlayRects();\n syncViewportSize();\n }\n\n function disconnectResizeObserver() {\n resizeObserverRef.value?.disconnect();\n resizeObserverRef.value = null;\n }\n\n function setupResizeObserver() {\n disconnectResizeObserver();\n if (typeof ResizeObserver === 'undefined') return;\n if (!stageRef.value || !contentRef.value) return;\n\n const observer = new ResizeObserver(() => {\n handleCanvasResize();\n });\n\n observer.observe(stageRef.value);\n observer.observe(contentRef.value);\n\n resizeObserverRef.value = observer;\n }\n\n async function syncOverlayRectsAfterRender() {\n await nextTick();\n renderIframeNodeTree();\n await nextTick();\n syncDraggableMarkers();\n syncOverlayRects();\n syncViewportSize();\n }\n\n function clearDropTargetOverlay() {\n dropRect.value = null;\n }\n\n function hideContextMenu() {\n contextMenuOpen.value = false;\n contextMenuNodeId.value = null;\n }\n\n function handleCanvasClick() {\n hideContextMenu();\n emit('select', null);\n emit('hover', null);\n }\n\n function handleContentClick(event: MouseEvent) {\n event.stopPropagation();\n hideContextMenu();\n const nodeId = getNodeIdFromEventTarget(event.target);\n if (nodeId !== null && !findNodeById(props.content, nodeId)) {\n emit('select', null);\n return;\n }\n emit('select', nodeId);\n }\n\n function handleContentMouseMove(event: MouseEvent) {\n const nodeId = getNodeIdFromEventTarget(event.target);\n if (nodeId !== null && !findNodeById(props.content, nodeId)) {\n if (props.hoveredNodeId !== null) emit('hover', null);\n return;\n }\n if (nodeId !== props.hoveredNodeId) {\n emit('hover', nodeId);\n }\n }\n\n function handleContentMouseLeave() {\n emit('hover', null);\n }\n\n function handleContentDragStart(event: DragEvent) {\n if (!dragDrop) return;\n const nodeId = getNodeIdFromEventTarget(event.target);\n if (nodeId === null) return;\n\n const node = findNodeById(props.content, nodeId);\n if (!node || node.readonly || node.id === props.content.id) {\n event.preventDefault();\n return;\n }\n\n dragDrop.startDragExisting(nodeId);\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = 'move';\n event.dataTransfer.setData('text/plain', String(nodeId));\n }\n }\n\n function handleContentDragOver(event: DragEvent) {\n if (!dragDrop || !dragDrop.dragState.value.isDragging) return;\n\n const targetNodeId = getNodeIdFromEventTarget(event.target);\n const location = resolveDropLocation(targetNodeId, dragDrop.dragState.value);\n if (!location) {\n clearDropTargetOverlay();\n return;\n }\n\n event.preventDefault();\n dragDrop.updateDropTarget(location.targetId, location.index, location.slot);\n dropRect.value = getOverlayRect(findMarkedElement(location.targetId));\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = dragDrop.dragState.value.isNewComponent ? 'copy' : 'move';\n }\n }\n\n function handleContentDragLeave(event: DragEvent) {\n if (!contentRef.value) return;\n const nextTarget = event.relatedTarget;\n if (nextTarget && typeof nextTarget === 'object' && 'nodeType' in nextTarget) {\n if (contentRef.value.contains(nextTarget as Node)) return;\n }\n clearDropTargetOverlay();\n }\n\n function handleContentDrop(event: DragEvent) {\n event.preventDefault();\n\n if (!dragDrop || !nodeTree || !dragDrop.dragState.value.isDragging) {\n clearDropTargetOverlay();\n return;\n }\n\n const targetNodeId = getNodeIdFromEventTarget(event.target);\n const location = resolveDropLocation(targetNodeId, dragDrop.dragState.value);\n if (!location) {\n dragDrop.cancelDrag();\n clearDropTargetOverlay();\n return;\n }\n\n dragDrop.updateDropTarget(location.targetId, location.index, location.slot);\n const finalState = dragDrop.endDrag();\n clearDropTargetOverlay();\n\n if (finalState.dropTargetId === null) return;\n\n if (finalState.isNewComponent && finalState.sourceComponentName) {\n const defaultProps = getComponent(finalState.sourceComponentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(\n finalState.dropTargetId,\n finalState.sourceComponentName,\n finalState.dropIndex,\n finalState.dropSlot,\n defaultProps,\n );\n if (newNodeId !== null) {\n emit('select', newNodeId);\n }\n return;\n }\n\n if (finalState.sourceNodeId === null) return;\n\n const moveResult = canMoveNode(\n finalState.sourceNodeId,\n finalState.dropTargetId,\n finalState.dropSlot,\n finalState.dropIndex,\n );\n if (!moveResult.valid) return;\n\n nodeTree.moveNodeTo(\n finalState.sourceNodeId,\n finalState.dropTargetId,\n moveResult.index,\n moveResult.slot,\n );\n emit('select', finalState.sourceNodeId);\n }\n\n function handleContentDragEnd() {\n if (dragDrop?.dragState.value.isDragging) {\n dragDrop.cancelDrag();\n }\n clearDropTargetOverlay();\n }\n\n function updateContextMenuCapabilities(nodeId: number) {\n const node = findNodeById(props.content, nodeId);\n if (node?.readonly) {\n canDeleteFromMenu.value = false;\n canMoveUpFromMenu.value = false;\n canMoveDownFromMenu.value = false;\n return;\n }\n\n const parentResult = findParent(props.content, nodeId);\n if (!parentResult) {\n canDeleteFromMenu.value = false;\n canMoveUpFromMenu.value = false;\n canMoveDownFromMenu.value = false;\n return;\n }\n\n canDeleteFromMenu.value = true;\n canMoveUpFromMenu.value = parentResult.index > 0;\n canMoveDownFromMenu.value = parentResult.index < parentResult.parent.children.length - 1;\n }\n\n function handleContentContextMenu(event: MouseEvent) {\n event.preventDefault();\n event.stopPropagation();\n const nodeId = getNodeIdFromEventTarget(event.target);\n if (nodeId === null || !contentRef.value || !findNodeById(props.content, nodeId)) {\n hideContextMenu();\n return;\n }\n\n const contentRect = contentRef.value.getBoundingClientRect();\n const frameScrollTop = iframeWindowRef.value?.scrollY ?? 0;\n const frameScrollLeft = iframeWindowRef.value?.scrollX ?? 0;\n contextMenuX.value = event.clientX - contentRect.left + frameScrollLeft;\n contextMenuY.value = event.clientY - contentRect.top + frameScrollTop;\n contextMenuNodeId.value = nodeId;\n updateContextMenuCapabilities(nodeId);\n contextMenuOpen.value = true;\n\n emit('select', nodeId);\n }\n\n function handleContextMenuAction(action: NodeContextMenuAction) {\n if (contextMenuNodeId.value === null) return;\n emit('context-action', { action, nodeId: contextMenuNodeId.value });\n hideContextMenu();\n }\n\n function isEditableTarget(target: EventTarget | null): boolean {\n if (!isElementTarget(target)) return false;\n const tagName = target.tagName.toLowerCase();\n if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') return true;\n return Boolean(target.closest('[contenteditable]:not([contenteditable=\"false\"])'));\n }\n\n function handleBridgePointer(payload: IframeBridgePointerPayload) {\n if (payload.interaction === 'hover') {\n if (payload.nodeId !== null && !findNodeById(props.content, payload.nodeId)) {\n if (props.hoveredNodeId !== null) emit('hover', null);\n return;\n }\n if (payload.nodeId !== props.hoveredNodeId) {\n emit('hover', payload.nodeId);\n }\n return;\n }\n\n if (payload.interaction === 'select') {\n hideContextMenu();\n if (payload.nodeId !== null && !findNodeById(props.content, payload.nodeId)) {\n emit('select', null);\n return;\n }\n emit('select', payload.nodeId);\n return;\n }\n\n if (payload.interaction !== 'context') return;\n\n if (payload.nodeId === null || !contentRef.value || !findNodeById(props.content, payload.nodeId)) {\n hideContextMenu();\n return;\n }\n\n const contentRect = contentRef.value.getBoundingClientRect();\n const frameScrollTop = iframeWindowRef.value?.scrollY ?? 0;\n const frameScrollLeft = iframeWindowRef.value?.scrollX ?? 0;\n contextMenuX.value = payload.clientX - contentRect.left + frameScrollLeft;\n contextMenuY.value = payload.clientY - contentRect.top + frameScrollTop;\n contextMenuNodeId.value = payload.nodeId;\n updateContextMenuCapabilities(payload.nodeId);\n contextMenuOpen.value = true;\n\n emit('select', payload.nodeId);\n }\n\n function handleBridgeKeydown(payload: IframeBridgeKeydownPayload) {\n if (payload.key === 'Escape') {\n hideContextMenu();\n }\n\n emit('iframe-keydown', {\n ...payload,\n // Preventing defaults from the parent is asynchronous in postMessage mode.\n preventDefault: () => {},\n });\n }\n\n function getWindowOrigin(targetWindow: Window): string {\n try {\n return targetWindow.location.origin;\n } catch {\n return window.location.origin;\n }\n }\n\n function teardownIframeBridge() {\n teardownBridgeParentRef.value?.();\n teardownBridgeParentRef.value = null;\n\n teardownBridgeDomRef.value?.();\n teardownBridgeDomRef.value = null;\n }\n\n function setupIframeBridge() {\n const frameWindow = iframeWindowRef.value;\n const frameDocument = iframeDocumentRef.value;\n const contentRoot = contentRef.value;\n if (!frameWindow || !frameDocument || !contentRoot) return;\n\n teardownIframeBridge();\n const sessionToken = createIframeBridgeSessionToken();\n\n const bridgeParent = createIframeBridgeParent({\n hostWindow: window,\n expectedSource: window,\n expectedOrigin: getWindowOrigin(window),\n expectedSessionToken: sessionToken,\n onReady: () => {\n void syncOverlayRectsAfterRender();\n },\n onPointer: handleBridgePointer,\n onKeydown: handleBridgeKeydown,\n });\n\n const bridgeChild = createIframeBridgeChild({\n targetWindow: window,\n targetOrigin: getWindowOrigin(window),\n sessionToken,\n });\n\n teardownBridgeParentRef.value = () => bridgeParent.dispose();\n teardownBridgeDomRef.value = mountIframeBridgeDomListeners({\n frameDocument,\n contentRoot,\n bridge: bridgeChild,\n resolveNodeId: getNodeIdFromEventTarget,\n isEditableTarget,\n });\n }\n\n function handleWindowResize() {\n handleCanvasResize();\n }\n\n function teardownIframeListeners() {\n disconnectResizeObserver();\n teardownIframeBridge();\n\n if (contentRef.value) {\n contentRef.value.removeEventListener('click', handleContentClick);\n contentRef.value.removeEventListener('contextmenu', handleContentContextMenu);\n contentRef.value.removeEventListener('mousemove', handleContentMouseMove);\n contentRef.value.removeEventListener('mouseleave', handleContentMouseLeave);\n contentRef.value.removeEventListener('dragstart', handleContentDragStart);\n contentRef.value.removeEventListener('dragover', handleContentDragOver);\n contentRef.value.removeEventListener('dragleave', handleContentDragLeave);\n contentRef.value.removeEventListener('drop', handleContentDrop);\n contentRef.value.removeEventListener('dragend', handleContentDragEnd);\n }\n\n if (!useFallbackDom.value && iframeWindowRef.value) {\n iframeWindowRef.value.removeEventListener('scroll', handleWindowResize);\n iframeWindowRef.value.removeEventListener('resize', handleWindowResize);\n }\n }\n\n function setupIframeListeners() {\n if (!contentRef.value) return;\n\n if (useFallbackDom.value) {\n contentRef.value.addEventListener('click', handleContentClick);\n contentRef.value.addEventListener('contextmenu', handleContentContextMenu);\n contentRef.value.addEventListener('mousemove', handleContentMouseMove);\n contentRef.value.addEventListener('mouseleave', handleContentMouseLeave);\n } else {\n setupIframeBridge();\n }\n\n contentRef.value.addEventListener('dragstart', handleContentDragStart);\n contentRef.value.addEventListener('dragover', handleContentDragOver);\n contentRef.value.addEventListener('dragleave', handleContentDragLeave);\n contentRef.value.addEventListener('drop', handleContentDrop);\n contentRef.value.addEventListener('dragend', handleContentDragEnd);\n\n if (!useFallbackDom.value && iframeWindowRef.value) {\n iframeWindowRef.value.addEventListener('scroll', handleWindowResize);\n iframeWindowRef.value.addEventListener('resize', handleWindowResize);\n }\n\n setupResizeObserver();\n }\n\n function initializeFallbackContent() {\n useFallbackDom.value = true;\n void nextTick().then(() => {\n if (!fallbackContentRef.value) return;\n\n teardownIframeListeners();\n unmountIframeNodeTree();\n\n iframeDocumentRef.value = null;\n iframeWindowRef.value = null;\n contentRef.value = fallbackContentRef.value;\n\n setupIframeListeners();\n void syncOverlayRectsAfterRender();\n });\n }\n\n function initializeIframeDocument() {\n const iframe = iframeRef.value;\n if (!iframe) {\n initializeFallbackContent();\n return;\n }\n\n const frameDocument = iframe.contentDocument;\n const frameWindow = iframe.contentWindow;\n if (!frameDocument || !frameWindow) {\n initializeFallbackContent();\n return;\n }\n\n const frameRoot = ensureIframeContentRoot(frameDocument);\n if (!frameRoot) {\n initializeFallbackContent();\n return;\n }\n\n teardownIframeListeners();\n unmountIframeNodeTree();\n\n useFallbackDom.value = false;\n iframeDocumentRef.value = frameDocument;\n iframeWindowRef.value = frameWindow;\n contentRef.value = frameRoot;\n\n setupIframeListeners();\n void syncOverlayRectsAfterRender();\n }\n\n watch(\n () => [props.selectedNodeId, props.hoveredNodeId],\n () => {\n void syncOverlayRectsAfterRender();\n },\n { immediate: true },\n );\n\n watch(\n () => [props.viewport, props.viewportWidth, props.viewportHeight],\n () => {\n void syncOverlayRectsAfterRender();\n },\n );\n\n watch(\n () => props.content,\n () => {\n if (contextMenuNodeId.value !== null && !findNodeById(props.content, contextMenuNodeId.value)) {\n hideContextMenu();\n }\n void syncOverlayRectsAfterRender();\n },\n { deep: true },\n );\n\n watch(\n () => props.variables,\n () => {\n void syncOverlayRectsAfterRender();\n },\n { deep: true },\n );\n\n watch(\n () => props.layout,\n () => {\n void syncOverlayRectsAfterRender();\n },\n { deep: true },\n );\n\n watch(\n () => dragDrop?.dragState.value.isDragging ?? false,\n (isDragging) => {\n if (!isDragging) {\n clearDropTargetOverlay();\n }\n },\n );\n\n onMounted(() => {\n window.addEventListener('resize', handleWindowResize);\n iframeRef.value?.addEventListener('load', initializeIframeDocument);\n initializeIframeDocument();\n });\n\n onBeforeUnmount(() => {\n window.removeEventListener('resize', handleWindowResize);\n iframeRef.value?.removeEventListener('load', initializeIframeDocument);\n teardownIframeListeners();\n unmountIframeNodeTree();\n });\n</script>\n\n<template>\n <main class=\"ipb-canvas\" @click=\"handleCanvasClick\" @contextmenu.prevent=\"hideContextMenu\">\n <div class=\"ipb-canvas__viewport\" :style=\"canvasStyle\">\n <div ref=\"stageRef\" class=\"ipb-iframe-canvas__stage\">\n <iframe\n v-if=\"!useFallbackDom\"\n ref=\"iframeRef\"\n class=\"ipb-iframe-canvas__frame\"\n :title=\"t('iframeCanvas.title')\"\n sandbox=\"allow-same-origin\"\n />\n <div\n v-else\n ref=\"fallbackContentRef\"\n id=\"ipb-iframe-canvas-content\"\n class=\"ipb-iframe-canvas__fallback\"\n />\n <div\n v-if=\"dropOverlayStyle\"\n class=\"ipb-canvas__overlay ipb-canvas__overlay--drop\"\n :style=\"dropOverlayStyle\"\n />\n <div\n v-if=\"hoveredOverlayStyle\"\n class=\"ipb-canvas__overlay ipb-canvas__overlay--hovered\"\n :style=\"hoveredOverlayStyle\"\n />\n <div\n v-if=\"selectedOverlayStyle\"\n class=\"ipb-canvas__overlay ipb-canvas__overlay--selected\"\n :style=\"selectedOverlayStyle\"\n />\n <NodeContextMenu\n :open=\"contextMenuOpen\"\n :x=\"contextMenuX\"\n :y=\"contextMenuY\"\n :can-delete=\"canDeleteFromMenu\"\n :can-move-up=\"canMoveUpFromMenu\"\n :can-move-down=\"canMoveDownFromMenu\"\n @action=\"handleContextMenuAction\"\n @close=\"hideContextMenu\"\n />\n </div>\n </div>\n </main>\n</template>\n\n<style scoped>\n .ipb-canvas {\n flex: 1;\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding: 24px;\n overflow: auto;\n background: var(--ipb-canvas-bg, #e5e7eb);\n }\n\n .ipb-canvas__viewport {\n position: relative;\n flex: 0 0 auto;\n background: #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.06);\n border-radius: 4px;\n overflow: hidden;\n transition: width 0.2s ease, height 0.2s ease;\n }\n\n .ipb-iframe-canvas__stage {\n position: relative;\n width: 100%;\n height: 100%;\n background: #fff;\n }\n\n .ipb-iframe-canvas__frame {\n width: 100%;\n height: 100%;\n border: 0;\n display: block;\n background: #fff;\n }\n\n .ipb-iframe-canvas__fallback {\n position: relative;\n width: 100%;\n height: 100%;\n background: #fff;\n }\n\n .ipb-canvas__overlay {\n position: absolute;\n pointer-events: none;\n border-radius: 4px;\n box-sizing: border-box;\n }\n\n .ipb-canvas__overlay--hovered {\n border: 1px dashed rgba(59, 130, 246, 0.75);\n background: rgba(59, 130, 246, 0.08);\n z-index: 10;\n }\n\n .ipb-canvas__overlay--drop {\n border: 2px dashed rgba(16, 185, 129, 0.9);\n background: rgba(16, 185, 129, 0.14);\n z-index: 12;\n }\n\n .ipb-canvas__overlay--selected {\n border: 2px solid rgba(37, 99, 235, 0.95);\n background: rgba(37, 99, 235, 0.14);\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.85) inset;\n z-index: 11;\n }\n</style>\n","<script setup lang=\"ts\">\n import { provide, onMounted, onUnmounted, ref, type PropType } from 'vue';\n import type { IPageData, INode, IPageSavePayload } from '@/types/node';\n import type { IViewportSize, ViewportPreset } from '@/types/editor';\n import { VIEWPORT_PRESETS } from '@/types/editor';\n import { findNodeById, findParent } from '@/core/tree';\n import { getComponent } from '@/core/registry';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import { PAGE_BUILDER_KEY, EDITOR_KEY, NODE_TREE_KEY, DRAG_DROP_KEY } from '@/types/keys';\n import { usePageBuilder } from '@/composables/use-page-builder';\n import { useEditor } from '@/composables/use-editor';\n import { useNodeTree } from '@/composables/use-node-tree';\n import { useDragDrop } from '@/composables/use-drag-drop';\n import EditorToolbar from './EditorToolbar.vue';\n import LeftDrawer from './LeftDrawer.vue';\n import RightDrawer from './RightDrawer.vue';\n import IframeCanvas from './IframeCanvas.vue';\n import type { NodeContextMenuAction } from './NodeContextMenu.vue';\n interface CanvasShortcutPayload {\n key: string;\n code: string;\n ctrlKey: boolean;\n metaKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n defaultPrevented: boolean;\n isEditable: boolean;\n preventDefault: () => void;\n }\n\n\n const props = defineProps({\n pageData: {\n type: Object as PropType<IPageData>,\n required: true,\n },\n });\n\n const emit = defineEmits<{\n save: [payload: IPageSavePayload];\n change: [tree: INode];\n }>();\n\n const pb = usePageBuilder({ initialData: props.pageData, mode: 'edit' });\n const editor = useEditor({ initialSnapshot: pb.getSnapshot() });\n const dragDrop = useDragDrop();\n\n const nodeTree = useNodeTree({\n content: pb.content,\n nextId: pb.nextId,\n onUpdate: (newContent) => {\n pb.updateContent(newContent);\n emit('change', newContent);\n },\n onSnapshot: (label) => {\n editor.pushHistory(label, pb.getSnapshot());\n },\n });\n\n const customViewportWidth = ref(1024);\n const customViewportHeight = ref(768);\n const activeViewportWidth = ref<number | null>(null);\n const activeViewportHeight = ref<number | null>(null);\n\n function handleSave() {\n emit('save', {\n content: pb.content.value,\n layout: pb.layout.value,\n maxId: pb.maxId.value,\n });\n }\n\n function restoreSnapshotAndEmit(snapshot: string | undefined): boolean {\n if (!snapshot) return false;\n try {\n pb.restoreSnapshot(snapshot);\n const selectedNodeId = editor.selectedNodeId.value;\n if (selectedNodeId !== null && !findNodeById(pb.content.value, selectedNodeId)) {\n editor.selectNode(null);\n }\n emit('change', pb.content.value);\n return true;\n } catch (error) {\n reportDevDiagnostic(\n 'PageEditor.restoreSnapshotAndEmit',\n createPageBuilderError(\n 'INVALID_SNAPSHOT',\n '[PageBuilder] Failed to apply history snapshot. Undo/redo step was skipped.',\n {\n cause: error,\n details: {\n snapshotPreview: snapshot.slice(0, 200),\n },\n },\n ),\n );\n return false;\n }\n }\n\n function handleUndo() {\n restoreSnapshotAndEmit(editor.undo());\n }\n\n function handleRedo() {\n restoreSnapshotAndEmit(editor.redo());\n }\n\n function handleDeleteNode(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node || node.readonly) return;\n nodeTree.deleteNode(nodeId);\n }\n\n function handleDuplicateNode(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node) return;\n nodeTree.duplicateNode(nodeId);\n }\n\n function handleMoveNodeUp(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node || node.readonly) return;\n if (!nodeTree.canMoveNodeUp(nodeId)) return;\n nodeTree.moveNodeUp(nodeId);\n }\n\n function handleMoveNodeDown(nodeId: number) {\n const node = findNodeById(pb.content.value, nodeId);\n if (!node || node.readonly) return;\n if (!nodeTree.canMoveNodeDown(nodeId)) return;\n nodeTree.moveNodeDown(nodeId);\n }\n\n function handleNodeContextAction(payload: { action: NodeContextMenuAction; nodeId: number }) {\n if (payload.action === 'duplicate') {\n handleDuplicateNode(payload.nodeId);\n return;\n }\n\n if (payload.action === 'delete') {\n handleDeleteNode(payload.nodeId);\n return;\n }\n\n if (payload.action === 'move-up') {\n handleMoveNodeUp(payload.nodeId);\n return;\n }\n\n if (payload.action === 'move-down') {\n handleMoveNodeDown(payload.nodeId);\n }\n }\n\n function isEditableTarget(target: EventTarget | null): boolean {\n if (!target || typeof target !== 'object') return false;\n if (!('nodeType' in target) || (target as { nodeType?: number }).nodeType !== 1) return false;\n const element = target as Element;\n const tagName = element.tagName.toLowerCase();\n if (tagName === 'input' || tagName === 'textarea' || tagName === 'select') return true;\n return Boolean(element.closest('[contenteditable]:not([contenteditable=\"false\"])'));\n }\n\n function handleDeleteSelected() {\n const selectedNodeId = editor.selectedNodeId.value;\n if (selectedNodeId === null) return;\n handleDeleteNode(selectedNodeId);\n }\n\n function handleShortcut(payload: CanvasShortcutPayload) {\n if (payload.defaultPrevented || payload.isEditable) return;\n\n const hasModifier = payload.ctrlKey || payload.metaKey;\n const key = payload.key.toLowerCase();\n const code = payload.code.toLowerCase();\n\n if (hasModifier && key === 'z') {\n payload.preventDefault();\n if (payload.shiftKey) {\n handleRedo();\n } else {\n handleUndo();\n }\n return;\n }\n\n if (hasModifier && key === 'y') {\n payload.preventDefault();\n handleRedo();\n return;\n }\n\n if (hasModifier && key === 's') {\n payload.preventDefault();\n handleSave();\n return;\n }\n\n const isDeleteKey = key === 'delete' || key === 'backspace' || code === 'delete' || code === 'backspace';\n if (isDeleteKey && !payload.ctrlKey && !payload.metaKey && !payload.altKey) {\n payload.preventDefault();\n handleDeleteSelected();\n }\n }\n\n function handleEditorKeydown(event: KeyboardEvent) {\n handleShortcut({\n key: event.key,\n code: event.code,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n shiftKey: event.shiftKey,\n altKey: event.altKey,\n defaultPrevented: event.defaultPrevented,\n isEditable: isEditableTarget(event.target) || isEditableTarget(document.activeElement),\n preventDefault: () => event.preventDefault(),\n });\n }\n\n function handleIframeKeydown(payload: CanvasShortcutPayload) {\n handleShortcut(payload);\n }\n\n function getViewportDimensions(preset: ViewportPreset): IViewportSize {\n const dimensions = VIEWPORT_PRESETS[preset];\n if (preset === 'custom') {\n return {\n width: customViewportWidth.value,\n height: customViewportHeight.value,\n };\n }\n\n return {\n width: dimensions.width,\n height: dimensions.height,\n };\n }\n\n function handleViewportChange(preset: ViewportPreset) {\n if (preset === 'custom' && editor.viewport.value !== 'custom') {\n if (activeViewportWidth.value !== null && activeViewportHeight.value !== null) {\n customViewportWidth.value = activeViewportWidth.value;\n customViewportHeight.value = activeViewportHeight.value;\n } else {\n const currentViewport = getViewportDimensions(editor.viewport.value);\n customViewportWidth.value = currentViewport.width;\n customViewportHeight.value = currentViewport.height;\n }\n }\n editor.setViewport(preset);\n }\n\n function handleCustomViewportChange(payload: IViewportSize) {\n customViewportWidth.value = payload.width;\n customViewportHeight.value = payload.height;\n if (editor.viewport.value !== 'custom') {\n editor.setViewport('custom');\n }\n }\n\n function handleViewportSizeChange(payload: IViewportSize) {\n activeViewportWidth.value = payload.width;\n activeViewportHeight.value = payload.height;\n }\n\n function handlePaletteDragStart(componentName: string) {\n dragDrop.startDragNew(componentName);\n }\n\n function handlePaletteDragEnd() {\n dragDrop.cancelDrag();\n }\n\n function handlePaletteAdd(componentName: string) {\n const selectedNodeId = editor.selectedNodeId.value;\n const selectedNode = selectedNodeId !== null ? findNodeById(pb.content.value, selectedNodeId) : undefined;\n\n let parentId = pb.content.value.id;\n let index = pb.content.value.children.length;\n let slot = 'default';\n\n if (selectedNodeId !== null && selectedNode) {\n const parentResult = findParent(pb.content.value, selectedNodeId);\n if (parentResult) {\n parentId = parentResult.parent.id;\n index = parentResult.index + 1;\n slot = selectedNode.slot ?? 'default';\n } else {\n // Selected root node: append into root children.\n parentId = selectedNode.id;\n index = selectedNode.children.length;\n }\n }\n\n const defaultProps = getComponent(componentName)?.defaultProps;\n const newNodeId = nodeTree.addNode(parentId, componentName, index, slot, defaultProps);\n if (newNodeId !== null) {\n editor.selectNode(newNodeId);\n }\n }\n\n onMounted(() => {\n window.addEventListener('keydown', handleEditorKeydown);\n });\n\n onUnmounted(() => {\n window.removeEventListener('keydown', handleEditorKeydown);\n });\n\n provide(PAGE_BUILDER_KEY, pb);\n provide(EDITOR_KEY, editor);\n provide(NODE_TREE_KEY, nodeTree);\n provide(DRAG_DROP_KEY, dragDrop);\n</script>\n\n<template>\n <div class=\"ipb-page-editor\">\n <EditorToolbar\n :can-undo=\"editor.canUndo.value\"\n :can-redo=\"editor.canRedo.value\"\n :is-dirty=\"pb.isDirty.value\"\n :viewport=\"editor.viewport.value\"\n :custom-viewport-width=\"customViewportWidth\"\n :custom-viewport-height=\"customViewportHeight\"\n :active-viewport-width=\"activeViewportWidth\"\n :active-viewport-height=\"activeViewportHeight\"\n @undo=\"handleUndo\"\n @redo=\"handleRedo\"\n @save=\"handleSave\"\n @viewport-change=\"handleViewportChange\"\n @custom-viewport-change=\"handleCustomViewportChange\"\n />\n\n <div class=\"ipb-page-editor__body\">\n <LeftDrawer\n :open=\"editor.leftDrawerOpen.value\"\n :content=\"pb.content.value\"\n :selected-node-id=\"editor.selectedNodeId.value\"\n @toggle=\"editor.toggleLeftDrawer\"\n @select=\"editor.selectNode\"\n @add=\"handlePaletteAdd\"\n @drag-start=\"handlePaletteDragStart\"\n @drag-end=\"handlePaletteDragEnd\"\n />\n\n <IframeCanvas\n :content=\"pb.content.value\"\n :layout=\"pb.layout.value\"\n :variables=\"pb.variables.value\"\n :selected-node-id=\"editor.selectedNodeId.value\"\n :hovered-node-id=\"editor.hoveredNodeId.value\"\n :viewport=\"editor.viewport.value\"\n :viewport-width=\"editor.viewport.value === 'custom' ? customViewportWidth : null\"\n :viewport-height=\"editor.viewport.value === 'custom' ? customViewportHeight : null\"\n @select=\"editor.selectNode\"\n @hover=\"editor.hoverNode\"\n @context-action=\"handleNodeContextAction\"\n @iframe-keydown=\"handleIframeKeydown\"\n @viewport-size-change=\"handleViewportSizeChange\"\n />\n\n <RightDrawer\n :open=\"editor.rightDrawerOpen.value\"\n :selected-node-id=\"editor.selectedNodeId.value\"\n :content=\"pb.content.value\"\n @toggle=\"editor.toggleRightDrawer\"\n @update-props=\"nodeTree.updateNodeProps\"\n @delete=\"handleDeleteNode\"\n @duplicate=\"handleDuplicateNode\"\n />\n </div>\n </div>\n</template>\n\n<style scoped>\n .ipb-page-editor {\n display: flex;\n flex-direction: column;\n height: 100vh;\n width: 100vw;\n overflow: hidden;\n background: var(--ipb-editor-bg, #f0f2f5);\n }\n\n .ipb-page-editor__body {\n display: flex;\n flex: 1;\n overflow: hidden;\n }\n</style>\n","<script setup lang=\"ts\">\n import { computed, inject, provide, type PropType, watch } from 'vue';\n import type { IPageData, INode, IPageSavePayload } from '@/types/node';\n import type { PageBuilderMode } from '@/types/editor';\n import { validateNode, validatePageData } from '@/core/validation';\n import { createPageBuilderError, reportDevDiagnostic } from '@/core/errors';\n import {\n DEFAULT_LOCALE,\n PAGE_BUILDER_I18N_KEY,\n PAGE_BUILDER_I18N_OPTIONS_KEY,\n createTranslator,\n defaultTranslations,\n mergeTranslations,\n type TranslationDictionary,\n } from '@/i18n';\n import PageReader from './reader/PageReader.vue';\n import PageEditor from './editor/PageEditor.vue';\n\n const props = defineProps({\n pageData: {\n type: Object as PropType<IPageData>,\n required: true,\n },\n mode: {\n type: String as PropType<PageBuilderMode>,\n default: 'read',\n },\n locale: {\n type: String,\n default: undefined,\n },\n messages: {\n type: Object as PropType<TranslationDictionary>,\n default: undefined,\n },\n });\n\n const reportedDiagnostics = new Set<string>();\n\n function reportOnce(key: string, message: string, details?: Record<string, unknown>) {\n if (reportedDiagnostics.has(key)) return;\n reportedDiagnostics.add(key);\n reportDevDiagnostic('PageBuilder', createPageBuilderError('INVALID_PAGE_DATA', message, { details }));\n }\n\n const pageData = computed(() => props.pageData);\n const mode = computed<PageBuilderMode>(() => {\n if (props.mode === 'read' || props.mode === 'edit') return props.mode;\n reportOnce(\n 'invalid-mode',\n `[PageBuilder] Unknown mode \"${String(props.mode)}\". Falling back to \"read\".`,\n { mode: props.mode },\n );\n return 'read';\n });\n\n const pageValidationResult = computed(() => validatePageData(pageData.value));\n const canRenderEditor = computed(() => {\n const contentResult = validateNode(pageData.value.content, 'content');\n const layoutResult = validateNode(pageData.value.layout, 'layout');\n return contentResult.isValid && layoutResult.isValid;\n });\n const showEditModeFallback = computed(() => mode.value === 'edit' && !canRenderEditor.value);\n const pluginI18nOptions = inject(PAGE_BUILDER_I18N_OPTIONS_KEY, null);\n const resolvedLocale = computed(() => props.locale ?? pluginI18nOptions?.locale ?? DEFAULT_LOCALE);\n const mergedMessages = computed(() =>\n mergeTranslations(defaultTranslations, pluginI18nOptions?.messages, props.messages),\n );\n const t = createTranslator(() => resolvedLocale.value, () => mergedMessages.value);\n\n watch(\n pageValidationResult,\n (result) => {\n if (result.isValid) return;\n reportOnce(\n 'invalid-page-data',\n '[PageBuilder] Invalid pageData payload detected. Rendering continues with degraded behavior.',\n { errors: result.errors },\n );\n },\n { immediate: true },\n );\n\n defineEmits<{\n save: [payload: IPageSavePayload];\n change: [tree: INode];\n }>();\n\n provide(PAGE_BUILDER_I18N_KEY, {\n locale: resolvedLocale,\n t,\n });\n</script>\n\n<template>\n <div v-if=\"showEditModeFallback\" class=\"ipb-page-builder__warning\" role=\"alert\">\n {{ t('pageBuilder.warning.invalidEditMode') }}\n </div>\n <PageReader v-if=\"mode === 'read' || showEditModeFallback\" :page-data=\"pageData\" />\n <PageEditor\n v-else\n :page-data=\"pageData\"\n @save=\"$emit('save', $event)\"\n @change=\"$emit('change', $event)\"\n />\n</template>\n\n<style scoped>\n .ipb-page-builder__warning {\n margin-bottom: 0.5rem;\n padding: 0.625rem 0.75rem;\n border: 1px solid #f8d7a8;\n border-radius: 0.375rem;\n background-color: #fff8ec;\n color: #7d4a00;\n font-size: 0.875rem;\n }\n</style>\n","import type { App } from 'vue';\nimport type { IComponentDefinition } from '@/types/component';\nimport { getComponent, registerComponents } from '@/core/registry';\nimport { createPageBuilderError } from '@/core/errors';\nimport { builtInComponents } from '@/built-in';\nimport PageBuilder from '@/components/PageBuilder.vue';\nimport { PAGE_BUILDER_I18N_OPTIONS_KEY, type TranslationDictionary } from '@/i18n';\n\nexport interface PageBuilderPluginOptions {\n /** Custom components to register in addition to built-in ones. */\n components?: IComponentDefinition[];\n\n /** If false, built-in components (PbColumn, PbRow, etc.) won't be registered. Default: true. */\n registerBuiltIn?: boolean;\n\n /** Global component name for <PageBuilder>. Default: 'PageBuilder'. Set to false to skip global registration. */\n globalName?: string | false;\n\n /** Default locale for editor UI text. Can be overridden per <PageBuilder> instance. */\n locale?: string;\n\n /** Additional/overridden translation messages grouped by locale. */\n messages?: TranslationDictionary;\n}\n\nconst INSTALLED_APPS = new WeakSet<App>();\n\nfunction registerComponentsIdempotently(definitions: IComponentDefinition[]): void {\n const pendingDefinitions: IComponentDefinition[] = [];\n\n for (const definition of definitions) {\n const normalizedName = definition.name.trim();\n const existing = getComponent(normalizedName);\n if (!existing) {\n pendingDefinitions.push(definition);\n continue;\n }\n\n if (existing.component !== definition.component) {\n throw createPageBuilderError(\n 'DUPLICATE_COMPONENT',\n `[PageBuilder] Component \"${normalizedName}\" is already registered with a different implementation.`,\n {\n details: {\n componentName: normalizedName,\n },\n },\n );\n }\n }\n\n if (pendingDefinitions.length > 0) {\n registerComponents(pendingDefinitions);\n }\n}\n\nexport const PageBuilderPlugin = {\n install(app: App, options: PageBuilderPluginOptions = {}) {\n if (INSTALLED_APPS.has(app)) return;\n INSTALLED_APPS.add(app);\n\n const {\n components = [],\n registerBuiltIn = true,\n globalName = 'PageBuilder',\n locale,\n messages,\n } = options;\n\n app.provide(PAGE_BUILDER_I18N_OPTIONS_KEY, { locale, messages });\n\n if (registerBuiltIn) {\n registerComponentsIdempotently(builtInComponents);\n }\n\n if (components.length > 0) {\n registerComponentsIdempotently(components);\n }\n\n if (globalName !== false) {\n app.component(globalName, PageBuilder);\n }\n },\n};\n","import type { Component, PropType } from 'vue';\n\n/**\n * Metadata describing a page builder component.\n * Every component registered in the page builder must provide this.\n */\nexport interface IComponentDefinition {\n /** Unique name used as key in the registry and in INode.name. */\n name: string;\n\n /** Human-readable label shown in the editor palette. */\n label: string;\n\n /** Short description for the editor tooltip. */\n description?: string;\n\n /** Category for grouping in the component palette. */\n category: ComponentCategory;\n\n /** URL or import path of a preview icon/thumbnail for the palette. */\n icon?: string;\n\n /** The Vue component to render. */\n component: Component;\n\n /** Named slots this component exposes for child nodes. */\n slots: ISlotDefinition[];\n\n /** Editable props schema for the right-drawer property editor. */\n editableProps: IPropDefinition[];\n\n /** Default props applied when the component is first added. */\n defaultProps?: Record<string, unknown>;\n\n /** If true, this component cannot be added by users (used for internal wrappers). */\n hidden?: boolean;\n}\n\nexport type ComponentCategory =\n | 'layout'\n | 'content'\n | 'media'\n | 'navigation'\n | 'form'\n | 'data'\n | 'custom';\n\nexport interface ISlotDefinition {\n /** Slot name matching Vue's named slot system. */\n name: string;\n\n /** Human-readable label. */\n label: string;\n\n /** Component names allowed in this slot. Empty array = all allowed. */\n allowedComponents?: string[];\n}\n\nexport interface IPropDefinition {\n /** Prop key (matches the component prop name). */\n key: string;\n\n /** Human-readable label for the property editor. */\n label: string;\n\n /** Editor widget type. */\n type: PropEditorType;\n\n /** Default value. */\n defaultValue?: unknown;\n\n /** Whether this prop is required. */\n required?: boolean;\n\n /** For 'select' type — available options. */\n options?: { label: string; value: string | number | boolean }[];\n\n /** Validation rules. */\n validation?: {\n min?: number;\n max?: number;\n pattern?: string;\n message?: string;\n };\n}\n\nexport type PropEditorType =\n | 'text'\n | 'textarea'\n | 'richtext'\n | 'number'\n | 'boolean'\n | 'select'\n | 'color'\n | 'image'\n | 'url'\n | 'json';\n\n/**\n * Vue prop type helper for builderOptions.\n * Components expose this as a static property so the registry can read it.\n */\nexport const builderOptionsPropType = {\n type: Object as PropType<IComponentDefinition>,\n};\n"],"names":["_registry","getRegistrySnapshot","names","normalizeComponentName","name","createDuplicateComponentError","message","createPageBuilderError","normalizeAndValidateDefinition","definition","action","normalizedName","normalizedDefinition","registerComponent","registerComponents","definitions","normalizedDefinitions","batchNames","replaceComponent","unregisterComponent","getComponent","resolveComponent","def","getRegisteredComponents","getComponentsByCategory","grouped","list","hasComponent","clearRegistry","builderOptions","props","__props","style","computed","_createElementBlock","_renderSlot","_ctx","safeTag","normalizeSafeHtmlTag","safeHtmlContent","sanitizeRichTextHtml","_openBlock","_createBlock","_resolveDynamicComponent","safeSrc","sanitizeUrlByKind","safePoster","_a","safeBackgroundImage","cssBackgroundImage","outerStyle","innerStyle","_createElementVNode","withComponent","options","component","builtInComponents","pbColumnOptions","PbColumn","pbRowOptions","PbRow","pbTextOptions","PbText","pbImageOptions","PbImage","pbVideoOptions","PbVideo","pbSectionOptions","PbSection","pbContainerOptions","PbContainer","DEFAULT_LOCALE","defaultTranslations","interpolate","params","match","paramName","value","mergeTranslations","dictionaries","merged","dictionary","locale","messages","translate","fallbackLocale","localeMessages","fallbackMessages","createTranslator","localeSource","dictionarySource","getLocale","getDictionary","key","PAGE_BUILDER_I18N_OPTIONS_KEY","PAGE_BUILDER_I18N_KEY","fallbackI18nContext","usePageBuilderI18n","inject","hasError","ref","capturedError","errorInfo","shouldShowDetails","errorDetails","errorDebugText","segment","onErrorCaptured","error","_instance","info","reportDevDiagnostic","toErrorMessage","_hoisted_1","_hoisted_2","_toDisplayString","_hoisted_3","reportedDiagnostics","reportOnce","details","isNodeObject","maybeNode","sanitizeVariables","rawVariables","entry","safeNode","safeVariables","NodeRenderCrash","defineComponent","localProps","resolutionResult","resolvedComponent","resolvedProps","interpolateProps","markerAttrs","renderedAttrs","slotGroups","groups","child","slotName","ErrorBoundary","_normalizeProps","_guardReactiveProps","_createSlots","children","_Fragment","_renderList","_component_NodeRenderer","pageValidationResult","validatePageData","contentValidationResult","validateNode","layoutValidationResult","watch","result","readerRoot","contentRoot","layoutChildren","_createVNode","NodeRenderer","VIEWPORT_PRESETS","PAGE_BUILDER_KEY","EDITOR_KEY","NODE_TREE_KEY","DRAG_DROP_KEY","isPlainObject","isPositiveInteger","isNonNegativeInteger","createFallbackNode","id","slot","isNode","visited","variableValue","sanitizeInitialData","initialData","issues","fallbackContent","fallbackLayout","source","content","layout","rawMaxId","computedMaxId","getMaxId","hasValidMaxId","maxId","variables","meta","pageData","parseSnapshot","snapshot","parsed","normalizedMaxId","usePageBuilder","initialMode","_initial","mode","isDirty","_initialDirtySnapshot","_serializeDirtyState","_serializeSnapshot","state","_syncDirtyFromCurrentState","setMode","newMode","updateContent","newContent","updateLayout","newLayout","nextId","getSnapshot","restoreSnapshot","reset","original","useEditor","initialSnapshot","initialLabel","initialHistory","baselineSnapshot","reactive","canUndo","canRedo","selectNode","hoverNode","toggleLeftDrawer","toggleRightDrawer","setViewport","preset","syncDirtyWithHistory","currentSnapshot","setHistoryBaseline","label","pushHistory","undo","redo","toRefs","useNodeTree","onUpdate","onSnapshot","_mutate","mutator","currentTree","toRaw","cloned","cloneTree","addNode","parentId","componentName","index","defaultProps","createdNodeId","tree","findNodeById","node","createNode","insertNode","deleteNode","nodeId","removeNode","moveNodeTo","newParentId","moveNode","updateNodeProps","duplicateNode","parentResult","findParent","_deepCloneWithNewIds","canMoveNodeUp","canMoveNodeDown","moveNodeUp","moveNodeDown","DEFAULT_DROP_SLOT","createInitialDragState","useDragDrop","resetDragState","startDragExisting","startDragNew","updateDropTarget","targetId","endDrag","cancelDrag","MIN_VIEWPORT_WIDTH","MIN_VIEWPORT_HEIGHT","MAX_VIEWPORT_WIDTH","MAX_VIEWPORT_HEIGHT","emit","__emit","t","VIEWPORT_LABEL_KEYS","VIEWPORT_ORDER","viewportButtonRefs","getViewportLabel","getViewportSwitchAriaLabel","setViewportButtonRef","element","maybeElement","getViewportIndex","focusViewportButton","handleViewportKeydown","event","currentPreset","currentIndex","nextIndex","nextPreset","nextTick","clampViewportSize","min","max","parseViewportSize","updateCustomViewportSize","dimension","rawValue","width","height","_unref","$emit","_hoisted_4","_","_normalizeClass","$event","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_10","_hoisted_12","_hoisted_14","_hoisted_15","getAllowedDropSlots","parentNode","allowedComponents","normalizeDropSlot","preferredSlot","allowedSlots","preferred","defaultSlot","nodeTree","dragDrop","dropHandled","dropTargetRowId","dropZone","rootId","getDropZoneFromEvent","rowElement","fallback","dropZoneEl","_b","zoneAttr","rect","y","third","getSiblingDropTarget","rowId","zone","rowNode","isNodeInSubtree","getDraggedComponentName","isValidDropTarget","targetNodeId","sourceName","targetNode","sourceNode","isValidSiblingDropTarget","rows","flattenTree","row","rowButtonRefs","setRowButtonRef","getRowIdFromEventTarget","target","getActiveRowIndex","fallbackToFirst","selectedIndex","focusRowById","selectRowByIndex","isRowTabStop","activeIndex","canDragDrop","isDropTargetOn","isDropTargetAbove","isDropTargetBelow","isRowDraggable","handleTreeDragStart","handleTreeDragOver","siblingTarget","handleTreeDrop","newNodeId","insertIndex","sourceParent","handleTreeDragEnd","handleTreeKeydown","currentRowId","selectedNodeId","_normalizeStyle","_hoisted_9","DRAWER_CONTENT_ID","TREE_PANEL_REGION_ID","categorizedComponents","searchQuery","treeOpen","drawerRef","drawerToggleRef","searchInputRef","focusContentOnNextOpen","filteredCategorizedComponents","query","filtered","category","components","matching","comp","handleDragStart","handleDragEnd","handleComponentAdd","toggleTree","getFirstFocusableDrawerControl","drawer","focusDrawerContent","handleDrawerToggle","getCategoryAriaLabel","getDragAriaLabel","isOpen","wasOpen","activeElement","_hoisted_5","_hoisted_13","_hoisted_16","_hoisted_17","_hoisted_18","TreePanel","_cache","handleInput","inputValue","handleChange","attrs","useAttrs","checkboxAttrs","_class","_style","rest","_mergeProps","idx","option","pickerValue","char","handlePickerInput","handleTextInput","inputAttrs","editorRef","lastEmittedValue","getSanitizedHtml","syncEditorHtml","editor","sanitizedHtml","emitCurrentHtml","focusEditor","executeCommand","command","runCommand","insertLink","rawUrl","safeUrl","onMounted","nextValue","contentAttrs","editorAriaLabel","ariaLabelledBy","ariaLabel","safePreviewUrl","hasValue","canPreview","handleClear","handleUploadPlaceholder","DEFAULT_PROP_EDITOR","PropTextEditor","PROP_EDITORS","RichTextEditor","PropNumberEditor","PropBooleanEditor","PropSelectEditor","PropColorEditor","MediaPicker","selectedNode","componentDef","getPropValue","propDef","getEditorComponent","type","getEditorBindings","modelValue","handlePropUpdate","propKey","getPropLabelId","getFirstFocusableContentControl","_hoisted_11","IFRAME_BRIDGE_NAMESPACE","IFRAME_BRIDGE_VERSION","createIframeBridgeEnvelope","channel","payload","sessionToken","createIframeBridgeSessionToken","bytes","byte","createIframeBridgeReadyMessage","createIframeBridgePointerMessage","createIframeBridgeKeydownMessage","isRecord","parsePointerPayload","interaction","maybeNodeId","clientX","clientY","parseKeydownPayload","parseIframeBridgeMessage","sessionTokenCandidate","hasValidSessionToken","createIframeBridgeParent","onMessage","_c","createIframeBridgeChild","shouldAutoPreventShortcut","hasModifier","code","mountIframeBridgeDomListeners","handleClick","handleMouseMove","handleMouseLeave","handleContextMenu","handleKeydown","menuStyle","menuItems","handleAction","disabled","menuRootRef","previousFocusedElement","getFocusableItems","item","focusFirstMenuItem","firstItem","restorePreviousFocus","handleMenuKeydown","items","_d","handleMenuFocusOut","nextTarget","onBeforeUnmount","IFRAME_CONTENT_ROOT_ID","IFRAME_BASE_STYLE_ID","iframeRef","stageRef","fallbackContentRef","useFallbackDom","contentRef","iframeDocumentRef","iframeWindowRef","teardownBridgeParentRef","teardownBridgeDomRef","resizeObserverRef","currentViewportSize","hasViewportSizeReport","selectedRect","hoveredRect","dropRect","contextMenuOpen","contextMenuNodeId","contextMenuX","contextMenuY","canDeleteFromMenu","canMoveUpFromMenu","canMoveDownFromMenu","resolvedViewportDimensions","canvasStyle","selectedOverlayStyle","hoveredOverlayStyle","dropOverlayStyle","isElementTarget","parseNodeId","getNodeIdFromEventTarget","marker","mergeLayoutAndContent","findMarkedElement","getOverlayRect","nodeRect","contentRect","frameScrollTop","frameScrollLeft","clampIndex","root","resolveDropLocation","directSlot","targetChild","rootSlot","canMoveNode","sourceNodeId","proposedIndex","sourceParentResult","normalizedSlot","targetChildrenCount","ensureIframeBaseStyle","doc","styleEl","ensureIframeContentRoot","renderIframeNodeTree","rootNode","render","h","unmountIframeNodeTree","syncDraggableMarkers","syncOverlayRects","dropTargetId","getStageViewportSize","syncViewportSize","nextSize","handleCanvasResize","disconnectResizeObserver","setupResizeObserver","observer","syncOverlayRectsAfterRender","clearDropTargetOverlay","hideContextMenu","handleCanvasClick","handleContentClick","handleContentMouseMove","handleContentMouseLeave","handleContentDragStart","handleContentDragOver","location","handleContentDragLeave","handleContentDrop","finalState","moveResult","handleContentDragEnd","updateContextMenuCapabilities","handleContentContextMenu","handleContextMenuAction","isEditableTarget","tagName","handleBridgePointer","handleBridgeKeydown","getWindowOrigin","targetWindow","teardownIframeBridge","setupIframeBridge","frameWindow","frameDocument","bridgeParent","bridgeChild","handleWindowResize","teardownIframeListeners","setupIframeListeners","initializeFallbackContent","initializeIframeDocument","iframe","frameRoot","isDragging","NodeContextMenu","pb","customViewportWidth","customViewportHeight","activeViewportWidth","activeViewportHeight","handleSave","restoreSnapshotAndEmit","handleUndo","handleRedo","handleDeleteNode","handleDuplicateNode","handleMoveNodeUp","handleMoveNodeDown","handleNodeContextAction","handleDeleteSelected","handleShortcut","handleEditorKeydown","handleIframeKeydown","getViewportDimensions","dimensions","handleViewportChange","currentViewport","handleCustomViewportChange","handleViewportSizeChange","handlePaletteDragStart","handlePaletteDragEnd","handlePaletteAdd","onUnmounted","provide","EditorToolbar","LeftDrawer","IframeCanvas","RightDrawer","canRenderEditor","contentResult","layoutResult","showEditModeFallback","pluginI18nOptions","resolvedLocale","mergedMessages","PageReader","PageEditor","INSTALLED_APPS","registerComponentsIdempotently","pendingDefinitions","existing","PageBuilderPlugin","app","registerBuiltIn","globalName","PageBuilder","builderOptionsPropType"],"mappings":"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"}