@base44-preview/vite-plugin 0.2.22-pr.36.019589c → 0.2.22-pr.36.9cc89ea

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/injections/layer-dropdown/component/{dropdown-ui.d.ts → dropdown.d.ts} +2 -5
  2. package/dist/injections/layer-dropdown/component/dropdown.d.ts.map +1 -0
  3. package/dist/injections/layer-dropdown/component/{dropdown-ui.js → dropdown.js} +64 -72
  4. package/dist/injections/layer-dropdown/component/dropdown.js.map +1 -0
  5. package/dist/injections/layer-dropdown/controller.d.ts +4 -0
  6. package/dist/injections/layer-dropdown/controller.d.ts.map +1 -0
  7. package/dist/injections/layer-dropdown/controller.js +85 -0
  8. package/dist/injections/layer-dropdown/controller.js.map +1 -0
  9. package/dist/injections/layer-dropdown/types.d.ts +21 -0
  10. package/dist/injections/layer-dropdown/types.d.ts.map +1 -0
  11. package/dist/injections/layer-dropdown/types.js +3 -0
  12. package/dist/injections/layer-dropdown/types.js.map +1 -0
  13. package/dist/injections/layer-dropdown/utils.d.ts +4 -7
  14. package/dist/injections/layer-dropdown/utils.d.ts.map +1 -1
  15. package/dist/injections/layer-dropdown/utils.js +5 -1
  16. package/dist/injections/layer-dropdown/utils.js.map +1 -1
  17. package/dist/injections/visual-edit-agent.d.ts.map +1 -1
  18. package/dist/injections/visual-edit-agent.js +73 -199
  19. package/dist/injections/visual-edit-agent.js.map +1 -1
  20. package/dist/statics/index.mjs +1 -1
  21. package/dist/statics/index.mjs.map +1 -1
  22. package/package.json +1 -1
  23. package/src/injections/layer-dropdown/component/{dropdown-ui.ts → dropdown.ts} +94 -93
  24. package/src/injections/layer-dropdown/controller.ts +105 -0
  25. package/src/injections/layer-dropdown/types.ts +24 -0
  26. package/src/injections/layer-dropdown/utils.ts +6 -6
  27. package/src/injections/visual-edit-agent.ts +81 -237
  28. package/dist/injections/layer-dropdown/component/dropdown-ui.d.ts.map +0 -1
  29. package/dist/injections/layer-dropdown/component/dropdown-ui.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/injections/utils.ts","../../src/injections/layer-dropdown/consts.ts","../../src/injections/layer-dropdown/utils.ts","../../src/injections/layer-dropdown/component/dropdown-ui.ts","../../src/injections/visual-edit-agent.ts"],"sourcesContent":["/** 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\n/** Find the nearest instrumented ancestor (not the element itself) */\nexport function getImmediateInstrumentedParent(element: Element): Element | null {\n let current = element.parentElement;\n while (\n current &&\n current !== document.documentElement &&\n current !== document.body\n ) {\n if (isInstrumentedElement(current)) {\n return current;\n }\n current = current.parentElement;\n }\n return null;\n}\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","/** 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\nexport const LABEL_CHEVRON = \" \\u25BE\";\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 traversal utilities for building the layer chain of instrumented elements */\n\nimport { isInstrumentedElement, getElementSelectorId } from \"../utils.js\";\nimport { MAX_PARENT_DEPTH, MAX_CHILD_DEPTH } from \"./consts.js\";\n\nexport interface LayerInfo {\n element: Element;\n tagName: string;\n selectorId: string | null;\n depth?: number;\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\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 */\nexport function getInstrumentedDescendants(\n parent: Element,\n maxDepth: 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 result.push({\n element: child,\n tagName: child.tagName.toLowerCase(),\n selectorId: getElementSelectorId(child),\n });\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/**\n * Build the layer chain for the dropdown:\n *\n * Parents – up to MAX_PARENT_DEPTH instrumented ancestors, outer → inner.\n * Current – the selected element.\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 // --- Parents (walk up, collect at most MAX_PARENT_DEPTH) ---\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({\n element: current,\n tagName: current.tagName.toLowerCase(),\n selectorId: getElementSelectorId(current),\n });\n }\n current = current.parentElement;\n }\n // Reverse so outermost parent comes first\n parents.reverse();\n\n // --- Build the chain with depth ---\n const chain: LayerInfo[] = [];\n const baseDepth = 0;\n\n // Parents: depth 0, 1, …\n parents.forEach((p, i) => {\n chain.push({ ...p, depth: baseDepth + i });\n });\n\n // Self\n const selfDepth = parents.length;\n chain.push({\n element: selectedElement,\n tagName: selectedElement.tagName.toLowerCase(),\n selectorId: getElementSelectorId(selectedElement),\n depth: selfDepth,\n });\n\n // Children: up to MAX_CHILD_DEPTH instrumented levels below selected\n const descendants = getInstrumentedDescendants(\n selectedElement,\n MAX_CHILD_DEPTH\n );\n // Assign visual depth: we need to track the instrumented nesting to set depth correctly\n assignDescendantDepths(selectedElement, descendants, selfDepth + 1);\n\n chain.push(...descendants);\n return chain;\n}\n\n/**\n * Walk the DOM tree again to assign correct visual depth to each descendant.\n * This avoids storing depth during collection and keeps the API simple.\n */\nfunction assignDescendantDepths(\n root: Element,\n descendants: LayerInfo[],\n startDepth: number\n): void {\n // Build a set for O(1) lookup\n const descSet = new Set(descendants.map((d) => d.element));\n // Map element → LayerInfo for mutation\n const descMap = new Map(descendants.map((d) => [d.element, d]));\n\n function walk(el: Element, instrDepth: number): void {\n for (let i = 0; i < el.children.length; i++) {\n const child = el.children[i]!;\n if (descSet.has(child)) {\n descMap.get(child)!.depth = startDepth + instrDepth - 1;\n walk(child, instrDepth + 1);\n } else {\n walk(child, instrDepth);\n }\n }\n }\n\n walk(root, 1);\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 LABEL_CHEVRON,\n LAYER_DROPDOWN_ATTR,\n} from \"../consts.js\";\nimport { getLayerDisplayName } from \"../utils.js\";\nimport type { LayerInfo } from \"../utils.js\";\n\nexport type OnLayerSelect = (layer: LayerInfo) => void;\nexport type OnLayerHover = (layer: LayerInfo) => void;\nexport type OnLayerHoverEnd = () => void;\n\nlet activeDropdown: HTMLDivElement | null = null;\nlet outsideMousedownHandler: ((e: MouseEvent) => void) | null = null;\nlet activeOnHoverEnd: OnLayerHoverEnd | null = null;\nlet activeKeydownHandler: ((e: KeyboardEvent) => void) | null = null;\n\n/** Create the dropdown DOM element with layer items */\nexport function createDropdownElement(\n layers: LayerInfo[],\n currentSelectorId: string | null,\n onSelect: OnLayerSelect,\n onHover?: OnLayerHover,\n onHoverEnd?: OnLayerHoverEnd\n): HTMLDivElement {\n const container = document.createElement(\"div\");\n container.setAttribute(LAYER_DROPDOWN_ATTR, \"true\");\n\n Object.keys(DROPDOWN_CONTAINER_STYLES).forEach((key) => {\n container.style[key as any] = DROPDOWN_CONTAINER_STYLES[key]!;\n });\n\n layers.forEach((layer) => {\n const item = document.createElement(\"div\");\n const isActive = layer.selectorId === currentSelectorId;\n\n item.textContent = getLayerDisplayName(layer);\n\n Object.keys(DROPDOWN_ITEM_BASE_STYLES).forEach((key) => {\n item.style[key as any] = DROPDOWN_ITEM_BASE_STYLES[key]!;\n });\n\n // Indent based on depth\n const depth = layer.depth ?? 0;\n if (depth > 0) {\n item.style.paddingLeft = `${12 + 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) {\n item.style.backgroundColor = DROPDOWN_ITEM_HOVER_BG;\n }\n if (onHover) onHover(layer);\n });\n\n item.addEventListener(\"mouseleave\", () => {\n if (!isActive) {\n item.style.backgroundColor = \"transparent\";\n }\n if (onHoverEnd) onHoverEnd();\n });\n\n item.addEventListener(\"click\", (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n onSelect(layer);\n });\n\n container.appendChild(item);\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.textContent?.includes(LABEL_CHEVRON)) return;\n\n label.textContent = label.textContent + LABEL_CHEVRON;\n label.style.cursor = \"pointer\";\n label.style.userSelect = \"none\";\n label.style.pointerEvents = \"auto\";\n label.setAttribute(LAYER_DROPDOWN_ATTR, \"true\");\n}\n\n/** Show the dropdown below the label element */\nexport function showDropdown(\n label: HTMLDivElement,\n layers: LayerInfo[],\n currentSelectorId: string | null,\n onSelect: OnLayerSelect,\n onHover?: OnLayerHover,\n onHoverEnd?: OnLayerHoverEnd\n): void {\n closeDropdown();\n\n const dropdown = createDropdownElement(\n layers,\n currentSelectorId,\n (layer) => {\n if (onHoverEnd) onHoverEnd();\n onSelect(layer);\n closeDropdown();\n },\n onHover,\n onHoverEnd\n );\n\n const overlay = label.parentElement;\n if (!overlay) return;\n\n // Position below the label\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 activeOnHoverEnd = onHoverEnd ?? null;\n\n // --- Arrow key navigation ---\n const items = Array.from(dropdown.children) as HTMLDivElement[];\n let focusedIndex = -1;\n\n const setFocusedItem = (index: number) => {\n // Clear previous focus styling\n if (focusedIndex >= 0 && focusedIndex < items.length) {\n const prev = items[focusedIndex]!;\n const prevIsActive = prev.style.color === DROPDOWN_ITEM_ACTIVE_COLOR;\n if (!prevIsActive) {\n prev.style.backgroundColor = \"transparent\";\n }\n }\n focusedIndex = index;\n // Apply hover styling to new focused item\n if (focusedIndex >= 0 && focusedIndex < items.length) {\n const cur = items[focusedIndex]!;\n const curIsActive = cur.style.color === DROPDOWN_ITEM_ACTIVE_COLOR;\n if (!curIsActive) {\n cur.style.backgroundColor = DROPDOWN_ITEM_HOVER_BG;\n }\n cur.scrollIntoView({ block: \"nearest\" });\n if (onHover) onHover(layers[focusedIndex]!);\n }\n };\n\n activeKeydownHandler = (e: KeyboardEvent) => {\n if (e.key === \"ArrowDown\") {\n e.preventDefault();\n e.stopPropagation();\n const next = focusedIndex < items.length - 1 ? focusedIndex + 1 : 0;\n setFocusedItem(next);\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault();\n e.stopPropagation();\n const prev = focusedIndex > 0 ? focusedIndex - 1 : items.length - 1;\n setFocusedItem(prev);\n } else if (e.key === \"Enter\" && focusedIndex >= 0) {\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 // Close on outside mousedown (mousedown fires before click, avoiding\n // conflict with handleElementClick's stopPropagation on click events)\n setTimeout(() => {\n outsideMousedownHandler = (e: MouseEvent) => {\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 }, 0);\n}\n\n/** Close the active dropdown and clean up listeners */\nexport function closeDropdown(): void {\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","import { findElementsById, updateElementClasses, getElementSelectorId } from \"./utils.js\";\nimport { buildLayerChain } from \"./layer-dropdown/utils.js\";\nimport type { LayerInfo } from \"./layer-dropdown/utils.js\";\nimport {\n enhanceLabelWithChevron,\n showDropdown,\n closeDropdown as closeLayerDropdown,\n isDropdownOpen as isLayerDropdownOpen,\n} from \"./layer-dropdown/component/dropdown-ui.js\";\nimport { LAYER_DROPDOWN_ATTR } from \"./layer-dropdown/consts.js\";\n\nexport function setupVisualEditAgent() {\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\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.top = \"-27px\";\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 ? \"#526cff\" : \"#DBEAFE\";\n label.style.borderRadius = \"3px\";\n label.style.minWidth = \"24px\";\n label.style.textAlign = \"center\";\n overlay.appendChild(label);\n }\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 // Handle mouse over event\n const handleMouseOver = (e: MouseEvent) => {\n if (!isVisualEditMode || isPopoverDragging) return;\n\n const target = e.target as Element;\n\n // Prevent hover effects when a dropdown is open\n if (isDropdownOpen) {\n clearHoverOverlays();\n return;\n }\n\n // Prevent hover effects on SVG path elements\n if (target.tagName.toLowerCase() === \"path\") {\n clearHoverOverlays();\n return;\n }\n\n // Support both data-source-location and data-visual-selector-id\n const element = target.closest(\n \"[data-source-location], [data-visual-selector-id]\"\n );\n if (!element) {\n clearHoverOverlays();\n return;\n }\n\n // Prefer data-source-location, fallback to data-visual-selector-id\n const htmlElement = element as HTMLElement;\n const selectorId =\n htmlElement.dataset.sourceLocation ||\n htmlElement.dataset.visualSelectorId;\n\n // Skip if this element is already selected\n if (selectedElementId === selectorId) {\n clearHoverOverlays();\n return;\n }\n\n // Find all elements with the same ID\n const elements = findElementsById(selectorId || null);\n\n // Clear previous hover overlays\n clearHoverOverlays();\n\n // Create overlays for all matching elements\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 };\n\n // Handle mouse out event\n const handleMouseOut = () => {\n if (isPopoverDragging) return;\n clearHoverOverlays();\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 // 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 clicking on SVG path elements\n if (target.tagName.toLowerCase() === \"path\") {\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 // Support both data-source-location and data-visual-selector-id\n const element = target.closest(\n \"[data-source-location], [data-visual-selector-id]\"\n );\n if (!element) {\n return;\n }\n\n const htmlElement = element as HTMLElement;\n const visualSelectorId =\n htmlElement.dataset.sourceLocation ||\n htmlElement.dataset.visualSelectorId;\n\n // Clear any existing selected overlays\n selectedOverlays.forEach((overlay) => {\n if (overlay && overlay.parentNode) {\n overlay.remove();\n }\n });\n selectedOverlays = [];\n\n // Find all elements with the same ID\n const elements = findElementsById(visualSelectorId || null);\n\n // Create selected overlays for all matching elements\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\n // Clear hover overlays\n clearHoverOverlays();\n\n // Attach layer dropdown to the selected overlay label\n attachLayerDropdownToOverlay(selectedOverlays[0], element);\n\n // Calculate element position for popover positioning\n const rect = element.getBoundingClientRect();\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 // Send message to parent window with element info including position\n const svgElement = element as SVGElement;\n const elementData = {\n type: \"element-selected\",\n tagName: element.tagName,\n classes:\n (svgElement.className as unknown as SVGAnimatedString)?.baseVal ||\n element.className ||\n \"\",\n visualSelectorId: visualSelectorId,\n content: (element as HTMLElement).innerText,\n dataSourceLocation: htmlElement.dataset.sourceLocation,\n isDynamicContent: htmlElement.dataset.dynamicContent === \"true\",\n linenumber: htmlElement.dataset.linenumber,\n filename: htmlElement.dataset.filename,\n position: elementPosition,\n };\n window.parent.postMessage(elementData, \"*\");\n };\n\n // Unselect the current element\n const unselectElement = () => {\n selectedOverlays.forEach((overlay) => {\n if (overlay && overlay.parentNode) {\n overlay.remove();\n }\n });\n selectedOverlays = [];\n selectedElementId = null;\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 }, 50);\n };\n\n // Update element content by visual selector ID\n const updateElementContent = (visualSelectorId: string, content: string) => {\n const elements = findElementsById(visualSelectorId);\n\n if (elements.length === 0) {\n return;\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 }, 50);\n };\n\n // --- Layer dropdown: hover preview overlay ---\n let layerPreviewOverlay: HTMLDivElement | 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 // Don't preview the currently selected element\n if (getElementSelectorId(layer.element) === selectedElementId) return;\n\n const overlay = createOverlay(false);\n overlay.style.zIndex = \"9998\";\n document.body.appendChild(overlay);\n positionOverlay(overlay, layer.element);\n layerPreviewOverlay = overlay;\n };\n\n // --- Layer dropdown: select a different element from the layer chain ---\n\n const selectElementFromLayer = (layer: LayerInfo) => {\n clearLayerPreview();\n closeLayerDropdown();\n if (escapeHandler) {\n document.removeEventListener(\"keydown\", escapeHandler, true);\n escapeHandler = null;\n }\n dropdownSourceElement = null;\n\n const element = layer.element;\n const htmlElement = element as HTMLElement;\n const visualSelectorId = getElementSelectorId(element);\n\n // Clear existing selected overlays\n selectedOverlays.forEach((overlay) => {\n if (overlay && overlay.parentNode) {\n overlay.remove();\n }\n });\n selectedOverlays = [];\n\n // Find all elements with the same ID\n const elements = findElementsById(visualSelectorId || null);\n\n // Create selected overlays for all matching elements\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 clearHoverOverlays();\n\n // Attach layer dropdown to the new overlay label\n attachLayerDropdownToOverlay(selectedOverlays[0], element);\n\n // Notify parent of the newly selected element\n const rect = element.getBoundingClientRect();\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 const svgElement = element as SVGElement;\n const elementData = {\n type: \"element-selected\",\n tagName: element.tagName,\n classes:\n (svgElement.className as unknown as SVGAnimatedString)?.baseVal ||\n element.className ||\n \"\",\n visualSelectorId: visualSelectorId,\n content: (element as HTMLElement).innerText,\n dataSourceLocation: htmlElement.dataset.sourceLocation,\n isDynamicContent: htmlElement.dataset.dynamicContent === \"true\",\n linenumber: htmlElement.dataset.linenumber,\n filename: htmlElement.dataset.filename,\n position: elementPosition,\n };\n window.parent.postMessage(elementData, \"*\");\n };\n\n let escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n let dropdownSourceElement: Element | null = null;\n\n const attachLayerDropdownToOverlay = (\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 // Only show dropdown when there are multiple layers to navigate\n if (layers.length <= 1) return;\n\n const currentId = getElementSelectorId(element);\n enhanceLabelWithChevron(label);\n\n label.addEventListener(\"click\", (e: MouseEvent) => {\n e.stopPropagation();\n e.preventDefault();\n if (isLayerDropdownOpen()) {\n closeLayerDropdown();\n reselectDropdownSource();\n } else {\n dropdownSourceElement = element;\n selectedElementId = null;\n window.parent.postMessage({ type: \"element-selected\", visualSelectorId: null }, \"*\");\n\n escapeHandler = (ev: KeyboardEvent) => {\n if (ev.key === \"Escape\") {\n ev.stopPropagation();\n closeLayerDropdown();\n reselectDropdownSource();\n }\n };\n document.addEventListener(\"keydown\", escapeHandler, true);\n\n showDropdown(label, layers, currentId, selectElementFromLayer, showLayerPreview, clearLayerPreview);\n }\n });\n };\n\n const reselectDropdownSource = () => {\n if (escapeHandler) {\n document.removeEventListener(\"keydown\", escapeHandler, true);\n escapeHandler = null;\n }\n if (dropdownSourceElement) {\n selectElementFromLayer({\n element: dropdownSourceElement,\n tagName: dropdownSourceElement.tagName.toLowerCase(),\n selectorId: getElementSelectorId(dropdownSourceElement),\n });\n dropdownSourceElement = null;\n }\n };\n\n // Toggle visual edit mode\n const toggleVisualEditMode = (isEnabled: boolean) => {\n isVisualEditMode = isEnabled;\n\n if (!isEnabled) {\n clearLayerPreview();\n closeLayerDropdown();\n clearHoverOverlays();\n\n selectedOverlays.forEach((overlay) => {\n if (overlay && overlay.parentNode) {\n overlay.remove();\n }\n });\n selectedOverlays = [];\n\n currentHighlightedElements = [];\n selectedElementId = null;\n document.body.style.cursor = \"default\";\n\n document.removeEventListener(\"mouseover\", handleMouseOver);\n document.removeEventListener(\"mouseout\", handleMouseOut);\n document.removeEventListener(\"click\", handleElementClick, true);\n } else {\n document.body.style.cursor = \"crosshair\";\n document.addEventListener(\"mouseover\", handleMouseOver);\n document.addEventListener(\"mouseout\", handleMouseOut);\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 elements = findElementsById(selectedElementId);\n if (elements.length > 0) {\n const element = elements[0];\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 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 \"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 );\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) {\n const elements = findElementsById(selectedElementId);\n if (elements.length > 0) {\n const element = elements[0];\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 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 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, 50);\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}"],"mappings":"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","names":["isInstrumentedElement","element","htmlEl","getElementSelectorId","findElementsById","id","sourceElements","updateElementClasses","elements","classes","element","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","LABEL_CHEVRON","LAYER_DROPDOWN_ATTR","MAX_PARENT_DEPTH","MAX_CHILD_DEPTH","getLayerDisplayName","layer","getInstrumentedDescendants","parent","maxDepth","result","walk","el","instrDepth","i","child","isInstrumentedElement","getElementSelectorId","buildLayerChain","selectedElement","parents","current","MAX_PARENT_DEPTH","chain","baseDepth","p","selfDepth","descendants","MAX_CHILD_DEPTH","assignDescendantDepths","root","startDepth","descSet","d","descMap","activeDropdown","outsideMousedownHandler","activeOnHoverEnd","activeKeydownHandler","createDropdownElement","layers","currentSelectorId","onSelect","onHover","onHoverEnd","container","LAYER_DROPDOWN_ATTR","DROPDOWN_CONTAINER_STYLES","key","layer","item","isActive","getLayerDisplayName","DROPDOWN_ITEM_BASE_STYLES","depth","DEPTH_INDENT_PX","DROPDOWN_ITEM_ACTIVE_COLOR","DROPDOWN_ITEM_ACTIVE_BG","DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT","DROPDOWN_ITEM_HOVER_BG","e","enhanceLabelWithChevron","label","LABEL_CHEVRON","showDropdown","closeDropdown","dropdown","overlay","items","focusedIndex","setFocusedItem","index","prev","cur","next","target","isDropdownOpen","setupVisualEditAgent","isVisualEditMode","isPopoverDragging","isDropdownOpen","hoverOverlays","selectedOverlays","currentHighlightedElements","selectedElementId","createOverlay","isSelected","overlay","positionOverlay","element","rect","label","clearHoverOverlays","handleMouseOver","e","target","htmlElement","selectorId","elements","findElementsById","el","handleMouseOut","handleElementClick","LAYER_DROPDOWN_ATTR","visualSelectorId","attachLayerDropdownToOverlay","elementPosition","svgElement","elementData","unselectElement","updateElementClassesAndReposition","classes","updateElementClasses","index","updateElementContent","content","layerPreviewOverlay","clearLayerPreview","showLayerPreview","layer","getElementSelectorId","selectElementFromLayer","closeDropdown","escapeHandler","dropdownSourceElement","layers","buildLayerChain","currentId","enhanceLabelWithChevron","reselectDropdownSource","ev","showDropdown","toggleVisualEditMode","isEnabled","handleScroll","viewportHeight","viewportWidth","isInViewport","handleMessage","event","message","handleResize","htmlEl","id","mutationObserver","mutations","mutation","hasVisualId","node","i"]}
1
+ {"version":3,"sources":["../../src/injections/utils.ts","../../src/injections/layer-dropdown/consts.ts","../../src/injections/layer-dropdown/utils.ts","../../src/injections/layer-dropdown/component/dropdown.ts","../../src/injections/layer-dropdown/controller.ts","../../src/injections/visual-edit-agent.ts"],"sourcesContent":["/** 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\n/** Find the nearest instrumented ancestor (not the element itself) */\nexport function getImmediateInstrumentedParent(element: Element): Element | null {\n let current = element.parentElement;\n while (\n current &&\n current !== document.documentElement &&\n current !== document.body\n ) {\n if (isInstrumentedElement(current)) {\n return current;\n }\n current = current.parentElement;\n }\n return null;\n}\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","/** 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\nexport const LABEL_CHEVRON = \" \\u25BE\";\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 Object.assign(element.style, styles);\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\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 */\nexport function getInstrumentedDescendants(\n parent: Element,\n maxDepth: 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 result.push({\n element: child,\n tagName: child.tagName.toLowerCase(),\n selectorId: getElementSelectorId(child),\n });\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/**\n * Build the layer chain for the dropdown:\n *\n * Parents – up to MAX_PARENT_DEPTH instrumented ancestors, outer → inner.\n * Current – the selected element.\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 // --- Parents (walk up, collect at most MAX_PARENT_DEPTH) ---\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({\n element: current,\n tagName: current.tagName.toLowerCase(),\n selectorId: getElementSelectorId(current),\n });\n }\n current = current.parentElement;\n }\n // Reverse so outermost parent comes first\n parents.reverse();\n\n // --- Build the chain with depth ---\n const chain: LayerInfo[] = [];\n const baseDepth = 0;\n\n // Parents: depth 0, 1, …\n parents.forEach((p, i) => {\n chain.push({ ...p, depth: baseDepth + i });\n });\n\n // Self\n const selfDepth = parents.length;\n chain.push({\n element: selectedElement,\n tagName: selectedElement.tagName.toLowerCase(),\n selectorId: getElementSelectorId(selectedElement),\n depth: selfDepth,\n });\n\n // Children: up to MAX_CHILD_DEPTH instrumented levels below selected\n const descendants = getInstrumentedDescendants(\n selectedElement,\n MAX_CHILD_DEPTH\n );\n // Assign visual depth: we need to track the instrumented nesting to set depth correctly\n assignDescendantDepths(selectedElement, descendants, selfDepth + 1);\n\n chain.push(...descendants);\n return chain;\n}\n\n/**\n * Walk the DOM tree again to assign correct visual depth to each descendant.\n * This avoids storing depth during collection and keeps the API simple.\n */\nfunction assignDescendantDepths(\n root: Element,\n descendants: LayerInfo[],\n startDepth: number\n): void {\n // Build a set for O(1) lookup\n const descSet = new Set(descendants.map((d) => d.element));\n // Map element → LayerInfo for mutation\n const descMap = new Map(descendants.map((d) => [d.element, d]));\n\n function walk(el: Element, instrDepth: number): void {\n for (let i = 0; i < el.children.length; i++) {\n const child = el.children[i]!;\n if (descSet.has(child)) {\n descMap.get(child)!.depth = startDepth + instrDepth - 1;\n walk(child, instrDepth + 1);\n } else {\n walk(child, instrDepth);\n }\n }\n }\n\n walk(root, 1);\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 LABEL_CHEVRON,\n LAYER_DROPDOWN_ATTR,\n} from \"../consts.js\";\nimport { applyStyles, getLayerDisplayName } from \"../utils.js\";\nimport type { LayerInfo, OnLayerSelect, OnLayerHover, OnLayerHoverEnd } from \"../types.js\";\n\nlet activeDropdown: HTMLDivElement | null = null;\nlet outsideMousedownHandler: ((e: MouseEvent) => void) | null = null;\nlet activeOnHoverEnd: OnLayerHoverEnd | null = null;\nlet activeKeydownHandler: ((e: KeyboardEvent) => void) | null = null;\n\nfunction createDropdownItem(\n layer: LayerInfo,\n isActive: boolean,\n onSelect: OnLayerSelect,\n onHover?: OnLayerHover,\n onHoverEnd?: OnLayerHoverEnd\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 = `${12 + 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 currentSelectorId: string | null,\n onSelect: OnLayerSelect,\n onHover?: OnLayerHover,\n onHoverEnd?: OnLayerHoverEnd\n): HTMLDivElement {\n const container = document.createElement(\"div\");\n container.setAttribute(LAYER_DROPDOWN_ATTR, \"true\");\n applyStyles(container, DROPDOWN_CONTAINER_STYLES);\n\n layers.forEach((layer) => {\n const isActive = layer.selectorId === currentSelectorId;\n container.appendChild(createDropdownItem(layer, isActive, onSelect, onHover, onHoverEnd));\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.textContent?.includes(LABEL_CHEVRON)) return;\n\n label.textContent = label.textContent + LABEL_CHEVRON;\n label.style.cursor = \"pointer\";\n label.style.userSelect = \"none\";\n label.style.pointerEvents = \"auto\";\n label.setAttribute(LAYER_DROPDOWN_ATTR, \"true\");\n}\n\nfunction setupKeyboardNavigation(\n dropdown: HTMLDivElement,\n layers: LayerInfo[],\n currentSelectorId: string | null,\n onSelect: OnLayerSelect,\n onHover?: OnLayerHover,\n onHoverEnd?: OnLayerHoverEnd\n): void {\n const items = Array.from(dropdown.children) as HTMLDivElement[];\n let focusedIndex = layers.findIndex((l) => l.selectorId === currentSelectorId);\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) onHover(layers[focusedIndex]!);\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) {\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 setTimeout(() => {\n outsideMousedownHandler = (e: MouseEvent) => {\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 }, 0);\n}\n\n/** Show the dropdown below the label element */\nexport function showDropdown(\n label: HTMLDivElement,\n layers: LayerInfo[],\n currentSelectorId: string | null,\n onSelect: OnLayerSelect,\n onHover?: OnLayerHover,\n onHoverEnd?: OnLayerHoverEnd\n): void {\n closeDropdown();\n\n const dropdown = createDropdownElement(\n layers,\n currentSelectorId,\n (layer) => {\n if (onHoverEnd) onHoverEnd();\n onSelect(layer);\n closeDropdown();\n },\n onHover,\n onHoverEnd\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 activeOnHoverEnd = onHoverEnd ?? null;\n\n setupKeyboardNavigation(dropdown, layers, currentSelectorId, onSelect, onHover, onHoverEnd);\n setupOutsideClickHandler(dropdown, label);\n}\n\n/** Close the active dropdown and clean up listeners */\nexport function closeDropdown(): void {\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 \"./component/dropdown.js\";\nimport type { LayerInfo, LayerControllerDeps, LayerController } from \"./types.js\";\n\nexport function createLayerController(deps: LayerControllerDeps): LayerController {\n let layerPreviewOverlay: HTMLDivElement | null = null;\n let escapeHandler: ((e: KeyboardEvent) => void) | null = null;\n let dropdownSourceElement: Element | 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) === deps.getSelectedElementId()) return;\n\n layerPreviewOverlay = deps.createPreviewOverlay(layer.element);\n };\n\n const selectElementFromLayer = (layer: LayerInfo) => {\n clearLayerPreview();\n closeDropdown();\n if (escapeHandler) {\n document.removeEventListener(\"keydown\", escapeHandler, true);\n escapeHandler = null;\n }\n dropdownSourceElement = null;\n\n const firstOverlay = deps.selectElement(layer.element);\n attachToOverlay(firstOverlay, layer.element);\n };\n\n const reselectDropdownSource = () => {\n if (escapeHandler) {\n document.removeEventListener(\"keydown\", escapeHandler, true);\n escapeHandler = null;\n }\n if (dropdownSourceElement) {\n selectElementFromLayer({\n element: dropdownSourceElement,\n tagName: dropdownSourceElement.tagName.toLowerCase(),\n selectorId: getElementSelectorId(dropdownSourceElement),\n });\n dropdownSourceElement = null;\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 e.stopPropagation();\n e.preventDefault();\n if (isDropdownOpen()) {\n closeDropdown();\n reselectDropdownSource();\n } else {\n dropdownSourceElement = element;\n deps.onDeselect();\n\n escapeHandler = (ev: KeyboardEvent) => {\n if (ev.key === \"Escape\") {\n ev.stopPropagation();\n closeDropdown();\n reselectDropdownSource();\n }\n };\n document.addEventListener(\"keydown\", escapeHandler, true);\n\n showDropdown(label, layers, currentId, selectElementFromLayer, showLayerPreview, clearLayerPreview);\n }\n });\n };\n\n const cleanup = () => {\n clearLayerPreview();\n closeDropdown();\n };\n\n return { attachToOverlay, cleanup };\n}\n","import { findElementsById, updateElementClasses, getElementSelectorId } from \"./utils.js\";\nimport { createLayerController } from \"./layer-dropdown/controller.js\";\nimport { LAYER_DROPDOWN_ATTR } from \"./layer-dropdown/consts.js\";\n\nexport function setupVisualEditAgent() {\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\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.top = \"-27px\";\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 ? \"#526cff\" : \"#DBEAFE\";\n label.style.borderRadius = \"3px\";\n label.style.minWidth = \"24px\";\n label.style.textAlign = \"center\";\n overlay.appendChild(label);\n }\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 notifyElementSelected = (element: Element) => {\n const htmlElement = element as HTMLElement;\n const rect = element.getBoundingClientRect();\n const svgElement = element as SVGElement;\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: htmlElement.innerText,\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 }, \"*\");\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 clearHoverOverlays();\n notifyElementSelected(element);\n\n return selectedOverlays[0];\n };\n\n // Handle mouse over event\n const handleMouseOver = (e: MouseEvent) => {\n if (!isVisualEditMode || isPopoverDragging) return;\n\n const target = e.target as Element;\n\n // Prevent hover effects when a dropdown is open\n if (isDropdownOpen) {\n clearHoverOverlays();\n return;\n }\n\n // Prevent hover effects on SVG path elements\n if (target.tagName.toLowerCase() === \"path\") {\n clearHoverOverlays();\n return;\n }\n\n // Support both data-source-location and data-visual-selector-id\n const element = target.closest(\n \"[data-source-location], [data-visual-selector-id]\"\n );\n if (!element) {\n clearHoverOverlays();\n return;\n }\n\n // Prefer data-source-location, fallback to data-visual-selector-id\n const htmlElement = element as HTMLElement;\n const selectorId =\n htmlElement.dataset.sourceLocation ||\n htmlElement.dataset.visualSelectorId;\n\n // Skip if this element is already selected\n if (selectedElementId === selectorId) {\n clearHoverOverlays();\n return;\n }\n\n // Find all elements with the same ID\n const elements = findElementsById(selectorId || null);\n\n // Clear previous hover overlays\n clearHoverOverlays();\n\n // Create overlays for all matching elements\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 };\n\n // Handle mouse out event\n const handleMouseOut = () => {\n if (isPopoverDragging) return;\n clearHoverOverlays();\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 // 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 clicking on SVG path elements\n if (target.tagName.toLowerCase() === \"path\") {\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 // Support both data-source-location and data-visual-selector-id\n const element = target.closest(\n \"[data-source-location], [data-visual-selector-id]\"\n );\n if (!element) {\n return;\n }\n\n const selectedOverlay = selectElement(element);\n layerController.attachToOverlay(selectedOverlay, element);\n };\n\n // Unselect the current element\n const unselectElement = () => {\n clearSelectedOverlays();\n selectedElementId = null;\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 }, 50);\n };\n\n // Update element content by visual selector ID\n const updateElementContent = (visualSelectorId: string, content: string) => {\n const elements = findElementsById(visualSelectorId);\n\n if (elements.length === 0) {\n return;\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 }, 50);\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: () => {\n selectedElementId = null;\n window.parent.postMessage({ type: \"element-selected\", visualSelectorId: null }, \"*\");\n },\n });\n\n // Toggle visual edit mode\n const toggleVisualEditMode = (isEnabled: boolean) => {\n isVisualEditMode = isEnabled;\n\n if (!isEnabled) {\n layerController.cleanup();\n clearHoverOverlays();\n clearSelectedOverlays();\n\n currentHighlightedElements = [];\n selectedElementId = null;\n document.body.style.cursor = \"default\";\n\n document.removeEventListener(\"mouseover\", handleMouseOver);\n document.removeEventListener(\"mouseout\", handleMouseOut);\n document.removeEventListener(\"click\", handleElementClick, true);\n } else {\n document.body.style.cursor = \"crosshair\";\n document.addEventListener(\"mouseover\", handleMouseOver);\n document.addEventListener(\"mouseout\", handleMouseOut);\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 elements = findElementsById(selectedElementId);\n if (elements.length > 0) {\n const element = elements[0];\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 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 \"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 );\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) {\n const elements = findElementsById(selectedElementId);\n if (elements.length > 0) {\n const element = elements[0];\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 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 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, 50);\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}"],"mappings":"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","names":["isInstrumentedElement","element","htmlEl","getElementSelectorId","findElementsById","id","sourceElements","updateElementClasses","elements","classes","element","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","LABEL_CHEVRON","LAYER_DROPDOWN_ATTR","MAX_PARENT_DEPTH","MAX_CHILD_DEPTH","applyStyles","element","styles","getLayerDisplayName","layer","getInstrumentedDescendants","parent","maxDepth","result","walk","el","instrDepth","i","child","isInstrumentedElement","getElementSelectorId","buildLayerChain","selectedElement","parents","current","MAX_PARENT_DEPTH","chain","baseDepth","p","selfDepth","descendants","MAX_CHILD_DEPTH","assignDescendantDepths","root","startDepth","descSet","d","descMap","activeDropdown","outsideMousedownHandler","activeOnHoverEnd","activeKeydownHandler","createDropdownItem","layer","isActive","onSelect","onHover","onHoverEnd","item","getLayerDisplayName","applyStyles","DROPDOWN_ITEM_BASE_STYLES","depth","DEPTH_INDENT_PX","DROPDOWN_ITEM_ACTIVE_COLOR","DROPDOWN_ITEM_ACTIVE_BG","DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT","DROPDOWN_ITEM_HOVER_BG","e","createDropdownElement","layers","currentSelectorId","container","LAYER_DROPDOWN_ATTR","DROPDOWN_CONTAINER_STYLES","enhanceLabelWithChevron","label","LABEL_CHEVRON","setupKeyboardNavigation","dropdown","items","focusedIndex","l","setFocusedItem","index","prev","cur","closeDropdown","setupOutsideClickHandler","target","showDropdown","overlay","isDropdownOpen","createLayerController","deps","layerPreviewOverlay","escapeHandler","dropdownSourceElement","clearLayerPreview","showLayerPreview","layer","getElementSelectorId","selectElementFromLayer","closeDropdown","firstOverlay","attachToOverlay","reselectDropdownSource","overlay","element","label","layers","buildLayerChain","currentId","enhanceLabelWithChevron","e","isDropdownOpen","ev","showDropdown","setupVisualEditAgent","isVisualEditMode","isPopoverDragging","isDropdownOpen","hoverOverlays","selectedOverlays","currentHighlightedElements","selectedElementId","createOverlay","isSelected","overlay","positionOverlay","element","rect","label","clearHoverOverlays","clearSelectedOverlays","notifyElementSelected","htmlElement","svgElement","getElementSelectorId","selectElement","visualSelectorId","findElementsById","el","handleMouseOver","e","target","selectorId","elements","handleMouseOut","handleElementClick","LAYER_DROPDOWN_ATTR","selectedOverlay","layerController","unselectElement","updateElementClassesAndReposition","classes","updateElementClasses","index","updateElementContent","content","createLayerController","toggleVisualEditMode","isEnabled","handleScroll","viewportHeight","viewportWidth","isInViewport","elementPosition","handleMessage","event","message","handleResize","htmlEl","id","mutationObserver","mutations","mutation","hasVisualId","node","i"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/vite-plugin",
3
- "version": "0.2.22-pr.36.019589c",
3
+ "version": "0.2.22-pr.36.9cc89ea",
4
4
  "description": "The Vite plugin for base44 based applications",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,18 +11,55 @@ import {
11
11
  LABEL_CHEVRON,
12
12
  LAYER_DROPDOWN_ATTR,
13
13
  } from "../consts.js";
14
- import { getLayerDisplayName } from "../utils.js";
15
- import type { LayerInfo } from "../utils.js";
16
-
17
- export type OnLayerSelect = (layer: LayerInfo) => void;
18
- export type OnLayerHover = (layer: LayerInfo) => void;
19
- export type OnLayerHoverEnd = () => void;
14
+ import { applyStyles, getLayerDisplayName } from "../utils.js";
15
+ import type { LayerInfo, OnLayerSelect, OnLayerHover, OnLayerHoverEnd } from "../types.js";
20
16
 
21
17
  let activeDropdown: HTMLDivElement | null = null;
22
18
  let outsideMousedownHandler: ((e: MouseEvent) => void) | null = null;
23
19
  let activeOnHoverEnd: OnLayerHoverEnd | null = null;
24
20
  let activeKeydownHandler: ((e: KeyboardEvent) => void) | null = null;
25
21
 
22
+ function createDropdownItem(
23
+ layer: LayerInfo,
24
+ isActive: boolean,
25
+ onSelect: OnLayerSelect,
26
+ onHover?: OnLayerHover,
27
+ onHoverEnd?: OnLayerHoverEnd
28
+ ): HTMLDivElement {
29
+ const item = document.createElement("div");
30
+ item.textContent = getLayerDisplayName(layer);
31
+ applyStyles(item, DROPDOWN_ITEM_BASE_STYLES);
32
+
33
+ const depth = layer.depth ?? 0;
34
+ if (depth > 0) {
35
+ item.style.paddingLeft = `${12 + depth * DEPTH_INDENT_PX}px`;
36
+ }
37
+
38
+ if (isActive) {
39
+ item.style.color = DROPDOWN_ITEM_ACTIVE_COLOR;
40
+ item.style.backgroundColor = DROPDOWN_ITEM_ACTIVE_BG;
41
+ item.style.fontWeight = DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT;
42
+ }
43
+
44
+ item.addEventListener("mouseenter", () => {
45
+ if (!isActive) item.style.backgroundColor = DROPDOWN_ITEM_HOVER_BG;
46
+ if (onHover) onHover(layer);
47
+ });
48
+
49
+ item.addEventListener("mouseleave", () => {
50
+ if (!isActive) item.style.backgroundColor = "transparent";
51
+ if (onHoverEnd) onHoverEnd();
52
+ });
53
+
54
+ item.addEventListener("click", (e: MouseEvent) => {
55
+ e.stopPropagation();
56
+ e.preventDefault();
57
+ onSelect(layer);
58
+ });
59
+
60
+ return item;
61
+ }
62
+
26
63
  /** Create the dropdown DOM element with layer items */
27
64
  export function createDropdownElement(
28
65
  layers: LayerInfo[],
@@ -33,54 +70,11 @@ export function createDropdownElement(
33
70
  ): HTMLDivElement {
34
71
  const container = document.createElement("div");
35
72
  container.setAttribute(LAYER_DROPDOWN_ATTR, "true");
36
-
37
- Object.keys(DROPDOWN_CONTAINER_STYLES).forEach((key) => {
38
- container.style[key as any] = DROPDOWN_CONTAINER_STYLES[key]!;
39
- });
73
+ applyStyles(container, DROPDOWN_CONTAINER_STYLES);
40
74
 
41
75
  layers.forEach((layer) => {
42
- const item = document.createElement("div");
43
76
  const isActive = layer.selectorId === currentSelectorId;
44
-
45
- item.textContent = getLayerDisplayName(layer);
46
-
47
- Object.keys(DROPDOWN_ITEM_BASE_STYLES).forEach((key) => {
48
- item.style[key as any] = DROPDOWN_ITEM_BASE_STYLES[key]!;
49
- });
50
-
51
- // Indent based on depth
52
- const depth = layer.depth ?? 0;
53
- if (depth > 0) {
54
- item.style.paddingLeft = `${12 + depth * DEPTH_INDENT_PX}px`;
55
- }
56
-
57
- if (isActive) {
58
- item.style.color = DROPDOWN_ITEM_ACTIVE_COLOR;
59
- item.style.backgroundColor = DROPDOWN_ITEM_ACTIVE_BG;
60
- item.style.fontWeight = DROPDOWN_ITEM_ACTIVE_FONT_WEIGHT;
61
- }
62
-
63
- item.addEventListener("mouseenter", () => {
64
- if (!isActive) {
65
- item.style.backgroundColor = DROPDOWN_ITEM_HOVER_BG;
66
- }
67
- if (onHover) onHover(layer);
68
- });
69
-
70
- item.addEventListener("mouseleave", () => {
71
- if (!isActive) {
72
- item.style.backgroundColor = "transparent";
73
- }
74
- if (onHoverEnd) onHoverEnd();
75
- });
76
-
77
- item.addEventListener("click", (e: MouseEvent) => {
78
- e.stopPropagation();
79
- e.preventDefault();
80
- onSelect(layer);
81
- });
82
-
83
- container.appendChild(item);
77
+ container.appendChild(createDropdownItem(layer, isActive, onSelect, onHover, onHoverEnd));
84
78
  });
85
79
 
86
80
  return container;
@@ -97,59 +91,28 @@ export function enhanceLabelWithChevron(label: HTMLDivElement): void {
97
91
  label.setAttribute(LAYER_DROPDOWN_ATTR, "true");
98
92
  }
99
93
 
100
- /** Show the dropdown below the label element */
101
- export function showDropdown(
102
- label: HTMLDivElement,
94
+ function setupKeyboardNavigation(
95
+ dropdown: HTMLDivElement,
103
96
  layers: LayerInfo[],
104
97
  currentSelectorId: string | null,
105
98
  onSelect: OnLayerSelect,
106
99
  onHover?: OnLayerHover,
107
100
  onHoverEnd?: OnLayerHoverEnd
108
101
  ): void {
109
- closeDropdown();
110
-
111
- const dropdown = createDropdownElement(
112
- layers,
113
- currentSelectorId,
114
- (layer) => {
115
- if (onHoverEnd) onHoverEnd();
116
- onSelect(layer);
117
- closeDropdown();
118
- },
119
- onHover,
120
- onHoverEnd
121
- );
122
-
123
- const overlay = label.parentElement;
124
- if (!overlay) return;
125
-
126
- // Position below the label
127
- dropdown.style.top = `${label.offsetTop + label.offsetHeight + 2}px`;
128
- dropdown.style.left = `${label.offsetLeft}px`;
129
-
130
- overlay.appendChild(dropdown);
131
- activeDropdown = dropdown;
132
- activeOnHoverEnd = onHoverEnd ?? null;
133
-
134
- // --- Arrow key navigation ---
135
102
  const items = Array.from(dropdown.children) as HTMLDivElement[];
136
- let focusedIndex = -1;
103
+ let focusedIndex = layers.findIndex((l) => l.selectorId === currentSelectorId);
137
104
 
138
105
  const setFocusedItem = (index: number) => {
139
- // Clear previous focus styling
140
106
  if (focusedIndex >= 0 && focusedIndex < items.length) {
141
107
  const prev = items[focusedIndex]!;
142
- const prevIsActive = prev.style.color === DROPDOWN_ITEM_ACTIVE_COLOR;
143
- if (!prevIsActive) {
108
+ if (prev.style.color !== DROPDOWN_ITEM_ACTIVE_COLOR) {
144
109
  prev.style.backgroundColor = "transparent";
145
110
  }
146
111
  }
147
112
  focusedIndex = index;
148
- // Apply hover styling to new focused item
149
113
  if (focusedIndex >= 0 && focusedIndex < items.length) {
150
114
  const cur = items[focusedIndex]!;
151
- const curIsActive = cur.style.color === DROPDOWN_ITEM_ACTIVE_COLOR;
152
- if (!curIsActive) {
115
+ if (cur.style.color !== DROPDOWN_ITEM_ACTIVE_COLOR) {
153
116
  cur.style.backgroundColor = DROPDOWN_ITEM_HOVER_BG;
154
117
  }
155
118
  cur.scrollIntoView({ block: "nearest" });
@@ -161,13 +124,11 @@ export function showDropdown(
161
124
  if (e.key === "ArrowDown") {
162
125
  e.preventDefault();
163
126
  e.stopPropagation();
164
- const next = focusedIndex < items.length - 1 ? focusedIndex + 1 : 0;
165
- setFocusedItem(next);
127
+ setFocusedItem(focusedIndex < items.length - 1 ? focusedIndex + 1 : 0);
166
128
  } else if (e.key === "ArrowUp") {
167
129
  e.preventDefault();
168
130
  e.stopPropagation();
169
- const prev = focusedIndex > 0 ? focusedIndex - 1 : items.length - 1;
170
- setFocusedItem(prev);
131
+ setFocusedItem(focusedIndex > 0 ? focusedIndex - 1 : items.length - 1);
171
132
  } else if (e.key === "Enter" && focusedIndex >= 0) {
172
133
  e.preventDefault();
173
134
  e.stopPropagation();
@@ -177,9 +138,12 @@ export function showDropdown(
177
138
  }
178
139
  };
179
140
  document.addEventListener("keydown", activeKeydownHandler, true);
141
+ }
180
142
 
181
- // Close on outside mousedown (mousedown fires before click, avoiding
182
- // conflict with handleElementClick's stopPropagation on click events)
143
+ function setupOutsideClickHandler(
144
+ dropdown: HTMLDivElement,
145
+ label: HTMLDivElement
146
+ ): void {
183
147
  setTimeout(() => {
184
148
  outsideMousedownHandler = (e: MouseEvent) => {
185
149
  const target = e.target as Node;
@@ -191,6 +155,43 @@ export function showDropdown(
191
155
  }, 0);
192
156
  }
193
157
 
158
+ /** Show the dropdown below the label element */
159
+ export function showDropdown(
160
+ label: HTMLDivElement,
161
+ layers: LayerInfo[],
162
+ currentSelectorId: string | null,
163
+ onSelect: OnLayerSelect,
164
+ onHover?: OnLayerHover,
165
+ onHoverEnd?: OnLayerHoverEnd
166
+ ): void {
167
+ closeDropdown();
168
+
169
+ const dropdown = createDropdownElement(
170
+ layers,
171
+ currentSelectorId,
172
+ (layer) => {
173
+ if (onHoverEnd) onHoverEnd();
174
+ onSelect(layer);
175
+ closeDropdown();
176
+ },
177
+ onHover,
178
+ onHoverEnd
179
+ );
180
+
181
+ const overlay = label.parentElement;
182
+ if (!overlay) return;
183
+
184
+ dropdown.style.top = `${label.offsetTop + label.offsetHeight + 2}px`;
185
+ dropdown.style.left = `${label.offsetLeft}px`;
186
+
187
+ overlay.appendChild(dropdown);
188
+ activeDropdown = dropdown;
189
+ activeOnHoverEnd = onHoverEnd ?? null;
190
+
191
+ setupKeyboardNavigation(dropdown, layers, currentSelectorId, onSelect, onHover, onHoverEnd);
192
+ setupOutsideClickHandler(dropdown, label);
193
+ }
194
+
194
195
  /** Close the active dropdown and clean up listeners */
195
196
  export function closeDropdown(): void {
196
197
  if (activeOnHoverEnd) {
@@ -0,0 +1,105 @@
1
+ /** Controller that encapsulates layer-dropdown integration logic */
2
+
3
+ import { getElementSelectorId } from "../utils.js";
4
+ import { buildLayerChain } from "./utils.js";
5
+ import {
6
+ enhanceLabelWithChevron,
7
+ showDropdown,
8
+ closeDropdown,
9
+ isDropdownOpen,
10
+ } from "./component/dropdown.js";
11
+ import type { LayerInfo, LayerControllerDeps, LayerController } from "./types.js";
12
+
13
+ export function createLayerController(deps: LayerControllerDeps): LayerController {
14
+ let layerPreviewOverlay: HTMLDivElement | null = null;
15
+ let escapeHandler: ((e: KeyboardEvent) => void) | null = null;
16
+ let dropdownSourceElement: Element | null = null;
17
+
18
+ const clearLayerPreview = () => {
19
+ if (layerPreviewOverlay && layerPreviewOverlay.parentNode) {
20
+ layerPreviewOverlay.remove();
21
+ }
22
+ layerPreviewOverlay = null;
23
+ };
24
+
25
+ const showLayerPreview = (layer: LayerInfo) => {
26
+ clearLayerPreview();
27
+ if (getElementSelectorId(layer.element) === deps.getSelectedElementId()) return;
28
+
29
+ layerPreviewOverlay = deps.createPreviewOverlay(layer.element);
30
+ };
31
+
32
+ const selectElementFromLayer = (layer: LayerInfo) => {
33
+ clearLayerPreview();
34
+ closeDropdown();
35
+ if (escapeHandler) {
36
+ document.removeEventListener("keydown", escapeHandler, true);
37
+ escapeHandler = null;
38
+ }
39
+ dropdownSourceElement = null;
40
+
41
+ const firstOverlay = deps.selectElement(layer.element);
42
+ attachToOverlay(firstOverlay, layer.element);
43
+ };
44
+
45
+ const reselectDropdownSource = () => {
46
+ if (escapeHandler) {
47
+ document.removeEventListener("keydown", escapeHandler, true);
48
+ escapeHandler = null;
49
+ }
50
+ if (dropdownSourceElement) {
51
+ selectElementFromLayer({
52
+ element: dropdownSourceElement,
53
+ tagName: dropdownSourceElement.tagName.toLowerCase(),
54
+ selectorId: getElementSelectorId(dropdownSourceElement),
55
+ });
56
+ dropdownSourceElement = null;
57
+ }
58
+ };
59
+
60
+ const attachToOverlay = (
61
+ overlay: HTMLDivElement | undefined,
62
+ element: Element
63
+ ) => {
64
+ if (!overlay) return;
65
+
66
+ const label = overlay.querySelector("div") as HTMLDivElement | null;
67
+ if (!label) return;
68
+
69
+ const layers = buildLayerChain(element);
70
+ if (layers.length <= 1) return;
71
+
72
+ const currentId = getElementSelectorId(element);
73
+ enhanceLabelWithChevron(label);
74
+
75
+ label.addEventListener("click", (e: MouseEvent) => {
76
+ e.stopPropagation();
77
+ e.preventDefault();
78
+ if (isDropdownOpen()) {
79
+ closeDropdown();
80
+ reselectDropdownSource();
81
+ } else {
82
+ dropdownSourceElement = element;
83
+ deps.onDeselect();
84
+
85
+ escapeHandler = (ev: KeyboardEvent) => {
86
+ if (ev.key === "Escape") {
87
+ ev.stopPropagation();
88
+ closeDropdown();
89
+ reselectDropdownSource();
90
+ }
91
+ };
92
+ document.addEventListener("keydown", escapeHandler, true);
93
+
94
+ showDropdown(label, layers, currentId, selectElementFromLayer, showLayerPreview, clearLayerPreview);
95
+ }
96
+ });
97
+ };
98
+
99
+ const cleanup = () => {
100
+ clearLayerPreview();
101
+ closeDropdown();
102
+ };
103
+
104
+ return { attachToOverlay, cleanup };
105
+ }