1 line
143 KiB
Plaintext
1 line
143 KiB
Plaintext
{"version":3,"sources":["../../src/injections/utils.ts","../../src/injections/layer-dropdown/consts.ts","../../src/injections/layer-dropdown/utils.ts","../../src/injections/layer-dropdown/dropdown-ui.ts","../../src/injections/layer-dropdown/controller.ts","../../src/capabilities/inline-edit/dom-utils.ts","../../src/capabilities/inline-edit/controller.ts","../../src/consts.ts","../../src/injections/canvas-wheel-zoom-bridge.ts","../../src/injections/page-height-bridge.ts","../../src/injections/auto-popup-suppressor.ts","../../src/injections/visual-edit-agent.ts"],"sourcesContent":["const LABEL_HEIGHT = 27;\n\n/**\n * Positions an element-tag label relative to its highlighted overlay.\n *\n * Strategy (in priority order):\n * 1. If the element is near the viewport top AND tall enough (>= 2x label height),\n * place the label **inside** the element at the top-left.\n * 2. If the element is near the viewport top but too short, place the label\n * **below** the element.\n * 3. Otherwise, place the label **above** the element (default).\n *\n * For full-width elements (spanning nearly the entire viewport), the left offset\n * is nudged inward (6px) to prevent clipping against the viewport edge.\n *\n * @param label - The label div to position (style.top and style.left are set).\n * @param rect - The bounding client rect of the highlighted element.\n */\nexport function positionLabel(label: HTMLDivElement, rect: DOMRect): void {\n const nearTop = rect.top < LABEL_HEIGHT;\n const tallEnough = rect.height >= LABEL_HEIGHT * 2;\n const isFullWidth = rect.width >= window.innerWidth - 4;\n const edgeLeft = isFullWidth ? \"8px\" : \"-2px\";\n const insideLeft = isFullWidth ? \"8px\" : \"4px\";\n\n if (nearTop && tallEnough) {\n label.style.top = \"2px\";\n label.style.left = insideLeft;\n } else if (nearTop) {\n label.style.top = `${rect.height + 2}px`;\n label.style.left = edgeLeft;\n } else {\n label.style.top = `-${LABEL_HEIGHT}px`;\n label.style.left = edgeLeft;\n }\n}\n\n/** Check if an element has instrumentation attributes */\nexport function isInstrumentedElement(element: Element): boolean {\n const htmlEl = element as HTMLElement;\n return !!(\n htmlEl.dataset?.sourceLocation || htmlEl.dataset?.visualSelectorId\n );\n}\n\n/** Get the selector ID from an element's data attributes (prefers source-location) */\nexport function getElementSelectorId(element: Element): string | null {\n const htmlEl = element as HTMLElement;\n return (\n htmlEl.dataset?.sourceLocation ||\n htmlEl.dataset?.visualSelectorId ||\n null\n );\n}\n\nexport const ALLOWED_ATTRIBUTES: string[] = [\"src\"];\n\nexport const PLUGIN_ELEMENT_ATTR = \"data-vite-plugin-element\";\n\n/** Find elements by ID - first try data-source-location, fallback to data-visual-selector-id */\nexport function findElementsById(id: string | null): Element[] {\n if (!id) return [];\n const sourceElements = Array.from(\n document.querySelectorAll(`[data-source-location=\"${id}\"]`)\n );\n if (sourceElements.length > 0) {\n return sourceElements;\n }\n return Array.from(\n document.querySelectorAll(`[data-visual-selector-id=\"${id}\"]`)\n );\n}\n\n/**\n * Update element classes by visual selector ID.\n * Uses setAttribute instead of className to support both HTML and SVG elements.\n */\nexport function updateElementClasses(elements: Element[], classes: string): void {\n elements.forEach((element) => {\n element.setAttribute(\"class\", classes);\n });\n}\n\n/** Set a single attribute on all provided elements. */\nexport function updateElementAttribute(elements: Element[], attribute: string, value: string, arrIndex?: number | string): void {\n if (!ALLOWED_ATTRIBUTES.includes(attribute)) {\n return;\n }\n\n const targetArrIndex = arrIndex != null ? String(arrIndex) : null;\n elements.forEach((element) => {\n if (\n targetArrIndex === null ||\n (element as HTMLElement).dataset.arrIndex === targetArrIndex\n ) {\n element.setAttribute(attribute, value);\n }\n });\n}\n\n/** Collect attribute values from an element for a given allowlist. */\nexport function collectAllowedAttributes(element: Element, allowedAttributes: string[]): Record<string, string> {\n const attributes: Record<string, string> = {};\n for (const attr of allowedAttributes) {\n const val = element.getAttribute(attr);\n if (val !== null) {\n attributes[attr] = val;\n }\n }\n return attributes;\n}\n\n/**\n * Freeze all CSS animations and transitions on the page by injecting\n * scoped styles under `[data-visual-edit-active]` and programmatically\n * finishing (or pausing) every running animation.\n *\n * Plugin-owned elements (`[data-vite-plugin-element]`) are excluded so\n * the plugin UI stays animated.\n */\nexport function stopAnimations(): void {\n if (document.getElementById('freeze-animations')) return;\n\n document.documentElement.setAttribute('data-visual-edit-active', '');\n\n const animStyle = document.createElement('style');\n animStyle.id = 'freeze-animations';\n animStyle.textContent = `\n [data-visual-edit-active] *:not([${PLUGIN_ELEMENT_ATTR}]):not([${PLUGIN_ELEMENT_ATTR}] *),\n [data-visual-edit-active] *:not([${PLUGIN_ELEMENT_ATTR}]):not([${PLUGIN_ELEMENT_ATTR}] *)::before,\n [data-visual-edit-active] *:not([${PLUGIN_ELEMENT_ATTR}]):not([${PLUGIN_ELEMENT_ATTR}] *)::after {\n animation-play-state: paused !important;\n transition: none !important;\n }\n `;\n\n const pointerStyle = document.createElement('style');\n pointerStyle.id = 'freeze-pointer-events';\n pointerStyle.textContent = `\n [data-visual-edit-active] * { pointer-events: none !important; }\n [${PLUGIN_ELEMENT_ATTR}], [${PLUGIN_ELEMENT_ATTR}] * { pointer-events: auto !important; }\n `;\n\n const target = document.head || document.documentElement;\n target.appendChild(animStyle);\n target.appendChild(pointerStyle);\n\n document.getAnimations().forEach((a) => {\n // Skip animations on plugin UI elements\n const animTarget = (a.effect as KeyframeEffect)?.target;\n if (animTarget instanceof Element && animTarget.closest(`[${PLUGIN_ELEMENT_ATTR}]`)) return;\n\n try {\n a.finish(); // fast-forward to end state\n } catch {\n a.pause(); // finish() throws on infinite animations — pause instead\n }\n });\n}\n\n/**\n * Resume all previously frozen animations and remove the injected\n * freeze styles. Cleans up the `data-visual-edit-active` attribute\n * from `<html>` so scoped selectors no longer match.\n */\nexport function resumeAnimations(): void {\n const animStyle = document.getElementById('freeze-animations');\n if (!animStyle) return;\n\n animStyle.remove();\n document.getElementById('freeze-pointer-events')?.remove();\n document.documentElement.removeAttribute('data-visual-edit-active');\n\n document.getAnimations().forEach((a) => {\n if (a.playState === 'paused') {\n try { a.play(); } catch { /* animation target may have been removed */ }\n }\n });\n}\n\n/**\n * Hit-test the page at (`x`, `y`) and walk up the DOM to find the\n * nearest ancestor that carries instrumentation attributes\n * (`data-source-location` or `data-visual-selector-id`).\n *\n * Temporarily disables the pointer-events freeze sheet so the\n * browser's native `elementFromPoint` can reach the real target.\n */\nexport function findInstrumentedElement(x: number, y: number): Element | null {\n const pointerStyle = document.getElementById('freeze-pointer-events') as HTMLStyleElement | null;\n if (pointerStyle) pointerStyle.disabled = true;\n\n const el = document.elementFromPoint(x, y);\n\n if (pointerStyle) pointerStyle.disabled = false;\n\n return el?.closest('[data-source-location], [data-visual-selector-id]') ?? null;\n}\n\n/**\n * Resolve which element should be hovered at (`x`, `y`), skipping the\n * currently selected element. Returns the selector ID of the hovered\n * element, or `null` if the point is empty or hits the selected element.\n */\nexport function resolveHoverTarget(x: number, y: number, selectedElementId: string | null): string | null {\n const element = findInstrumentedElement(x, y);\n if (!element) return null;\n\n const selectorId = getElementSelectorId(element);\n\n if (selectorId === selectedElementId) return null;\n\n return selectorId;\n}\n\nconst VISUAL_EDIT_FONT_FACE_ID_PREFIX = \"visual-edit-font-face-\";\n\nfunction isValidFontFaceCss(css: string): boolean {\n const trimmed = css.trim();\n if (!trimmed.startsWith(\"@font-face\")) return false;\n\n if (trimmed.includes(\"\\\\\")) return false; // Prevent CSS escapes\n\n const openBraces = (trimmed.match(/{/g) || []).length;\n const closeBraces = (trimmed.match(/}/g) || []).length;\n if (openBraces !== 1 || closeBraces !== 1 || !trimmed.endsWith(\"}\")) return false;\n\n const chunks = trimmed.split(/url\\(/i);\n for (let i = 1; i < chunks.length; i++) {\n const end = chunks[i]!.indexOf(\")\");\n if (end === -1) return false;\n const url = chunks[i]!.slice(0, end).trim().replace(/^['\"]|['\"]$/g, \"\").trim();\n if (!/^https:\\/\\//i.test(url)) return false;\n }\n\n return true;\n}\n\nexport function injectFontFaceCss(id: string, css: string): void {\n if (typeof id !== \"string\" || !id.trim()) return;\n if (typeof css !== \"string\" || !isValidFontFaceCss(css)) return;\n\n const styleId = `${VISUAL_EDIT_FONT_FACE_ID_PREFIX}${id}`;\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.dataset.visualEditFontFace = \"true\";\n style.textContent = css;\n document.head.appendChild(style);\n}\n","/** Style constants for the layer dropdown UI */\n\nexport const DROPDOWN_CONTAINER_STYLES: Record<string, string> = {\n position: \"absolute\",\n backgroundColor: \"#ffffff\",\n border: \"1px solid #e2e8f0\",\n borderRadius: \"6px\",\n boxShadow: \"0 4px 12px rgba(0, 0, 0, 0.15)\",\n fontSize: \"12px\",\n minWidth: \"120px\",\n maxHeight: \"200px\",\n overflowY: \"auto\",\n zIndex: \"10001\",\n padding: \"4px 0\",\n pointerEvents: \"auto\",\n};\n\nexport const DROPDOWN_ITEM_BASE_STYLES: Record<string, string> = {\n padding: \"4px 12px\",\n cursor: \"pointer\",\n color: \"#334155\",\n backgroundColor: \"transparent\",\n whiteSpace: \"nowrap\",\n lineHeight: \"1.5\",\n fontWeight: \"400\",\n};\n\nexport const DROPDOWN_ITEM_ACTIVE_COLOR = \"#526cff\";\nexport const DROPDOWN_ITEM_ACTIVE_BG = \"#DBEAFE\";\nexport const DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT = \"600\";\n\nexport const DROPDOWN_ITEM_HOVER_BG = \"#f1f5f9\";\n\nexport const DEPTH_INDENT_PX = 10;\n\n/** SVG chevron shown when dropdown is collapsed (click to expand) */\nexport const CHEVRON_COLLAPSED = `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" style=\"vertical-align:middle;margin-left:4px\"><path d=\"M6 9l6 6 6-6\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"/></svg>`;\n/** SVG chevron shown when dropdown is expanded (click to collapse) */\nexport const CHEVRON_EXPANDED = `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" style=\"vertical-align:middle;margin-left:4px\"><path d=\"M18 15l-6-6-6 6\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\"/></svg>`;\n\nexport const CHEVRON_ATTR = \"data-chevron\";\n\nexport const BASE_PADDING_PX = 12;\n\nexport const LAYER_DROPDOWN_ATTR = \"data-layer-dropdown\";\n\n/** Max instrumented ancestors to show above the selected element */\nexport const MAX_PARENT_DEPTH = 2;\n\n/** Max instrumented depth levels to show below the selected element */\nexport const MAX_CHILD_DEPTH = 2;\n","/** DOM utilities for the layer-dropdown module */\n\nimport { isInstrumentedElement, getElementSelectorId } from \"../utils.js\";\nimport { MAX_PARENT_DEPTH, MAX_CHILD_DEPTH } from \"./consts.js\";\n\nimport type { LayerInfo } from \"./types.js\";\n\n/** Apply a style map to an element */\nexport function applyStyles(element: HTMLElement, styles: Record<string, string>): void {\n for (const key of Object.keys(styles)) {\n element.style.setProperty(\n key.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`),\n styles[key]!\n );\n }\n}\n\n/** Display name for a layer — just the real tag name */\nexport function getLayerDisplayName(layer: LayerInfo): string {\n return layer.tagName;\n}\n\nfunction toLayerInfo(element: Element, depth?: number): LayerInfo {\n const info: LayerInfo = {\n element,\n tagName: element.tagName.toLowerCase(),\n selectorId: getElementSelectorId(element),\n };\n if (depth !== undefined) info.depth = depth;\n return info;\n}\n\n/**\n * Collect instrumented descendants up to `maxDepth` instrumented nesting levels.\n * Non-instrumented wrappers are walked through without counting toward depth.\n * Results are in DOM order.\n * When `startDepth` is provided, assigns `depth` to each item during collection.\n */\nexport function getInstrumentedDescendants(\n parent: Element,\n maxDepth: number,\n startDepth?: number\n): LayerInfo[] {\n const result: LayerInfo[] = [];\n\n function walk(el: Element, instrDepth: number): void {\n if (instrDepth > maxDepth) return;\n for (let i = 0; i < el.children.length; i++) {\n const child = el.children[i]!;\n if (isInstrumentedElement(child)) {\n const info: LayerInfo = {\n element: child,\n tagName: child.tagName.toLowerCase(),\n selectorId: getElementSelectorId(child),\n };\n if (startDepth !== undefined) {\n info.depth = startDepth + instrDepth - 1;\n }\n result.push(info);\n walk(child, instrDepth + 1);\n } else {\n walk(child, instrDepth);\n }\n }\n }\n\n walk(parent, 1);\n return result;\n}\n\n/** Collect instrumented ancestors from selected element up to MAX_PARENT_DEPTH (outermost first). */\nfunction collectInstrumentedParents(selectedElement: Element): LayerInfo[] {\n const parents: LayerInfo[] = [];\n let current = selectedElement.parentElement;\n while (\n current &&\n current !== document.documentElement &&\n current !== document.body &&\n parents.length < MAX_PARENT_DEPTH\n ) {\n if (isInstrumentedElement(current)) {\n parents.push(toLayerInfo(current));\n }\n current = current.parentElement;\n }\n parents.reverse();\n return parents;\n}\n\n/** Add parents to chain with depth 0, 1, …; returns depth of selected (parents.length). */\nfunction addParentsToChain(chain: LayerInfo[], parents: LayerInfo[]): number {\n parents.forEach((p, i) => {\n chain.push({ ...p, depth: i });\n });\n return parents.length;\n}\n\n/** Add selected element and its descendants at the given depth. */\nfunction addSelfAndDescendantsToChain(\n chain: LayerInfo[],\n selectedElement: Element,\n selfDepth: number\n): void {\n chain.push(toLayerInfo(selectedElement, selfDepth));\n const descendants = getInstrumentedDescendants(\n selectedElement,\n MAX_CHILD_DEPTH,\n selfDepth + 1\n );\n chain.push(...descendants);\n}\n\n/** Get the innermost instrumented parent's DOM element, or null if none. */\nfunction getImmediateInstrParent(parents: LayerInfo[]): Element | null {\n return parents.at(-1)?.element ?? null;\n}\n\n/** Collect instrumented siblings of the selected element from its parent (DOM order). */\nfunction collectSiblings(parent: Element, selectedElement: Element): LayerInfo[] {\n const siblings = getInstrumentedDescendants(parent, 1);\n if (!siblings.some((s) => s.element === selectedElement)) {\n siblings.push(toLayerInfo(selectedElement));\n }\n return siblings;\n}\n\n/** Add siblings at selfDepth, expanding children only for the selected element. */\nfunction appendSiblingsWithSelected(\n chain: LayerInfo[],\n siblings: LayerInfo[],\n selectedElement: Element,\n selfDepth: number\n): void {\n const selectedSelectorId = getElementSelectorId(selectedElement);\n const seen = new Set<string>();\n for (const sibling of siblings) {\n if (sibling.element === selectedElement) {\n addSelfAndDescendantsToChain(chain, selectedElement, selfDepth);\n if (selectedSelectorId) seen.add(selectedSelectorId);\n } else {\n const id = sibling.selectorId;\n if (id != null) {\n if (id === selectedSelectorId || seen.has(id)) continue;\n seen.add(id);\n }\n chain.push({ ...sibling, depth: selfDepth });\n }\n }\n}\n\n/**\n * Build the layer chain for the dropdown:\n *\n * Parents – up to MAX_PARENT_DEPTH instrumented ancestors, outer → inner.\n * Siblings – instrumented children of the immediate parent, at the same depth.\n * Current – the selected element (highlighted), with children expanded.\n * Children – instrumented descendants within MAX_CHILD_DEPTH levels, DOM order.\n *\n * Each item carries a `depth` for visual indentation.\n */\nexport function buildLayerChain(selectedElement: Element): LayerInfo[] {\n const parents = collectInstrumentedParents(selectedElement);\n const chain: LayerInfo[] = [];\n const selfDepth = addParentsToChain(chain, parents);\n\n const instrParent = getImmediateInstrParent(parents);\n if (instrParent) {\n const siblings = collectSiblings(instrParent, selectedElement);\n appendSiblingsWithSelected(chain, siblings, selectedElement, selfDepth);\n } else {\n addSelfAndDescendantsToChain(chain, selectedElement, selfDepth);\n }\n\n return chain;\n}\n","/** Dropdown UI component for layer navigation */\n\nimport {\n DROPDOWN_CONTAINER_STYLES,\n DROPDOWN_ITEM_BASE_STYLES,\n DROPDOWN_ITEM_ACTIVE_COLOR,\n DROPDOWN_ITEM_ACTIVE_BG,\n DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT,\n DROPDOWN_ITEM_HOVER_BG,\n DEPTH_INDENT_PX,\n BASE_PADDING_PX,\n CHEVRON_COLLAPSED,\n CHEVRON_EXPANDED,\n CHEVRON_ATTR,\n LAYER_DROPDOWN_ATTR,\n} from \"./consts.js\";\nimport { applyStyles, getLayerDisplayName } from \"./utils.js\";\nimport type { LayerInfo, DropdownCallbacks } from \"./types.js\";\nimport { PLUGIN_ELEMENT_ATTR } from \"../utils.js\";\n\nlet activeDropdown: HTMLDivElement | null = null;\nlet activeLabel: HTMLDivElement | null = null;\nlet outsideMousedownHandler: ((e: MouseEvent) => void) | null = null;\nlet activeOnHoverEnd: (() => void) | null = null;\nlet activeKeydownHandler: ((e: KeyboardEvent) => void) | null = null;\n\nfunction createDropdownItem(\n layer: LayerInfo,\n isActive: boolean,\n { onSelect, onHover, onHoverEnd }: DropdownCallbacks\n): HTMLDivElement {\n const item = document.createElement(\"div\");\n item.textContent = getLayerDisplayName(layer);\n applyStyles(item, DROPDOWN_ITEM_BASE_STYLES);\n\n const depth = layer.depth ?? 0;\n if (depth > 0) {\n item.style.paddingLeft = `${BASE_PADDING_PX + depth * DEPTH_INDENT_PX}px`;\n }\n\n if (isActive) {\n item.style.color = DROPDOWN_ITEM_ACTIVE_COLOR;\n item.style.backgroundColor = DROPDOWN_ITEM_ACTIVE_BG;\n item.style.fontWeight = DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT;\n }\n\n item.addEventListener(\"mouseenter\", () => {\n if (!isActive) item.style.backgroundColor = DROPDOWN_ITEM_HOVER_BG;\n if (onHover) onHover(layer);\n });\n\n item.addEventListener(\"mouseleave\", () => {\n if (!isActive) item.style.backgroundColor = \"transparent\";\n if (onHoverEnd) onHoverEnd();\n });\n\n item.addEventListener(\"click\", (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n onSelect(layer);\n });\n\n return item;\n}\n\n/** Create the dropdown DOM element with layer items */\nexport function createDropdownElement(\n layers: LayerInfo[],\n currentElement: Element | null,\n callbacks: DropdownCallbacks\n): HTMLDivElement {\n const container = document.createElement(\"div\");\n container.setAttribute(LAYER_DROPDOWN_ATTR, \"true\");\n container.setAttribute(PLUGIN_ELEMENT_ATTR, \"true\");\n applyStyles(container, DROPDOWN_CONTAINER_STYLES);\n\n layers.forEach((layer) => {\n const isActive = layer.element === currentElement;\n container.appendChild(createDropdownItem(layer, isActive, callbacks));\n });\n\n return container;\n}\n\n/** Add chevron indicator and pointer-events to the label */\nexport function enhanceLabelWithChevron(label: HTMLDivElement): void {\n if (label.querySelector(`[${CHEVRON_ATTR}]`)) return;\n\n const chevron = document.createElement(\"span\");\n chevron.setAttribute(CHEVRON_ATTR, \"true\");\n chevron.style.display = \"inline-flex\";\n chevron.innerHTML = CHEVRON_COLLAPSED;\n label.appendChild(chevron);\n\n label.style.display = \"inline-flex\";\n label.style.alignItems = \"center\";\n label.style.cursor = \"pointer\";\n label.style.userSelect = \"none\";\n label.style.whiteSpace = \"nowrap\";\n label.style.pointerEvents = \"auto\";\n label.setAttribute(LAYER_DROPDOWN_ATTR, \"true\");\n label.setAttribute(PLUGIN_ELEMENT_ATTR, \"true\");\n}\n\nfunction setupKeyboardNavigation(\n dropdown: HTMLDivElement,\n layers: LayerInfo[],\n currentElement: Element | null,\n { onSelect, onHover, onHoverEnd }: DropdownCallbacks\n): void {\n const items = Array.from(dropdown.children) as HTMLDivElement[];\n let focusedIndex = layers.findIndex((l) => l.element === currentElement);\n\n const setFocusedItem = (index: number) => {\n if (focusedIndex >= 0 && focusedIndex < items.length) {\n const prev = items[focusedIndex]!;\n if (prev.style.color !== DROPDOWN_ITEM_ACTIVE_COLOR) {\n prev.style.backgroundColor = \"transparent\";\n }\n }\n focusedIndex = index;\n if (focusedIndex >= 0 && focusedIndex < items.length) {\n const cur = items[focusedIndex]!;\n if (cur.style.color !== DROPDOWN_ITEM_ACTIVE_COLOR) {\n cur.style.backgroundColor = DROPDOWN_ITEM_HOVER_BG;\n }\n cur.scrollIntoView({ block: \"nearest\" });\n if (onHover && focusedIndex >= 0 && focusedIndex < layers.length) {\n onHover(layers[focusedIndex]!);\n }\n }\n };\n\n activeKeydownHandler = (e: KeyboardEvent) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n e.stopPropagation();\n setFocusedItem(focusedIndex < items.length - 1 ? focusedIndex + 1 : 0);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n e.stopPropagation();\n setFocusedItem(focusedIndex > 0 ? focusedIndex - 1 : items.length - 1);\n } else if (e.key === \"Enter\" && focusedIndex >= 0 && focusedIndex < layers.length) {\n e.preventDefault();\n e.stopPropagation();\n if (onHoverEnd) onHoverEnd();\n onSelect(layers[focusedIndex]!);\n closeDropdown();\n }\n };\n document.addEventListener(\"keydown\", activeKeydownHandler, true);\n}\n\nfunction setupOutsideClickHandler(\n dropdown: HTMLDivElement,\n label: HTMLDivElement\n): void {\n let skipFirst = true;\n outsideMousedownHandler = (e: MouseEvent) => {\n if (skipFirst) { skipFirst = false; return; }\n const target = e.target as Node;\n if (!dropdown.contains(target) && target !== label) {\n closeDropdown();\n }\n };\n document.addEventListener(\"mousedown\", outsideMousedownHandler, true);\n}\n\n/** Show the dropdown below the label element */\nexport function showDropdown(\n label: HTMLDivElement,\n layers: LayerInfo[],\n currentElement: Element | null,\n callbacks: DropdownCallbacks\n): void {\n closeDropdown();\n\n const dropdown = createDropdownElement(\n layers,\n currentElement,\n {\n ...callbacks,\n onSelect: (layer) => {\n if (callbacks.onHoverEnd) callbacks.onHoverEnd();\n callbacks.onSelect(layer);\n closeDropdown();\n },\n }\n );\n\n const overlay = label.parentElement;\n if (!overlay) return;\n\n dropdown.style.top = `${label.offsetTop + label.offsetHeight + 2}px`;\n dropdown.style.left = `${label.offsetLeft}px`;\n\n overlay.appendChild(dropdown);\n activeDropdown = dropdown;\n activeLabel = label;\n const chevronEl = label.querySelector(`[${CHEVRON_ATTR}]`);\n if (chevronEl) {\n chevronEl.innerHTML = CHEVRON_EXPANDED;\n }\n activeOnHoverEnd = callbacks.onHoverEnd ?? null;\n\n setupKeyboardNavigation(dropdown, layers, currentElement, callbacks);\n setupOutsideClickHandler(dropdown, label);\n}\n\n/** Close the active dropdown and clean up listeners */\nexport function closeDropdown(): void {\n const chevronEl = activeLabel?.querySelector(`[${CHEVRON_ATTR}]`);\n if (chevronEl) {\n chevronEl.innerHTML = CHEVRON_COLLAPSED;\n }\n activeLabel = null;\n\n if (activeOnHoverEnd) {\n activeOnHoverEnd();\n activeOnHoverEnd = null;\n }\n\n if (activeDropdown && activeDropdown.parentNode) {\n activeDropdown.remove();\n }\n activeDropdown = null;\n\n if (outsideMousedownHandler) {\n document.removeEventListener(\"mousedown\", outsideMousedownHandler, true);\n outsideMousedownHandler = null;\n }\n\n if (activeKeydownHandler) {\n document.removeEventListener(\"keydown\", activeKeydownHandler, true);\n activeKeydownHandler = null;\n }\n}\n\n/** Check if a dropdown is currently visible */\nexport function isDropdownOpen(): boolean {\n return activeDropdown !== null;\n}\n","/** Controller that encapsulates layer-dropdown integration logic */\n\nimport { getElementSelectorId } from \"../utils.js\";\nimport { buildLayerChain } from \"./utils.js\";\nimport {\n enhanceLabelWithChevron,\n showDropdown,\n closeDropdown,\n isDropdownOpen,\n} from \"./dropdown-ui.js\";\nimport type { LayerInfo, LayerControllerConfig, LayerController } from \"./types.js\";\n\nexport function createLayerController(config: LayerControllerConfig): LayerController {\n let layerPreviewOverlay: HTMLDivElement | null = null;\n let escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n let dropdownSourceLayer: LayerInfo | null = null;\n\n const clearLayerPreview = () => {\n if (layerPreviewOverlay && layerPreviewOverlay.parentNode) {\n layerPreviewOverlay.remove();\n }\n layerPreviewOverlay = null;\n };\n\n const showLayerPreview = (layer: LayerInfo) => {\n clearLayerPreview();\n if (getElementSelectorId(layer.element) === config.getSelectedElementId()) return;\n\n layerPreviewOverlay = config.createPreviewOverlay(layer.element);\n };\n\n const selectLayer = (layer: LayerInfo) => {\n clearLayerPreview();\n closeDropdown();\n if (escapeHandler) {\n document.removeEventListener(\"keydown\", escapeHandler, true);\n escapeHandler = null;\n }\n dropdownSourceLayer = null;\n\n const firstOverlay = config.selectElement(layer.element);\n attachToOverlay(firstOverlay, layer.element);\n };\n\n const restoreSelection = () => {\n if (escapeHandler) {\n document.removeEventListener(\"keydown\", escapeHandler, true);\n escapeHandler = null;\n }\n if (dropdownSourceLayer) {\n selectLayer(dropdownSourceLayer);\n dropdownSourceLayer = null;\n }\n };\n\n const handleLabelClick = (e: MouseEvent, label: HTMLDivElement, element: Element, layers: LayerInfo[], currentId: string | null) => {\n e.stopPropagation();\n e.preventDefault();\n if (isDropdownOpen()) {\n closeDropdown();\n restoreSelection();\n } else {\n dropdownSourceLayer = {\n element,\n tagName: element.tagName.toLowerCase(),\n selectorId: currentId,\n };\n config.onDeselect();\n\n escapeHandler = (ev: KeyboardEvent) => {\n if (ev.key === \"Escape\") {\n ev.stopPropagation();\n closeDropdown();\n restoreSelection();\n }\n };\n document.addEventListener(\"keydown\", escapeHandler, true);\n\n showDropdown(label, layers, element, { onSelect: selectLayer, onHover: showLayerPreview, onHoverEnd: clearLayerPreview });\n }\n };\n\n const attachToOverlay = (\n overlay: HTMLDivElement | undefined,\n element: Element\n ) => {\n if (!overlay) return;\n\n const label = overlay.querySelector(\"div\") as HTMLDivElement | null;\n if (!label) return;\n\n const layers = buildLayerChain(element);\n if (layers.length <= 1) return;\n\n const currentId = getElementSelectorId(element);\n enhanceLabelWithChevron(label);\n\n label.addEventListener(\"click\", (e: MouseEvent) => {\n handleLabelClick(e, label, element, layers, currentId);\n });\n };\n\n const cleanup = () => {\n clearLayerPreview();\n closeDropdown();\n };\n\n return { attachToOverlay, cleanup };\n}\n","const FOCUS_STYLE_ID = \"visual-edit-focus-styles\";\n\nconst EDITABLE_TAGS = [\n \"div\", \"p\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n \"span\", \"li\", \"td\", \"a\", \"button\", \"label\",\n];\n\nexport const isStaticArrayTextElement = (element: HTMLElement): boolean => {\n return !!element.dataset.arrField;\n};\n\nconst passesStructuralChecks = (element: HTMLElement): boolean => {\n if (!EDITABLE_TAGS.includes(element.tagName.toLowerCase())) return false;\n if (!element.textContent?.trim()) return false;\n if (element.querySelector(\"img, video, canvas, svg\")) return false;\n if (element.children?.length > 0) return false;\n return true;\n};\n\nexport const injectFocusOutlineCSS = () => {\n if (document.getElementById(FOCUS_STYLE_ID)) return;\n\n const style = document.createElement(\"style\");\n style.id = FOCUS_STYLE_ID;\n style.textContent = `\n [data-selected=\"true\"][contenteditable=\"true\"]:focus {\n outline: none !important;\n }\n `;\n document.head.appendChild(style);\n};\n\nexport const removeFocusOutlineCSS = () => {\n document.getElementById(FOCUS_STYLE_ID)?.remove();\n};\n\nexport const selectText = (element: HTMLElement) => {\n const range = document.createRange();\n range.selectNodeContents(element);\n const selection = window.getSelection();\n selection?.removeAllRanges();\n selection?.addRange(range);\n};\n\nexport const isEditableTextElement = (element: Element): boolean => {\n if (!(element instanceof HTMLElement)) return false;\n if (!passesStructuralChecks(element)) return false;\n if (isStaticArrayTextElement(element)) return true;\n if (element.dataset.dynamicContent === \"true\") return false;\n return true;\n};\n\nexport const shouldEnterInlineEditingMode = (element: Element): boolean => {\n if (!(element instanceof HTMLElement) || element.dataset.selected !== \"true\") {\n return false;\n }\n return isEditableTextElement(element);\n};\n","import type { InlineEditHost, InlineEditController } from \"./types.js\";\nimport {\n injectFocusOutlineCSS,\n removeFocusOutlineCSS,\n selectText,\n shouldEnterInlineEditingMode,\n isStaticArrayTextElement,\n} from \"./dom-utils.js\";\nimport { PLUGIN_ELEMENT_ATTR } from \"../../injections/utils.js\";\n\nconst DEBOUNCE_MS = 500;\n\nexport function createInlineEditController(\n host: InlineEditHost\n): InlineEditController {\n let currentEditingElement: HTMLElement | null = null;\n let debouncedSendTimeout: ReturnType<typeof setTimeout> | null = null;\n let enabled = false;\n const listenerAbortControllers = new WeakMap<HTMLElement, AbortController>();\n\n // --- Private helpers ---\n\n const repositionOverlays = () => {\n const selectedId = host.getSelectedElementId();\n if (!selectedId) return;\n const elements = host.findElementsById(selectedId);\n const overlays = host.getSelectedOverlays();\n overlays.forEach((overlay, i) => {\n if (i < elements.length && elements[i]) {\n host.positionOverlay(overlay, elements[i]);\n }\n });\n };\n\n const reportEdit = (element: HTMLElement) => {\n const originalContent = element.dataset.originalTextContent;\n const newContent = element.textContent;\n\n const svgElement = element as unknown as SVGElement;\n const rect = element.getBoundingClientRect();\n\n const message: Record<string, unknown> = {\n type: \"inline-edit\",\n elementInfo: {\n tagName: element.tagName,\n classes:\n (svgElement.className as unknown as SVGAnimatedString)?.baseVal ||\n element.className ||\n \"\",\n visualSelectorId: host.getSelectedElementId(),\n content: newContent,\n dataSourceLocation: element.dataset.sourceLocation,\n isDynamicContent: element.dataset.dynamicContent === \"true\",\n linenumber: element.dataset.linenumber,\n filename: element.dataset.filename,\n position: {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n centerX: rect.left + rect.width / 2,\n centerY: rect.top + rect.height / 2,\n },\n },\n originalContent,\n newContent,\n };\n\n if (isStaticArrayTextElement(element)) {\n message.arrIndex = element.dataset.arrIndex;\n message.arrVariableName = element.dataset.arrVariableName;\n message.arrField = element.dataset.arrField;\n }\n\n window.parent.postMessage(message, \"*\");\n\n element.dataset.originalTextContent = newContent || \"\";\n };\n\n const debouncedReport = (element: HTMLElement) => {\n if (debouncedSendTimeout) clearTimeout(debouncedSendTimeout);\n debouncedSendTimeout = setTimeout(() => reportEdit(element), DEBOUNCE_MS);\n };\n\n const onTextInput = (element: HTMLElement) => {\n repositionOverlays();\n debouncedReport(element);\n };\n\n const handleInputEvent = function (this: HTMLElement) {\n onTextInput(this);\n };\n\n const makeEditable = (element: HTMLElement) => {\n injectFocusOutlineCSS();\n\n element.dataset.originalTextContent = element.textContent || \"\";\n element.dataset.originalCursor = element.style.cursor;\n element.contentEditable = \"true\";\n element.setAttribute(PLUGIN_ELEMENT_ATTR, \"true\");\n\n const abortController = new AbortController();\n listenerAbortControllers.set(element, abortController);\n element.addEventListener(\"input\", handleInputEvent, {\n signal: abortController.signal,\n });\n\n element.style.cursor = \"text\";\n selectText(element);\n setTimeout(() => {\n if (element.isConnected) {\n element.focus();\n }\n }, 0);\n };\n\n const makeNonEditable = (element: HTMLElement) => {\n const abortController = listenerAbortControllers.get(element);\n if (abortController) {\n abortController.abort();\n listenerAbortControllers.delete(element);\n }\n\n if (!element.isConnected) return;\n\n removeFocusOutlineCSS();\n element.contentEditable = \"false\";\n element.removeAttribute(PLUGIN_ELEMENT_ATTR);\n delete element.dataset.originalTextContent;\n\n if (element.dataset.originalCursor !== undefined) {\n element.style.cursor = element.dataset.originalCursor;\n delete element.dataset.originalCursor;\n }\n };\n\n // --- Public API ---\n\n return {\n get enabled() {\n return enabled;\n },\n set enabled(value: boolean) {\n enabled = value;\n },\n\n isEditing() {\n return currentEditingElement !== null;\n },\n\n getCurrentElement() {\n return currentEditingElement;\n },\n\n canEdit(element: Element) {\n return shouldEnterInlineEditingMode(element);\n },\n\n startEditing(element: HTMLElement) {\n currentEditingElement = element;\n\n host.getSelectedOverlays().forEach((o) => {\n o.style.display = \"none\";\n });\n\n makeEditable(element);\n\n window.parent.postMessage(\n {\n type: \"content-editing-started\",\n visualSelectorId: host.getSelectedElementId(),\n },\n \"*\"\n );\n },\n\n stopEditing() {\n if (!currentEditingElement) return;\n\n if (debouncedSendTimeout) {\n clearTimeout(debouncedSendTimeout);\n debouncedSendTimeout = null;\n }\n\n const element = currentEditingElement;\n makeNonEditable(element);\n\n host.getSelectedOverlays().forEach((o) => {\n o.style.display = \"\";\n });\n\n repositionOverlays();\n\n window.parent.postMessage(\n {\n type: \"content-editing-ended\",\n visualSelectorId: host.getSelectedElementId(),\n },\n \"*\"\n );\n\n currentEditingElement = null;\n },\n\n markElementsSelected(elements: Element[]) {\n elements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.dataset.selected = \"true\";\n }\n });\n },\n\n clearSelectedMarks(elementId: string | null) {\n if (!elementId) return;\n host.findElementsById(elementId).forEach((el) => {\n if (el instanceof HTMLElement) {\n delete el.dataset.selected;\n }\n });\n },\n\n handleToggleMessage(data: { dataSourceLocation: string; inlineEditingMode: boolean }) {\n if (!enabled) return;\n\n const elements = host.findElementsById(data.dataSourceLocation);\n if (elements.length === 0 || !(elements[0] instanceof HTMLElement)) return;\n\n const element = elements[0];\n\n if (data.inlineEditingMode) {\n if (!shouldEnterInlineEditingMode(element)) return;\n\n // Select the element first if not already selected\n if (host.getSelectedElementId() !== data.dataSourceLocation) {\n this.stopEditing();\n host.clearSelection();\n this.markElementsSelected(elements);\n host.createSelectionOverlays(elements, data.dataSourceLocation);\n }\n this.startEditing(element);\n } else {\n if (currentEditingElement === element) {\n this.stopEditing();\n }\n }\n },\n\n cleanup() {\n this.stopEditing();\n },\n };\n}\n","export const DATA_COLLECTION_ID = \"data-collection-id\";\nexport const DATA_COLLECTION_ITEM_ID = \"data-collection-item-id\";\nexport const DATA_COLLECTION_ITEM_FIELD = \"data-collection-item-field\";\nexport const DATA_COLLECTION_REFERENCE = \"data-collection-reference\";\nexport const DATA_ARR_INDEX = \"data-arr-index\";\nexport const DATA_ARR_VARIABLE_NAME = \"data-arr-variable-name\";\nexport const DATA_ARR_FIELD = \"data-arr-field\";\n\nexport const ALLOWED_CUSTOM_COMPONENTS = [\"Image\", \"Link\"];\nexport const MAX_JSX_DEPTH = 10;\nexport const EXCLUDED_FIELDS = [\"children\", \"length\"];\nexport const THEME_FONT_PREVIEW_ID = \"__theme-font-preview\";\n","import { PLUGIN_ELEMENT_ATTR } from \"./utils.js\";\n\ntype CanvasWheelPanData = {\n deltaX: number;\n deltaY: number;\n deltaMode: number;\n clientX: number;\n clientY: number;\n shiftKey: boolean;\n ctrlKey: false;\n metaKey: false;\n};\n\nfunction elementFromEventTarget(target: EventTarget | null): Element | null {\n if (target instanceof Element) return target;\n if (target instanceof Node) return target.parentElement;\n return null;\n}\n\nfunction isPluginOwnedTarget(target: EventTarget | null): boolean {\n return elementFromEventTarget(target)?.closest(`[${PLUGIN_ELEMENT_ATTR}]`) != null;\n}\n\nexport function createCanvasWheelZoomBridgeController() {\n let isEnabled = false;\n\n const onWheel = (event: WheelEvent): void => {\n if (isPluginOwnedTarget(event.target)) return;\n\n event.preventDefault();\n if (event.ctrlKey || event.metaKey) {\n window.parent.postMessage({\n type: \"canvas-wheel-zoom\",\n data: {\n deltaY: event.deltaY,\n deltaMode: event.deltaMode,\n clientX: event.clientX,\n clientY: event.clientY,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n },\n }, \"*\");\n return;\n }\n\n const panData: CanvasWheelPanData = {\n deltaX: event.deltaX,\n deltaY: event.deltaY,\n deltaMode: event.deltaMode,\n clientX: event.clientX,\n clientY: event.clientY,\n shiftKey: event.shiftKey,\n ctrlKey: false,\n metaKey: false,\n };\n window.parent.postMessage({\n type: \"canvas-wheel-pan\",\n data: panData,\n }, \"*\");\n };\n\n const enable = (): void => {\n if (isEnabled) return;\n isEnabled = true;\n window.addEventListener(\"wheel\", onWheel, { capture: true, passive: false });\n };\n\n const disable = (): void => {\n if (!isEnabled) return;\n isEnabled = false;\n window.removeEventListener(\"wheel\", onWheel, true);\n };\n\n return {\n enable,\n disable,\n };\n}\n","// page-height-bridge — postMessage protocol the iframe exposes to its parent.\n// Inert until the parent posts a message; no observers, rewrites, or timers\n// fire on their own.\n//\n// parent → child { type: \"freeze-vh-units\", referenceVhBase?: number }\n// Rewrites every viewport-height unit (`vh`/`dvh`/`svh`/`lvh`) in\n// <style> + CSSOM to a CSS variable-backed expression (kills the\n// vh ↔ auto-resize feedback loop). Repeated calls update the variable,\n// so callers can rebase without recovering raw CSS. Idempotent; covers\n// HMR-added styles too. Fire-and-forget.\n//\n// parent → child { type: \"measure-page-height\", settleMs?: number }\n// After `settleMs` (default 2000) posts the page's measured content height\n// as `{ type: \"page-height-measured\", height }` to the requester.\n\ntype IncomingMessage = {\n type?: string;\n settleMs?: number;\n referenceVhBase?: number;\n};\n\ntype IndexableCssRule = CSSRule & {\n cssRules?: CSSRuleList;\n style?: CSSStyleDeclaration;\n};\n\ntype Debouncer = { trigger: () => void; cancel: () => void };\n\nexport type PageHeightBridgeController = {\n freezeVhUnits: (override?: number) => void;\n measurePageHeight: (origin: string, settleMs?: number) => void;\n teardown: () => void;\n};\n\nconst FALLBACK_VHBASE: number = 900;\nconst MIN_VHBASE: number = 400;\nconst DEFAULT_SETTLE_MS: number = 2000;\nconst NEUTRALIZE_DEBOUNCE_MS: number = 16;\n// Three consecutive same-height samples ≈ ~50ms of \"no change\". Three is\n// enough to filter single-frame jitter from layout passes but short enough\n// that responses arrive promptly when the DOM is already settled.\nconst STABILITY_SAMPLES: number = 3;\n// Interval between stability samples. ~1 frame at 60Hz; chosen as a plain\n// setTimeout (not rAF) because jsdom rAFs are unreliably timed for tests and\n// in real browsers a 16ms tick is post-layout for any layout work that fits\n// inside one frame.\nconst STABILITY_TICK_MS: number = 16;\n// Hard cap on the stability poll past settleMs. Pages that genuinely never\n// stabilize (looping height-animating content) reply with their last sample\n// rather than hanging the parent's resize logic.\nconst STABILITY_MAX_WAIT_MS: number = 1500;\nconst REFERENCE_VH_BASE_VAR: string = \"--base44-reference-vh-base\";\n\nconst noop: () => void = (): void => {};\n\nlet started: boolean = false;\n\n/**\n * Installs the parent-driven message listener. Returns a teardown that\n * removes the listener, disconnects any observers attached as a result of\n * `freeze-vh-units`, and clears any pending response timer. Returns a\n * no-op when bailed (already started, SSR, top window).\n */\nexport function setupPageHeightBridge(): () => void {\n if (started) return noop;\n if (typeof window === \"undefined\") return noop;\n if (window.self === window.top) return noop;\n started = true;\n\n const controller: PageHeightBridgeController = createPageHeightBridgeController();\n\n const onMessage = (event: MessageEvent): void => {\n const data: IncomingMessage | null = (event.data ?? null) as IncomingMessage | null;\n if (!data || typeof data !== \"object\") return;\n switch (data.type) {\n case \"freeze-vh-units\": {\n const override: number | undefined =\n typeof data.referenceVhBase === \"number\" ? data.referenceVhBase : undefined;\n controller.freezeVhUnits(override);\n return;\n }\n case \"measure-page-height\": {\n const settleMs: number =\n typeof data.settleMs === \"number\" ? data.settleMs : DEFAULT_SETTLE_MS;\n const origin: string =\n event.origin && event.origin !== \"null\" ? event.origin : \"*\";\n controller.measurePageHeight(origin, settleMs);\n return;\n }\n }\n };\n\n window.addEventListener(\"message\", onMessage);\n\n let torn: boolean = false;\n return (): void => {\n if (torn) return;\n torn = true;\n started = false;\n window.removeEventListener(\"message\", onMessage);\n controller.teardown();\n };\n}\n\nexport function createPageHeightBridgeController(): PageHeightBridgeController {\n let vhCleanups: Array<() => void> | null = null;\n let vhForceRun: (() => void) | null = null;\n let pendingSettle: number | undefined;\n let pendingTick: number | undefined;\n let pendingOrigin: string = \"*\";\n\n const cancelPending = (): void => {\n if (pendingSettle !== undefined) {\n window.clearTimeout(pendingSettle);\n pendingSettle = undefined;\n }\n if (pendingTick !== undefined) {\n window.clearTimeout(pendingTick);\n pendingTick = undefined;\n }\n };\n\n return {\n freezeVhUnits: (override: number | undefined): void => {\n const referenceVhBase: number = resolveReferenceVhBase(override);\n setReferenceVhBase(referenceVhBase);\n if (vhCleanups) {\n vhForceRun?.();\n return;\n }\n vhCleanups = [];\n vhForceRun = startVhNeutralizer(vhCleanups);\n },\n\n // Target the requester's origin so the height isn't broadcast to anyone\n // who happens to embed us. Falls back to \"*\" when origin is unavailable\n // (jsdom default, sandboxed iframes with `null` origin).\n //\n // Stability-wait response: after `settleMs`, poll measureContentHeight at\n // STABILITY_TICK_MS intervals until it's unchanged for STABILITY_SAMPLES\n // consecutive ticks, then send exactly one reply. Catches late React\n // mounts (sticky-positioned sections committing after settleMs), debounced\n // neutralizer mutations not yet flushed, image/font-driven layout shifts.\n // STABILITY_MAX_WAIT_MS caps the poll so a page that genuinely never\n // settles still replies eventually.\n measurePageHeight: (origin: string, settleMs: number = DEFAULT_SETTLE_MS): void => {\n pendingOrigin = origin;\n cancelPending();\n\n pendingSettle = window.setTimeout((): void => {\n pendingSettle = undefined;\n // Flush any debounced unscroll / inline-vh rewrites NOW so the first\n // sample sees a DOM that reflects every mutation triggered during the\n // settle window. Without this, an `overflow-y: scroll` container that\n // mounted mid-settle can still be hiding its children at sample time.\n vhForceRun?.();\n\n const deadline: number = nowMs() + STABILITY_MAX_WAIT_MS;\n let lastHeight: number = -1;\n let stableSamples: number = 0;\n\n const respond = (height: number): void => {\n pendingTick = undefined;\n window.parent.postMessage({ type: \"page-height-measured\", height }, pendingOrigin);\n };\n\n const tick = (): void => {\n pendingTick = undefined;\n const height: number = measureContentHeight();\n if (height === lastHeight) {\n stableSamples++;\n } else {\n stableSamples = 1;\n lastHeight = height;\n }\n if (stableSamples >= STABILITY_SAMPLES || nowMs() >= deadline) {\n respond(height);\n return;\n }\n pendingTick = window.setTimeout(tick, STABILITY_TICK_MS);\n };\n\n tick();\n }, settleMs);\n },\n\n teardown: (): void => {\n if (vhCleanups) {\n for (const c of vhCleanups) c();\n vhCleanups = null;\n vhForceRun = null;\n }\n cancelPending();\n },\n };\n}\n\nfunction nowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction resolveReferenceVhBase(override: number | undefined): number {\n if (override !== undefined) return override;\n const detected: number = window.innerHeight || 0;\n return detected >= MIN_VHBASE ? detected : FALLBACK_VHBASE;\n}\n\nfunction setReferenceVhBase(referenceVhBase: number): void {\n document.documentElement.style.setProperty(REFERENCE_VH_BASE_VAR, `${referenceVhBase}px`);\n}\n\n// Caches keep work proportional to *new* CSS, not total CSS. <head> observer\n// catches `<style>`/`<link>` adds; per-element observers catch HMR text edits.\n// Returns a `forceRun` so the caller can re-trigger neutralization on later\n// parent requests (idempotent — already-rewritten text is skipped via the\n// processed sets).\nfunction startVhNeutralizer(cleanups: Array<() => void>): () => void {\n // Match vh + the dynamic/small/large variants. Tailwind v4 emits `h-screen`\n // as `100dvh`; all four collapse to the same frozen `referenceVhBase`.\n const VH_RE: RegExp = /(\\d+(?:\\.\\d+)?)(?:d|s|l)?vh\\b/g;\n const processedStyles: WeakSet<HTMLStyleElement> = new WeakSet();\n const processedSheets: WeakMap<CSSStyleSheet, number> = new WeakMap();\n const watchedStyles: WeakSet<HTMLStyleElement> = new WeakSet();\n const styleObservers: Set<MutationObserver> = new Set();\n\n const unscrolled: WeakSet<Element> = new WeakSet();\n\n const rewrite = (input: string): string =>\n input.replace(VH_RE, (_match: string, n: string): string =>\n `calc(var(${REFERENCE_VH_BASE_VAR}) * ${formatVhFactor(n)})`,\n );\n\n // Defeats internal vertical scrollers. The canvas wants the whole page laid\n // out top-to-bottom, but `<div class=\"overflow-y-auto\" style={{height:\n // \"100vh\"}}>` hides its children behind an internal scrollbar — only the\n // first child appears in the preview. Forcing `overflow-y: visible` lets\n // children paint outside the parent's box; block flow positions them at\n // their natural offsets so document.body extends to include them. `auto`\n // and `scroll` only — `hidden` and `clip` express intentional clipping (UI\n // chrome, rounded-corner masks) we shouldn't undo.\n const unscrollY = (el: Element): void => {\n if (unscrolled.has(el)) return;\n const computedStyle: CSSStyleDeclaration = window.getComputedStyle(el);\n const ovY: string = computedStyle.overflowY;\n if (ovY !== \"auto\" && ovY !== \"scroll\") return;\n unscrolled.add(el);\n (el as HTMLElement).style.setProperty(\"overflow-y\", \"visible\", \"important\");\n };\n\n const unscrollSubtree = (root: Element): void => {\n unscrollY(root);\n root.querySelectorAll<HTMLElement>(\"*\").forEach(unscrollY);\n };\n\n // Rewrites vh-bearing properties on a single element's inline style. Covers\n // React's `style={{ height: \"100vh\" }}` and imperative `el.style.h = \".vh\"`\n // — both bypass <style> tags and CSSOM. Per-property setProperty preserves\n // `!important`. Snapshotting prop names first guards against iteration-time\n // mutation of `style.length`.\n const rewriteInlineStyle = (el: Element): void => {\n const style: CSSStyleDeclaration | undefined = (el as HTMLElement).style;\n if (!style || style.length === 0) return;\n const props: string[] = [];\n for (let i: number = 0; i < style.length; i++) {\n const prop: string | undefined = style[i];\n if (prop) props.push(prop);\n }\n for (const prop of props) {\n const value: string = style.getPropertyValue(prop);\n if (!value || value.indexOf(\"vh\") === -1) continue;\n const next: string = rewrite(value);\n if (next !== value) style.setProperty(prop, next, style.getPropertyPriority(prop));\n }\n };\n\n const neutralize = (): void => {\n document.querySelectorAll<HTMLStyleElement>(\"style\").forEach((el: HTMLStyleElement): void => {\n watchStyleEl(el);\n if (processedStyles.has(el)) return;\n processedStyles.add(el);\n const text: string | null = el.textContent;\n if (!text || text.indexOf(\"vh\") === -1) return;\n const next: string = rewrite(text);\n if (next !== text) el.textContent = next;\n });\n\n for (let i: number = 0; i < document.styleSheets.length; i++) {\n const sheet: CSSStyleSheet | undefined = document.styleSheets[i];\n if (!sheet) continue;\n let rules: CSSRuleList;\n try {\n rules = sheet.cssRules;\n } catch {\n continue; // CORS-protected\n }\n if (processedSheets.get(sheet) === rules.length) continue;\n rewriteVhInRules(rules, rewrite);\n processedSheets.set(sheet, rules.length);\n }\n\n // Initial sweep of inline `style=\"...vh...\"` attributes already in the DOM\n // at freeze time. Future inline-style mutations (React commits, motion\n // libraries, imperative assignments) are picked up by inlineStyleObserver.\n document.querySelectorAll<HTMLElement>('[style*=\"vh\"]').forEach(rewriteInlineStyle);\n\n // Defeat internal scrollers — same dual coverage (initial sweep here,\n // subtree additions in inlineStyleObserver).\n if (document.body) unscrollSubtree(document.body);\n };\n\n const debouncer: Debouncer = createDebouncer(neutralize, NEUTRALIZE_DEBOUNCE_MS);\n const debouncedNeutralize: () => void = debouncer.trigger;\n cleanups.push(debouncer.cancel);\n\n const watchStyleEl = (el: HTMLStyleElement): void => {\n if (watchedStyles.has(el)) return;\n watchedStyles.add(el);\n const obs: MutationObserver = new MutationObserver((): void => {\n processedStyles.delete(el);\n debouncedNeutralize();\n });\n obs.observe(el, { characterData: true, childList: true, subtree: true });\n styleObservers.add(obs);\n };\n cleanups.push((): void => {\n for (const obs of styleObservers) obs.disconnect();\n styleObservers.clear();\n });\n\n debouncedNeutralize();\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", debouncedNeutralize);\n cleanups.push((): void => document.removeEventListener(\"DOMContentLoaded\", debouncedNeutralize));\n }\n window.addEventListener(\"load\", debouncedNeutralize);\n cleanups.push((): void => window.removeEventListener(\"load\", debouncedNeutralize));\n\n const headObserver: MutationObserver = new MutationObserver((mutations: MutationRecord[]): void => {\n for (const m of mutations) {\n if (containsStylesheetNode(m.addedNodes) || containsStylesheetNode(m.removedNodes)) {\n debouncedNeutralize();\n return;\n }\n }\n });\n cleanups.push((): void => headObserver.disconnect());\n\n const attachHeadObserver = (): void => {\n if (document.head) headObserver.observe(document.head, { childList: true, subtree: false });\n };\n if (document.head) {\n attachHeadObserver();\n } else {\n document.addEventListener(\"DOMContentLoaded\", attachHeadObserver);\n cleanups.push((): void => document.removeEventListener(\"DOMContentLoaded\", attachHeadObserver));\n }\n\n // Pass 3: inline `style` attributes. One global observer covers every\n // element — past, present, and future — without per-node tracking. Two\n // mutation kinds matter:\n // • attributes: React/JS sets `style` on an element already in the tree\n // (`el.style.h = \"..vh\"`, re-render diff). After rewrite the value has\n // no \"vh\", so the next mutation gates out — single-tick convergence.\n // • childList: a node is mounted with its `style` attribute already set\n // off-tree (React's initial mount path uses createElement+setAttribute\n // BEFORE appendChild, so attribute mutations never fire for them). Scan\n // the added subtree for `[style*=\"vh\"]` and rewrite.\n // Microtask delivery means rewrites land before layout, so no flash.\n const scanSubtreeForInlineVh = (node: Node): void => {\n if (!(node instanceof Element)) return;\n const attr: string | null = node.getAttribute(\"style\");\n if (attr && attr.indexOf(\"vh\") !== -1) rewriteInlineStyle(node);\n node.querySelectorAll<HTMLElement>('[style*=\"vh\"]').forEach(rewriteInlineStyle);\n // New subtrees may introduce overflow-y: auto|scroll containers (route\n // changes, conditional UI). Catch them here too.\n unscrollSubtree(node);\n };\n const inlineStyleObserver: MutationObserver = new MutationObserver(\n (mutations: MutationRecord[]): void => {\n for (const m of mutations) {\n if (m.type === \"attributes\") {\n const target: Node = m.target;\n if (!(target instanceof Element)) continue;\n const attr: string | null = target.getAttribute(\"style\");\n if (!attr || attr.indexOf(\"vh\") === -1) continue;\n rewriteInlineStyle(target);\n } else if (m.type === \"childList\") {\n for (let i: number = 0; i < m.addedNodes.length; i++) {\n const node: Node | undefined = m.addedNodes[i];\n if (node) scanSubtreeForInlineVh(node);\n }\n }\n }\n },\n );\n cleanups.push((): void => inlineStyleObserver.disconnect());\n\n const attachInlineStyleObserver = (): void => {\n const root: Element | null = document.documentElement;\n if (!root) return;\n inlineStyleObserver.observe(root, {\n attributes: true,\n attributeFilter: [\"style\"],\n childList: true,\n subtree: true,\n });\n };\n attachInlineStyleObserver();\n\n return debouncedNeutralize;\n}\n\nfunction formatVhFactor(value: string): string {\n return String(Number((parseFloat(value) / 100).toFixed(6)));\n}\n\nfunction rewriteVhInRules(rules: CSSRuleList, rewrite: (value: string) => string): void {\n for (let i: number = 0; i < rules.length; i++) {\n const rule: IndexableCssRule | undefined = rules[i] as IndexableCssRule | undefined;\n if (!rule) continue;\n if (rule.cssRules) rewriteVhInRules(rule.cssRules, rewrite);\n const style: CSSStyleDeclaration | undefined = rule.style;\n if (!style) continue;\n for (let j: number = 0; j < style.length; j++) {\n const prop: string | undefined = style[j];\n if (!prop) continue;\n const value: string = style.getPropertyValue(prop);\n if (!value || value.indexOf(\"vh\") === -1) continue;\n const next: string = rewrite(value);\n if (next !== value) style.setProperty(prop, next, style.getPropertyPriority(prop));\n }\n }\n}\n\nfunction containsStylesheetNode(nodes: NodeList): boolean {\n for (let i: number = 0; i < nodes.length; i++) {\n const node: Node | undefined = nodes[i];\n if (node instanceof HTMLStyleElement || node instanceof HTMLLinkElement) return true;\n }\n return false;\n}\n\nfunction measureContentHeight(): number {\n const scrollHeight: number = Math.max(\n document.documentElement.scrollHeight,\n document.body?.scrollHeight ?? 0,\n );\n const referenceVhBase: number = readReferenceVhBase();\n // Excludes `body.clientHeight`: it grows with content, which makes\n // viewportBottom land at the document bottom and trips the stretched-\n // container heuristic on the last section. `referenceVhBase` keeps the\n // h-screen-wrapper case covered when the iframe is shorter than 100vh.\n const viewportHeight: number = Math.max(\n window.innerHeight || 0,\n document.documentElement.clientHeight,\n referenceVhBase,\n );\n const contentBottom: number = measureElementContentBottom(viewportHeight);\n if (contentBottom > 0) return Math.ceil(Math.max(contentBottom, referenceVhBase));\n return Math.ceil(Math.max(scrollHeight, referenceVhBase));\n}\n\nfunction readReferenceVhBase(): number {\n const value: string = document.documentElement.style.getPropertyValue(REFERENCE_VH_BASE_VAR);\n const parsed: number = parseFloat(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nfunction measureElementContentBottom(viewportHeight: number): number {\n if (!document.body) return 0;\n const elements: Element[] = [document.body, ...Array.from(document.body.querySelectorAll(\"*\"))];\n const contentBottoms: WeakMap<Element, number> = new WeakMap();\n const viewportBottom: number = window.scrollY + viewportHeight;\n\n for (let i: number = elements.length - 1; i >= 0; i--) {\n const el: Element | undefined = elements[i];\n if (!el) continue;\n const childContentBottom: number = readChildrenContentBottom(el, contentBottoms);\n const metrics: ElementMetrics = readElementMetrics(el);\n const selfBottom: number = isViewportStretchedContainer(\n metrics,\n childContentBottom,\n viewportHeight,\n viewportBottom,\n )\n ? 0\n : metrics.bottom;\n contentBottoms.set(el, Math.max(childContentBottom, selfBottom));\n }\n\n return contentBottoms.get(document.body) ?? 0;\n}\n\nfunction readChildrenContentBottom(\n el: Element,\n contentBottoms: WeakMap<Element, number>,\n): number {\n let childContentBottom: number = 0;\n for (let i: number = 0; i < el.children.length; i++) {\n const child: Element | undefined = el.children[i];\n if (!child) continue;\n childContentBottom = Math.max(childContentBottom, contentBottoms.get(child) ?? 0);\n }\n return childContentBottom;\n}\n\ntype ElementMetrics = { bottom: number; height: number };\n\nfunction readElementMetrics(el: Element): ElementMetrics {\n const computedStyle: CSSStyleDeclaration = window.getComputedStyle(el);\n if (isOutOfFlowDecoration(computedStyle)) return { bottom: 0, height: 0 };\n const rect: DOMRect = el.getBoundingClientRect();\n if (rect.width === 0 && rect.height === 0) return { bottom: 0, height: 0 };\n return {\n bottom: rect.bottom + window.scrollY + readMarginBottom(computedStyle),\n height: rect.height,\n };\n}\n\nfunction readMarginBottom(computedStyle: CSSStyleDeclaration): number {\n const marginBottom: number = parseFloat(computedStyle.marginBottom);\n return Number.isFinite(marginBottom) ? marginBottom : 0;\n}\n\nfunction isOutOfFlowDecoration(computedStyle: CSSStyleDeclaration): boolean {\n if (computedStyle.position === \"fixed\") return true;\n return computedStyle.position === \"absolute\" && computedStyle.pointerEvents === \"none\";\n}\n\n// A \"stretched container\" spans the full viewport top-to-bottom. Requires\n// BOTH `bottom ≈ viewportBottom` AND `height ≈ viewportHeight` — otherwise an\n// in-flow section that just happens to end at viewportBottom (e.g. when the\n// iframe has been content-sized to the previous measurement) gets falsely\n// filtered, undermeasuring the page.\nfunction isViewportStretchedContainer(\n metrics: ElementMetrics,\n childBottom: number,\n viewportHeight: number,\n viewportBottom: number,\n): boolean {\n return (\n childBottom > 0 &&\n Math.abs(metrics.bottom - viewportBottom) <= 1 &&\n Math.abs(metrics.height - viewportHeight) <= 1 &&\n metrics.bottom - childBottom > 8\n );\n}\n\nfunction createDebouncer(fn: () => void, delayMs: number): Debouncer {\n let timer: number | undefined;\n return {\n trigger: (): void => {\n if (timer !== undefined) window.clearTimeout(timer);\n timer = window.setTimeout(fn, delayMs);\n },\n cancel: (): void => {\n if (timer !== undefined) {\n window.clearTimeout(timer);\n timer = undefined;\n }\n },\n };\n}\n","// auto-popup-suppressor — hides auto-opening modal popups in the canvas\n// preview iframe so the page snapshot isn't obscured by overlays the user\n// didn't intend to capture. Driven by `{ type: \"suppress-auto-popups\" }` from\n// the parent; inert until that arrives.\n//\n// Two-stage heuristic:\n//\n// 1. BACKDROP MATCH — element must be `position: fixed`, cover ≥90% of the\n// viewport on both axes, have a popup-level z-index, and show backdrop-\n// like styles (translucent background OR backdrop-filter). This is the\n// modal-overlay fingerprint.\n//\n// 2. PANEL SWEEP — once we've hidden any backdrop, sweep the whole document\n// for fixed/high-z elements whose bbox falls in a \"modal-shaped\" band\n// (15–95% on both axes). Picks up the dialog content panel even when it\n// isn't a direct sibling of the overlay (Radix wraps content in\n// FocusScope + DismissableLayer + focus-guards; shadcn's portals use\n// `asChild`, so structural relationships vary).\n//\n// A sticky `backdropEverDetected` flag keeps the panel-shape check live for\n// later MutationObserver ticks — Content sometimes mounts in a different\n// batch than its Overlay.\n//\n// Why the percentage gates aren't based on window.innerHeight: the canvas\n// iframe is auto-sized to the document content (e.g. 4958px), so innerHeight\n// is the document height, not the visible viewport. page-height-bridge sets\n// `--base44-reference-vh-base` to the canvas tile height — the viewport the\n// user actually sees — and that's what our gates use.\n\nconst SUPPRESSED_ATTR = \"data-base44-suppressed-popup\";\nconst REFERENCE_VH_BASE_VAR = \"--base44-reference-vh-base\";\n\nconst FULL_VIEWPORT_RATIO = 0.9;\nconst MODAL_PANEL_MIN_RATIO = 0.15;\nconst MODAL_PANEL_MAX_RATIO = 0.95;\nconst POPUP_Z_INDEX_THRESHOLD = 40;\n\ntype Viewport = { vw: number; vh: number };\n\nexport type AutoPopupSuppressorController = {\n suppress: () => void;\n teardown: () => void;\n};\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\nexport function createAutoPopupSuppressorController(): AutoPopupSuppressorController {\n let observer: MutationObserver | null = null;\n let domReadyHandler: (() => void) | null = null;\n let active = false;\n // Once a backdrop has been seen, modal-shaped panels appearing in later\n // mutation batches are also hidden. Without this, a Content node that\n // mounts after its Overlay's batch wouldn't be matched in-flight.\n let backdropEverDetected = false;\n\n // Single decision per element. One getComputedStyle call — backdrop and\n // panel checks share the position/z-index preconditions. Without sharing,\n // every non-matching node in a React commit's added subtree would pay for\n // two style recalcs, which is the MutationObserver hot path.\n const classify = (el: Element, vp: Viewport): void => {\n if (!(el instanceof HTMLElement)) return;\n if (el.hasAttribute(SUPPRESSED_ATTR)) return;\n const style = window.getComputedStyle(el);\n if (style.position !== \"fixed\") return;\n if (!hasPopupZIndex(style)) return;\n if (coversFullViewport(el, vp) && hasBackdropLook(el, style)) {\n hideBackdrop(el);\n return;\n }\n if (backdropEverDetected && hasModalShapeBbox(el, vp)) {\n applyHide(el);\n }\n };\n\n const hideBackdrop = (el: Element): void => {\n if (el.hasAttribute(SUPPRESSED_ATTR)) return;\n applyHide(el);\n backdropEverDetected = true;\n sweepDocumentForModalPanels(viewportForGates());\n };\n\n const scanSubtree = (root: Element, vp: Viewport): void => {\n classify(root, vp);\n const descendants = root.querySelectorAll<HTMLElement>(\n `*:not([${SUPPRESSED_ATTR}])`,\n );\n for (let i = 0; i < descendants.length; i++) {\n const el = descendants[i];\n if (el) classify(el, vp);\n }\n };\n\n const attachObserver = (): void => {\n if (observer) return;\n // viewportForGates is read once per mutation batch, not per added node —\n // a busy React commit can deliver dozens of added subtrees in one tick.\n observer = new MutationObserver((mutations) => {\n const vp = viewportForGates();\n for (const m of mutations) {\n if (m.type !== \"childList\") continue;\n for (let i = 0; i < m.addedNodes.length; i++) {\n const node = m.addedNodes[i];\n if (node instanceof Element) scanSubtree(node, vp);\n }\n }\n });\n observer.observe(document.documentElement, { childList: true, subtree: true });\n };\n\n const start = (): void => {\n if (!document.body) return;\n scanSubtree(document.body, viewportForGates());\n attachObserver();\n };\n\n return {\n suppress: (): void => {\n if (active) return;\n active = true;\n if (document.body) {\n start();\n } else {\n domReadyHandler = (): void => {\n domReadyHandler = null;\n start();\n };\n document.addEventListener(\"DOMContentLoaded\", domReadyHandler);\n }\n },\n teardown: (): void => {\n active = false;\n backdropEverDetected = false;\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n if (domReadyHandler) {\n document.removeEventListener(\"DOMContentLoaded\", domReadyHandler);\n domReadyHandler = null;\n }\n },\n };\n}\n\n// ── Document-wide panel sweep ───────────────────────────────────────────────\n\n// Triggered once per backdrop hide. Walks the whole document for unhidden\n// fixed/high-z elements whose bbox falls inside the modal-shape band — picks\n// up content panels regardless of how they're nested or which portal they\n// went through.\nfunction sweepDocumentForModalPanels(vp: Viewport): void {\n if (!document.body) return;\n if (vp.vw <= 0 || vp.vh <= 0) return;\n const candidates = document.body.querySelectorAll<HTMLElement>(\n `*:not([${SUPPRESSED_ATTR}])`,\n );\n for (let i = 0; i < candidates.length; i++) {\n const el = candidates[i];\n if (el && isModalPanel(el, vp)) applyHide(el);\n }\n}\n\nfunction isModalPanel(el: HTMLElement, vp: Viewport): boolean {\n if (el.hasAttribute(SUPPRESSED_ATTR)) return false;\n const style = window.getComputedStyle(el);\n if (style.position !== \"fixed\") return false;\n if (!hasPopupZIndex(style)) return false;\n return hasModalShapeBbox(el, vp);\n}\n\n// ── Gate predicates ─────────────────────────────────────────────────────────\n\nfunction coversFullViewport(el: HTMLElement, vp: Viewport): boolean {\n if (vp.vw <= 0 || vp.vh <= 0) return false;\n const rect = el.getBoundingClientRect();\n return (\n rect.width >= vp.vw * FULL_VIEWPORT_RATIO &&\n rect.height >= vp.vh * FULL_VIEWPORT_RATIO\n );\n}\n\n// \"Modal-shaped\" = small enough not to be a sidebar/full-screen overlay\n// (≤95% on both axes), big enough not to be a nav/footer/toast (≥15% on both\n// axes). Calibrated against shadcn Dialog content (≈25–50% × 30–50%), top\n// nav (height fails ≤15%), sidebar (height fails ≥95%), toast (height fails\n// ≤15%).\nfunction hasModalShapeBbox(el: HTMLElement, vp: Viewport): boolean {\n const rect = el.getBoundingClientRect();\n return (\n rect.width >= vp.vw * MODAL_PANEL_MIN_RATIO &&\n rect.height >= vp.vh * MODAL_PANEL_MIN_RATIO &&\n rect.width <= vp.vw * MODAL_PANEL_MAX_RATIO &&\n rect.height <= vp.vh * MODAL_PANEL_MAX_RATIO\n );\n}\n\nfunction hasPopupZIndex(style: CSSStyleDeclaration): boolean {\n const z = parseInt(style.zIndex, 10);\n return Number.isFinite(z) && z >= POPUP_Z_INDEX_THRESHOLD;\n}\n\n// True if the element looks like a modal backdrop: translucent fill OR a\n// backdrop-filter (e.g. blur). Also returns true if the element's own bg is\n// transparent but a fixed/high-z descendant paints the backdrop — covers\n// dialog wrappers that delegate the backdrop to a child element.\nfunction hasBackdropLook(el: HTMLElement, style: CSSStyleDeclaration): boolean {\n if (isTranslucent(style.backgroundColor)) return true;\n if (style.backdropFilter && style.backdropFilter !== \"none\") return true;\n const descendants = el.querySelectorAll<HTMLElement>(\"*\");\n for (let i = 0; i < descendants.length; i++) {\n const child = descendants[i];\n if (!child) continue;\n const cs = window.getComputedStyle(child);\n if (cs.position !== \"fixed\" && cs.position !== \"absolute\") continue;\n if (!hasPopupZIndex(cs)) continue;\n if (isTranslucent(cs.backgroundColor)) return true;\n if (cs.backdropFilter && cs.backdropFilter !== \"none\") return true;\n }\n return false;\n}\n\nfunction isTranslucent(color: string): boolean {\n const alpha = parseAlpha(color);\n return alpha !== null && alpha > 0 && alpha < 1;\n}\n\n// Extracts the alpha channel from a computed background-color across legacy\n// AND modern color syntaxes:\n//\n// • `rgb(r, g, b)` / `rgba(r, g, b, a)` — legacy comma syntax.\n// • `<func>(... / a)` / `<func>(... / a%)` — modern slash-alpha (oklch,\n// oklab, lch, lab, hsl, hsla, color, modern rgb). Tailwind v4 / shadcn\n// theme tokens compute to these.\n// • A recognized color function call without explicit alpha → 1.\n//\n// Returns null when unrecognized; callers treat null as \"not a backdrop\".\nfunction parseAlpha(value: string): number | null {\n if (!value) return null;\n const comma = /^rgba?\\(\\s*\\d+\\s*,\\s*\\d+\\s*,\\s*\\d+\\s*(?:,\\s*([0-9.]+)\\s*)?\\)$/.exec(value);\n if (comma) return comma[1] === undefined ? 1 : parseFloat(comma[1]);\n const slash = /\\/\\s*([0-9.]+)(%?)\\s*\\)$/.exec(value);\n if (slash) {\n const n = parseFloat(slash[1]!);\n return slash[2] === \"%\" ? n / 100 : n;\n }\n if (/^[a-z]+\\s*\\(/.test(value)) return 1;\n return null;\n}\n\n// ── Viewport + DOM ops ──────────────────────────────────────────────────────\n\n// Viewport dimensions used for percentage gates. Width comes from\n// `innerWidth` (unaffected by canvas auto-fit). Height prefers the reference\n// vh set by page-height-bridge — without that, after the iframe auto-resizes\n// to document content, `innerHeight` is the document height and every modal\n// panel falls below the 15% floor.\nfunction viewportForGates(): Viewport {\n const vw = window.innerWidth || document.documentElement.clientWidth || 0;\n const refStr = document.documentElement.style.getPropertyValue(REFERENCE_VH_BASE_VAR);\n const ref = parseFloat(refStr);\n const vh = Number.isFinite(ref) && ref > 0\n ? ref\n : (window.innerHeight || document.documentElement.clientHeight || 0);\n return { vw, vh };\n}\n\nfunction applyHide(el: Element): void {\n if (el.hasAttribute(SUPPRESSED_ATTR)) return;\n el.setAttribute(SUPPRESSED_ATTR, \"1\");\n (el as HTMLElement).style.setProperty(\"display\", \"none\", \"important\");\n}\n","import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, ALLOWED_ATTRIBUTES, getElementSelectorId, stopAnimations, resumeAnimations, findInstrumentedElement, resolveHoverTarget, positionLabel, injectFontFaceCss } from \"./utils.js\";\nimport { createLayerController } from \"./layer-dropdown/controller.js\";\nimport { LAYER_DROPDOWN_ATTR } from \"./layer-dropdown/consts.js\";\nimport { createInlineEditController } from \"../capabilities/inline-edit/index.js\";\nimport { THEME_FONT_PREVIEW_ID } from \"../consts.js\";\nimport { createCanvasWheelZoomBridgeController } from \"./canvas-wheel-zoom-bridge.js\";\nimport { createPageHeightBridgeController } from \"./page-height-bridge.js\";\nimport { createAutoPopupSuppressorController } from \"./auto-popup-suppressor.js\";\n\nconst REPOSITION_DELAY_MS = 50;\n\nexport function setupVisualEditAgent() {\n const canvasWheelZoomBridge = createCanvasWheelZoomBridgeController();\n const pageHeightBridge = createPageHeightBridgeController();\n const autoPopupSuppressor = createAutoPopupSuppressorController();\n\n // State variables (replacing React useState/useRef)\n let isVisualEditMode = false;\n let isPopoverDragging = false;\n let isDropdownOpen = false;\n let hoverOverlays: HTMLDivElement[] = [];\n let selectedOverlays: HTMLDivElement[] = [];\n let currentHighlightedElements: Element[] = [];\n let selectedElementId: string | null = null;\n let selectedElement: Element | null = null;\n\n // Create overlay element\n const createOverlay = (isSelected = false): HTMLDivElement => {\n const overlay = document.createElement(\"div\");\n overlay.style.position = \"absolute\";\n overlay.style.pointerEvents = \"none\";\n overlay.style.transition = \"all 0.1s ease-in-out\";\n overlay.style.zIndex = \"9999\";\n\n if (isSelected) {\n overlay.style.border = \"2px solid #2563EB\";\n } else {\n overlay.style.border = \"2px solid #95a5fc\";\n overlay.style.backgroundColor = \"rgba(99, 102, 241, 0.05)\";\n }\n\n return overlay;\n };\n\n // Position overlay relative to element\n const positionOverlay = (\n overlay: HTMLDivElement,\n element: Element,\n isSelected = false\n ) => {\n if (!element || !isVisualEditMode) return;\n\n const htmlElement = element as HTMLElement;\n // Force layout recalculation\n void htmlElement.offsetWidth;\n\n const rect = element.getBoundingClientRect();\n overlay.style.top = `${rect.top + window.scrollY}px`;\n overlay.style.left = `${rect.left + window.scrollX}px`;\n overlay.style.width = `${rect.width}px`;\n overlay.style.height = `${rect.height}px`;\n\n // Check if label already exists in overlay\n let label = overlay.querySelector(\"div\") as HTMLDivElement | null;\n\n if (!label) {\n label = document.createElement(\"div\");\n label.textContent = element.tagName.toLowerCase();\n label.style.position = \"absolute\";\n label.style.left = \"-2px\";\n label.style.padding = \"2px 8px\";\n label.style.fontSize = \"11px\";\n label.style.fontWeight = isSelected ? \"500\" : \"400\";\n label.style.color = isSelected ? \"#ffffff\" : \"#526cff\";\n label.style.backgroundColor = isSelected ? \"#2563EB\" : \"#DBEAFE\";\n label.style.borderRadius = \"3px\";\n label.style.minWidth = \"24px\";\n label.style.textAlign = \"center\";\n overlay.appendChild(label);\n }\n\n positionLabel(label, rect);\n };\n\n // --- Inline edit controller ---\n const inlineEdit = createInlineEditController({\n findElementsById,\n getSelectedElementId: () => selectedElementId,\n getSelectedOverlays: () => selectedOverlays,\n positionOverlay,\n clearSelection: () => {\n inlineEdit.clearSelectedMarks(selectedElementId);\n clearSelectedOverlays();\n selectedElementId = null;\n selectedElement = null;\n },\n createSelectionOverlays: (elements, elementId) => {\n elements.forEach((el) => {\n const overlay = createOverlay(true);\n document.body.appendChild(overlay);\n selectedOverlays.push(overlay);\n positionOverlay(overlay, el, true);\n });\n selectedElementId = elementId;\n },\n });\n\n const clearSelection = () => {\n inlineEdit.clearSelectedMarks(selectedElementId);\n clearSelectedOverlays();\n selectedElementId = null;\n selectedElement = null;\n };\n\n // Clear hover overlays\n const clearHoverOverlays = () => {\n hoverOverlays.forEach((overlay) => {\n if (overlay && overlay.parentNode) {\n overlay.remove();\n }\n });\n hoverOverlays = [];\n currentHighlightedElements = [];\n };\n\n const clearSelectedOverlays = () => {\n selectedOverlays.forEach((overlay) => {\n if (overlay && overlay.parentNode) {\n overlay.remove();\n }\n });\n selectedOverlays = [];\n };\n\n const TEXT_TAGS = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'a', 'label'];\n\n const notifyElementSelected = (element: Element) => {\n const htmlElement = element as HTMLElement;\n const rect = element.getBoundingClientRect();\n const svgElement = element as SVGElement;\n const isTextElement = TEXT_TAGS.includes(element.tagName?.toLowerCase());\n\n const arrEl = htmlElement.closest(\"[data-arr-variable-name]\") as HTMLElement | null;\n const staticArrayName = arrEl?.dataset?.arrVariableName || null;\n const rawIdx = arrEl?.dataset?.arrIndex;\n const staticArrayIndex = rawIdx != null ? parseInt(rawIdx, 10) : null;\n const staticArrayField = htmlElement.dataset?.arrField || null;\n\n const collectionEl = htmlElement.closest(\"[data-collection-id]\") as HTMLElement | null;\n const itemFieldEl = htmlElement.closest(\"[data-collection-item-field]\") as HTMLElement | null;\n const itemIdEl = htmlElement.closest(\"[data-collection-item-id]\") as HTMLElement | null;\n\n window.parent.postMessage({\n type: \"element-selected\",\n tagName: element.tagName,\n classes:\n (svgElement.className as unknown as SVGAnimatedString)?.baseVal ||\n element.className ||\n \"\",\n visualSelectorId: getElementSelectorId(element),\n content: isTextElement ? htmlElement.innerText : undefined,\n dataSourceLocation: htmlElement.dataset.sourceLocation,\n isDynamicContent: htmlElement.dataset.dynamicContent === \"true\",\n linenumber: htmlElement.dataset.linenumber,\n filename: htmlElement.dataset.filename,\n position: {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n centerX: rect.left + rect.width / 2,\n centerY: rect.top + rect.height / 2,\n },\n attributes: collectAllowedAttributes(element, ALLOWED_ATTRIBUTES),\n isTextElement,\n staticArrayName,\n staticArrayIndex,\n staticArrayField,\n collectionId: collectionEl?.dataset?.collectionId || null,\n collectionItemField: itemFieldEl?.dataset?.collectionItemField || null,\n collectionItemId: itemIdEl?.dataset?.collectionItemId || null,\n }, \"*\");\n };\n\n // Select an element: create overlays, update state, notify parent\n const selectElement = (element: Element): HTMLDivElement | undefined => {\n const visualSelectorId = getElementSelectorId(element);\n\n clearSelectedOverlays();\n\n const elements = findElementsById(visualSelectorId || null);\n elements.forEach((el) => {\n const overlay = createOverlay(true);\n document.body.appendChild(overlay);\n selectedOverlays.push(overlay);\n positionOverlay(overlay, el, true);\n });\n\n selectedElementId = visualSelectorId || null;\n selectedElement = element;\n clearHoverOverlays();\n notifyElementSelected(element);\n\n return selectedOverlays[0];\n };\n\n const notifyDeselection = (): void => {\n selectedElementId = null;\n window.parent.postMessage({ type: \"unselect-element\" }, \"*\");\n };\n\n // Hover detection via mousemove + elementFromPoint (since app elements have pointer-events: none)\n let lastHoveredSelectorId: string | null = null;\n let pendingMouseMoveRaf: number | null = null;\n\n const clearHoverState = () => {\n clearHoverOverlays();\n lastHoveredSelectorId = null;\n };\n\n const applyHoverOverlays = (selectorId: string) => {\n const elements = findElementsById(selectorId);\n clearHoverOverlays();\n\n elements.forEach((el) => {\n const overlay = createOverlay(false);\n document.body.appendChild(overlay);\n hoverOverlays.push(overlay);\n positionOverlay(overlay, el);\n });\n\n currentHighlightedElements = elements;\n lastHoveredSelectorId = selectorId;\n };\n\n const handleMouseMove = (e: MouseEvent) => {\n if (!isVisualEditMode || isPopoverDragging || inlineEdit.isEditing()) return;\n\n if (pendingMouseMoveRaf !== null) return;\n pendingMouseMoveRaf = requestAnimationFrame(() => {\n pendingMouseMoveRaf = null;\n\n if (isDropdownOpen) { clearHoverState(); return; }\n\n const selectorId = resolveHoverTarget(e.clientX, e.clientY, selectedElementId);\n if (!selectorId) { clearHoverState(); return; }\n if (lastHoveredSelectorId === selectorId) return;\n\n applyHoverOverlays(selectorId);\n });\n };\n\n // Clear hover overlays when mouse leaves the viewport\n const handleMouseLeave = () => {\n if (pendingMouseMoveRaf !== null) {\n cancelAnimationFrame(pendingMouseMoveRaf);\n pendingMouseMoveRaf = null;\n }\n clearHoverState();\n };\n\n // Handle element click\n const handleElementClick = (e: MouseEvent) => {\n if (!isVisualEditMode) return;\n\n const target = e.target as Element;\n\n // Let layer dropdown clicks pass through without interference\n if (target.closest(`[${LAYER_DROPDOWN_ATTR}]`)) return;\n\n // Let clicks inside the editable element pass through to the browser\n // so the user can reposition the cursor and select text naturally.\n if (inlineEdit.enabled && target instanceof HTMLElement && target.contentEditable === \"true\") {\n return;\n }\n\n // Clicking outside the editable element exits inline editing mode.\n if (inlineEdit.isEditing()) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n inlineEdit.stopEditing();\n return;\n }\n\n // Close dropdowns when clicking anywhere in iframe if a dropdown is open\n if (isDropdownOpen) {\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n\n window.parent.postMessage({ type: \"close-dropdowns\" }, \"*\");\n return;\n }\n\n // Prevent default behavior immediately when in visual edit mode\n e.preventDefault();\n e.stopPropagation();\n e.stopImmediatePropagation();\n\n const element = findInstrumentedElement(e.clientX, e.clientY);\n if (!element) {\n return;\n }\n\n const htmlElement = element as HTMLElement;\n const visualSelectorId = getElementSelectorId(element);\n\n const isAlreadySelected =\n selectedElementId === visualSelectorId &&\n htmlElement.dataset.selected === \"true\";\n\n if (isAlreadySelected && inlineEdit.enabled && inlineEdit.canEdit(htmlElement)) {\n inlineEdit.startEditing(htmlElement);\n return;\n }\n\n inlineEdit.stopEditing();\n\n if (inlineEdit.enabled) {\n inlineEdit.markElementsSelected(findElementsById(visualSelectorId));\n }\n\n const selectedOverlay = selectElement(element);\n layerController.attachToOverlay(selectedOverlay, element);\n };\n\n const unselectElement = () => {\n inlineEdit.stopEditing();\n clearSelection();\n };\n\n const updateElementClassesAndReposition = (visualSelectorId: string, classes: string) => {\n const elements = findElementsById(visualSelectorId);\n if (elements.length === 0) return;\n\n updateElementClasses(elements, classes);\n\n // Use a small delay to allow the browser to recalculate layout before repositioning\n setTimeout(() => {\n // Reposition selected overlays\n if (selectedElementId === visualSelectorId) {\n selectedOverlays.forEach((overlay, index) => {\n if (index < elements.length) {\n positionOverlay(overlay, elements[index]!);\n }\n });\n }\n\n // Reposition hover overlays if needed\n if (currentHighlightedElements.length > 0) {\n const hoveredElement = currentHighlightedElements[0] as HTMLElement;\n const hoveredId = hoveredElement?.dataset?.visualSelectorId;\n if (hoveredId === visualSelectorId) {\n hoverOverlays.forEach((overlay, index) => {\n if (index < currentHighlightedElements.length) {\n positionOverlay(overlay, currentHighlightedElements[index]!);\n }\n });\n }\n }\n }, REPOSITION_DELAY_MS);\n };\n\n // Update element attribute by visual selector ID\n const updateElementAttributeAndReposition = (\n visualSelectorId: string,\n attribute: string,\n value: string,\n arrIndex?: number | string\n ) => {\n const elements = findElementsById(visualSelectorId);\n if (elements.length === 0) return;\n\n const targetArrIndex =\n arrIndex ??\n (selectedElementId === visualSelectorId\n ? (selectedElement as HTMLElement | null)?.dataset.arrIndex\n : undefined);\n\n updateElementAttribute(elements, attribute, value, targetArrIndex);\n\n // Reposition overlays after attribute change (e.g. image src swap can affect layout)\n setTimeout(() => {\n if (selectedElementId === visualSelectorId) {\n selectedOverlays.forEach((overlay, index) => {\n if (index < elements.length) {\n positionOverlay(overlay, elements[index]!);\n }\n });\n }\n }, REPOSITION_DELAY_MS);\n };\n\n const updateElementContent = (visualSelectorId: string, content: string, arrIndex?: number) => {\n let elements = findElementsById(visualSelectorId);\n\n if (elements.length === 0) {\n return;\n }\n\n if (arrIndex != null) {\n elements = elements.filter(\n (el) => (el as HTMLElement).dataset.arrIndex === String(arrIndex)\n );\n }\n\n elements.forEach((element) => {\n (element as HTMLElement).innerText = content;\n });\n\n setTimeout(() => {\n if (selectedElementId === visualSelectorId) {\n selectedOverlays.forEach((overlay, index) => {\n if (index < elements.length) {\n positionOverlay(overlay, elements[index]!);\n }\n });\n }\n }, REPOSITION_DELAY_MS);\n };\n\n // --- Layer dropdown controller ---\n const layerController = createLayerController({\n createPreviewOverlay: (element: Element) => {\n const overlay = createOverlay(false);\n overlay.style.zIndex = \"9998\";\n document.body.appendChild(overlay);\n positionOverlay(overlay, element);\n return overlay;\n },\n getSelectedElementId: () => selectedElementId,\n selectElement,\n onDeselect: notifyDeselection,\n });\n\n // Toggle visual edit mode\n const toggleVisualEditMode = (isEnabled: boolean) => {\n isVisualEditMode = isEnabled;\n\n if (!isEnabled) {\n canvasWheelZoomBridge.disable();\n resumeAnimations();\n inlineEdit.stopEditing();\n clearSelection();\n layerController.cleanup();\n handleMouseLeave();\n document.body.style.cursor = \"default\";\n\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseleave\", handleMouseLeave);\n document.removeEventListener(\"click\", handleElementClick, true);\n } else {\n document.body.style.cursor = \"crosshair\";\n stopAnimations();\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseleave\", handleMouseLeave);\n document.addEventListener(\"click\", handleElementClick, true);\n }\n };\n\n // Handle scroll events to update popover position\n const handleScroll = () => {\n if (selectedElementId) {\n const element = selectedElement;\n if (element && element.isConnected) {\n const rect = element.getBoundingClientRect();\n\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n const isInViewport =\n rect.top < viewportHeight &&\n rect.bottom > 0 &&\n rect.left < viewportWidth &&\n rect.right > 0;\n\n const elementPosition = {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n centerX: rect.left + rect.width / 2,\n centerY: rect.top + rect.height / 2,\n };\n\n window.parent.postMessage(\n {\n type: \"element-position-update\",\n position: elementPosition,\n isInViewport: isInViewport,\n visualSelectorId: selectedElementId,\n },\n \"*\"\n );\n }\n }\n };\n\n // Handle messages from parent window\n const handleMessage = (event: MessageEvent) => {\n const message = event.data;\n\n switch (message.type) {\n case \"toggle-visual-edit-mode\":\n toggleVisualEditMode(message.data.enabled);\n if (message.data.specs?.newInlineEditEnabled !== undefined) {\n inlineEdit.enabled = message.data.specs.newInlineEditEnabled;\n }\n break;\n\n case \"update-classes\":\n if (message.data && message.data.classes !== undefined) {\n updateElementClassesAndReposition(\n message.data.visualSelectorId,\n message.data.classes\n );\n } else {\n console.warn(\n \"[VisualEditAgent] Invalid update-classes message:\",\n message\n );\n }\n break;\n\n case \"update-attribute\":\n if (\n message.data &&\n message.data.visualSelectorId &&\n message.data.attribute !== undefined &&\n message.data.value !== undefined\n ) {\n updateElementAttributeAndReposition(\n message.data.visualSelectorId,\n message.data.attribute,\n message.data.value,\n message.data.arrIndex\n );\n } else {\n console.warn(\n \"[VisualEditAgent] Invalid update-attribute message:\",\n message\n );\n }\n break;\n\n case \"unselect-element\":\n unselectElement();\n break;\n\n case \"refresh-page\":\n window.location.reload();\n break;\n\n case \"update-content\":\n if (message.data && message.data.content !== undefined) {\n updateElementContent(\n message.data.visualSelectorId,\n message.data.content,\n message.data.arrIndex\n );\n } else {\n console.warn(\n \"[VisualEditAgent] Invalid update-content message:\",\n message\n );\n }\n break;\n\n case \"request-element-position\":\n if (selectedElementId && selectedElement && selectedElement.isConnected) {\n const rect = selectedElement.getBoundingClientRect();\n\n const viewportHeight = window.innerHeight;\n const viewportWidth = window.innerWidth;\n const isInViewport =\n rect.top < viewportHeight &&\n rect.bottom > 0 &&\n rect.left < viewportWidth &&\n rect.right > 0;\n\n const elementPosition = {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n centerX: rect.left + rect.width / 2,\n centerY: rect.top + rect.height / 2,\n };\n\n window.parent.postMessage(\n {\n type: \"element-position-update\",\n position: elementPosition,\n isInViewport: isInViewport,\n visualSelectorId: selectedElementId,\n },\n \"*\"\n );\n }\n break;\n\n case \"popover-drag-state\":\n if (message.data && message.data.isDragging !== undefined) {\n isPopoverDragging = message.data.isDragging;\n if (message.data.isDragging) {\n clearHoverOverlays();\n }\n }\n break;\n\n case \"dropdown-state\":\n if (message.data && message.data.isOpen !== undefined) {\n isDropdownOpen = message.data.isOpen;\n if (message.data.isOpen) {\n clearHoverOverlays();\n }\n }\n break;\n\n case \"update-theme-variables\":\n if (message.data?.variables) {\n const target = message.data.mode === 'dark'\n ? document.querySelector('.dark') as HTMLElement\n : document.documentElement;\n if (target) {\n for (const [name, value] of Object.entries(message.data.variables)) {\n target.style.setProperty(name, value as string);\n }\n }\n }\n break;\n\n case \"inject-font-import\":\n if (message.data?.fontUrl) {\n let fontStyle = document.getElementById(THEME_FONT_PREVIEW_ID) as HTMLStyleElement | null;\n if (!fontStyle) {\n fontStyle = document.createElement('style');\n fontStyle.id = THEME_FONT_PREVIEW_ID;\n document.head.appendChild(fontStyle);\n }\n fontStyle.textContent = `@import url('${message.data.fontUrl}');`;\n }\n break;\n\n case \"inject-font-face\":\n if (message.data) {\n injectFontFaceCss(message.data.id, message.data.css);\n }\n break;\n\n case \"toggle-inline-edit-mode\":\n if (message.data) {\n inlineEdit.handleToggleMessage(message.data);\n }\n break;\n\n case \"freeze-vh-units\":\n pageHeightBridge.freezeVhUnits(\n typeof message.referenceVhBase === \"number\"\n ? message.referenceVhBase\n : undefined\n );\n break;\n\n case \"measure-page-height\":\n pageHeightBridge.measurePageHeight(\n event.origin && event.origin !== \"null\" ? event.origin : \"*\",\n typeof message.settleMs === \"number\" ? message.settleMs : undefined\n );\n break;\n\n case \"suppress-auto-popups\":\n autoPopupSuppressor.suppress();\n break;\n\n case \"toggle-canvas-wheel-zoom-bridge\":\n canvasWheelZoomBridge.enable();\n break;\n\n default:\n break;\n }\n };\n\n // Handle window resize to reposition overlays\n const handleResize = () => {\n if (selectedElementId) {\n const elements = findElementsById(selectedElementId);\n selectedOverlays.forEach((overlay, index) => {\n if (index < elements.length) {\n positionOverlay(overlay, elements[index]!);\n }\n });\n }\n\n if (currentHighlightedElements.length > 0) {\n hoverOverlays.forEach((overlay, index) => {\n if (index < currentHighlightedElements.length) {\n positionOverlay(overlay, currentHighlightedElements[index]!);\n }\n });\n }\n };\n\n // Initialize: Add IDs to elements that don't have them but have linenumbers\n const elementsWithLineNumber = document.querySelectorAll(\n \"[data-linenumber]:not([data-visual-selector-id])\"\n );\n elementsWithLineNumber.forEach((el, index) => {\n const htmlEl = el as HTMLElement;\n const id = `visual-id-${htmlEl.dataset.filename}-${htmlEl.dataset.linenumber}-${index}`;\n htmlEl.dataset.visualSelectorId = id;\n });\n\n // Create mutation observer to detect layout changes\n const mutationObserver = new MutationObserver((mutations) => {\n const needsUpdate = mutations.some((mutation) => {\n const hasVisualId = (node: Node): boolean => {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as HTMLElement;\n if (el.dataset && el.dataset.visualSelectorId) {\n return true;\n }\n for (let i = 0; i < el.children.length; i++) {\n if (hasVisualId(el.children[i]!)) {\n return true;\n }\n }\n }\n return false;\n };\n\n const isLayoutChange =\n mutation.type === \"attributes\" &&\n (mutation.attributeName === \"style\" ||\n mutation.attributeName === \"class\" ||\n mutation.attributeName === \"width\" ||\n mutation.attributeName === \"height\");\n\n return isLayoutChange && hasVisualId(mutation.target);\n });\n\n if (needsUpdate) {\n setTimeout(handleResize, REPOSITION_DELAY_MS);\n }\n });\n\n // Set up event listeners\n window.addEventListener(\"message\", handleMessage);\n window.addEventListener(\"scroll\", handleScroll, true);\n document.addEventListener(\"scroll\", handleScroll, true);\n window.addEventListener(\"resize\", handleResize);\n window.addEventListener(\"scroll\", handleResize);\n\n // Start observing DOM mutations\n mutationObserver.observe(document.body, {\n attributes: true,\n childList: true,\n subtree: true,\n attributeFilter: [\"style\", \"class\", \"width\", \"height\"],\n });\n\n // Send ready message to parent\n window.parent.postMessage({ type: \"visual-edit-agent-ready\" }, \"*\");\n}\n"],"mappings":"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","names":["positionLabel","label","rect","nearTop","tallEnough","isFullWidth","edgeLeft","insideLeft","isInstrumentedElement","element","htmlEl","getElementSelectorId","ALLOWED_ATTRIBUTES","PLUGIN_ELEMENT_ATTR","findElementsById","id","sourceElements","updateElementClasses","elements","classes","updateElementAttribute","attribute","value","arrIndex","targetArrIndex","collectAllowedAttributes","allowedAttributes","attributes","attr","val","stopAnimations","animStyle","pointerStyle","target","a","animTarget","resumeAnimations","findInstrumentedElement","x","y","el","resolveHoverTarget","selectedElementId","selectorId","VISUAL_EDIT_FONT_FACE_ID_PREFIX","isValidFontFaceCss","css","trimmed","openBraces","closeBraces","chunks","i","end","url","injectFontFaceCss","styleId","style","DROPDOWN_CONTAINER_STYLES","DROPDOWN_ITEM_BASE_STYLES","DROPDOWN_ITEM_ACTIVE_COLOR","DROPDOWN_ITEM_ACTIVE_BG","DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT","DROPDOWN_ITEM_HOVER_BG","DEPTH_INDENT_PX","CHEVRON_COLLAPSED","CHEVRON_EXPANDED","CHEVRON_ATTR","BASE_PADDING_PX","LAYER_DROPDOWN_ATTR","MAX_PARENT_DEPTH","MAX_CHILD_DEPTH","applyStyles","element","styles","key","m","getLayerDisplayName","layer","toLayerInfo","depth","info","getElementSelectorId","getInstrumentedDescendants","parent","maxDepth","startDepth","result","walk","el","instrDepth","i","child","isInstrumentedElement","collectInstrumentedParents","selectedElement","parents","current","MAX_PARENT_DEPTH","addParentsToChain","chain","p","addSelfAndDescendantsToChain","selfDepth","descendants","MAX_CHILD_DEPTH","getImmediateInstrParent","collectSiblings","siblings","s","appendSiblingsWithSelected","selectedSelectorId","seen","sibling","id","buildLayerChain","instrParent","activeDropdown","activeLabel","outsideMousedownHandler","activeOnHoverEnd","activeKeydownHandler","createDropdownItem","layer","isActive","onSelect","onHover","onHoverEnd","item","getLayerDisplayName","applyStyles","DROPDOWN_ITEM_BASE_STYLES","depth","BASE_PADDING_PX","DEPTH_INDENT_PX","DROPDOWN_ITEM_ACTIVE_COLOR","DROPDOWN_ITEM_ACTIVE_BG","DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT","DROPDOWN_ITEM_HOVER_BG","e","createDropdownElement","layers","currentElement","callbacks","container","LAYER_DROPDOWN_ATTR","PLUGIN_ELEMENT_ATTR","DROPDOWN_CONTAINER_STYLES","enhanceLabelWithChevron","label","CHEVRON_ATTR","chevron","CHEVRON_COLLAPSED","setupKeyboardNavigation","dropdown","items","focusedIndex","l","setFocusedItem","index","prev","cur","closeDropdown","setupOutsideClickHandler","skipFirst","target","showDropdown","overlay","chevronEl","CHEVRON_EXPANDED","isDropdownOpen","createLayerController","config","layerPreviewOverlay","escapeHandler","dropdownSourceLayer","clearLayerPreview","showLayerPreview","layer","getElementSelectorId","selectLayer","closeDropdown","firstOverlay","attachToOverlay","restoreSelection","handleLabelClick","e","label","element","layers","currentId","isDropdownOpen","ev","showDropdown","overlay","buildLayerChain","enhanceLabelWithChevron","FOCUS_STYLE_ID","EDITABLE_TAGS","isStaticArrayTextElement","element","passesStructuralChecks","injectFocusOutlineCSS","style","removeFocusOutlineCSS","selectText","range","selection","isEditableTextElement","shouldEnterInlineEditingMode","DEBOUNCE_MS","createInlineEditController","host","currentEditingElement","debouncedSendTimeout","enabled","listenerAbortControllers","repositionOverlays","selectedId","elements","overlay","i","reportEdit","element","originalContent","newContent","svgElement","rect","message","isStaticArrayTextElement","debouncedReport","onTextInput","handleInputEvent","makeEditable","injectFocusOutlineCSS","PLUGIN_ELEMENT_ATTR","abortController","selectText","makeNonEditable","removeFocusOutlineCSS","value","shouldEnterInlineEditingMode","o","el","elementId","data","THEME_FONT_PREVIEW_ID","elementFromEventTarget","target","isPluginOwnedTarget","PLUGIN_ELEMENT_ATTR","createCanvasWheelZoomBridgeController","isEnabled","onWheel","event","panData","REFERENCE_VH_BASE_VAR","createPageHeightBridgeController","vhCleanups","vhForceRun","pendingSettle","pendingTick","pendingOrigin","cancelPending","override","referenceVhBase","resolveReferenceVhBase","setReferenceVhBase","startVhNeutralizer","origin","settleMs","deadline","nowMs","lastHeight","stableSamples","respond","height","tick","measureContentHeight","c","detected","REFERENCE_VH_BASE_VAR","cleanups","VH_RE","processedStyles","processedSheets","watchedStyles","styleObservers","unscrolled","rewrite","input","_match","n","formatVhFactor","unscrollY","el","ovY","unscrollSubtree","root","rewriteInlineStyle","style","props","i","prop","value","next","debouncer","createDebouncer","watchStyleEl","text","sheet","rules","rewriteVhInRules","debouncedNeutralize","obs","headObserver","mutations","m","containsStylesheetNode","attachHeadObserver","scanSubtreeForInlineVh","node","attr","inlineStyleObserver","target","rule","j","nodes","scrollHeight","readReferenceVhBase","viewportHeight","contentBottom","measureElementContentBottom","parsed","elements","contentBottoms","viewportBottom","childContentBottom","readChildrenContentBottom","metrics","readElementMetrics","selfBottom","isViewportStretchedContainer","child","computedStyle","isOutOfFlowDecoration","rect","readMarginBottom","marginBottom","childBottom","fn","delayMs","timer","SUPPRESSED_ATTR","REFERENCE_VH_BASE_VAR","createAutoPopupSuppressorController","observer","domReadyHandler","active","backdropEverDetected","classify","el","vp","SUPPRESSED_ATTR","style","hasPopupZIndex","coversFullViewport","hasBackdropLook","hideBackdrop","hasModalShapeBbox","applyHide","sweepDocumentForModalPanels","viewportForGates","scanSubtree","root","descendants","i","attachObserver","mutations","m","node","start","candidates","isModalPanel","rect","z","isTranslucent","child","cs","color","alpha","parseAlpha","value","comma","slash","n","vw","refStr","REFERENCE_VH_BASE_VAR","ref","vh","REPOSITION_DELAY_MS","setupVisualEditAgent","canvasWheelZoomBridge","createCanvasWheelZoomBridgeController","pageHeightBridge","createPageHeightBridgeController","autoPopupSuppressor","createAutoPopupSuppressorController","isVisualEditMode","isPopoverDragging","isDropdownOpen","hoverOverlays","selectedOverlays","currentHighlightedElements","selectedElementId","selectedElement","createOverlay","isSelected","overlay","positionOverlay","element","rect","label","positionLabel","inlineEdit","createInlineEditController","findElementsById","clearSelectedOverlays","elements","elementId","el","clearSelection","clearHoverOverlays","TEXT_TAGS","notifyElementSelected","htmlElement","svgElement","isTextElement","arrEl","staticArrayName","rawIdx","staticArrayIndex","staticArrayField","collectionEl","itemFieldEl","itemIdEl","getElementSelectorId","collectAllowedAttributes","ALLOWED_ATTRIBUTES","selectElement","visualSelectorId","notifyDeselection","lastHoveredSelectorId","pendingMouseMoveRaf","clearHoverState","applyHoverOverlays","selectorId","handleMouseMove","e","resolveHoverTarget","handleMouseLeave","handleElementClick","target","LAYER_DROPDOWN_ATTR","findInstrumentedElement","selectedOverlay","layerController","unselectElement","updateElementClassesAndReposition","classes","updateElementClasses","index","updateElementAttributeAndReposition","attribute","value","arrIndex","targetArrIndex","updateElementAttribute","updateElementContent","content","createLayerController","toggleVisualEditMode","isEnabled","stopAnimations","resumeAnimations","handleScroll","viewportHeight","viewportWidth","isInViewport","elementPosition","handleMessage","event","message","name","fontStyle","THEME_FONT_PREVIEW_ID","injectFontFaceCss","handleResize","htmlEl","id","mutationObserver","mutations","mutation","hasVisualId","node","i"]} |