vite-plugin-visual-selector 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
- import { V as VisualSelectorPluginOptions } from './runtime-DpE5pSIp.js';
3
- export { A as AgentReadyMessage, C as ContentEditingMessage, D as DropdownStateMessage, E as ElementPosition, a as ElementPositionUpdateMessage, b as ElementSelectedMessage, c as ElementUpdateMessage, I as InjectFontImportMessage, d as InlineEditMessage, L as LayerItem, P as PopoverDragStateMessage, R as RefreshPageMessage, e as RequestElementPositionMessage, S as SandboxMountMessage, f as SelectElementByIdMessage, T as ToggleInlineEditModeMessage, g as ToggleVisualEditModeMessage, U as UnselectElementMessage, h as UpdateAttributeMessage, i as UpdateClassesMessage, j as UpdateContentMessage, k as UpdateThemeVariablesMessage, l as VisualEditAgentInstance, m as VisualEditAgentOptions, n as VisualSelectorControlMessage, s as setupVisualEditAgent } from './runtime-DpE5pSIp.js';
2
+ import { V as VisualSelectorPluginOptions } from './runtime-D695qvel.js';
3
+ export { A as AgentReadyMessage, C as ContentEditingMessage, D as DropdownStateMessage, E as ElementPosition, a as ElementPositionUpdateMessage, b as ElementSelectedMessage, c as ElementUpdateMessage, I as InjectFontImportMessage, d as InlineEditMessage, L as LayerItem, P as PopoverDragStateMessage, R as RefreshPageMessage, e as RequestElementPositionMessage, S as SandboxMountMessage, f as SelectElementByIdMessage, T as ToggleInlineEditModeMessage, g as ToggleVisualEditModeMessage, U as UnselectElementMessage, h as UpdateAttributeMessage, i as UpdateClassesMessage, j as UpdateContentMessage, k as UpdateThemeVariablesMessage, l as VisualEditAgentInstance, m as VisualEditAgentOptions, n as VisualSelectorControlMessage, s as setupVisualEditAgent } from './runtime-D695qvel.js';
4
4
 
5
5
  /**
6
6
  * 创建 Vite 插件:在编译阶段(transform hook)向每个原生 JSX 元素注入
package/dist/index.js CHANGED
@@ -218,169 +218,6 @@ function handleInlineEdit(state, data, updatePositions) {
218
218
  }
219
219
  }
220
220
 
221
- // src/runtime/layer-navigation.ts
222
- function buildLayerTree(element) {
223
- const tree = [];
224
- const ancestors = [];
225
- let parent = element.parentElement;
226
- while (parent && parent !== document.body) {
227
- if (hasSourceLocation(parent)) {
228
- ancestors.push(parent);
229
- }
230
- parent = parent.parentElement;
231
- }
232
- ancestors.reverse();
233
- ancestors.forEach((el) => {
234
- tree.push({ element: el, tagName: el.tagName.toLowerCase(), depth: 0 });
235
- });
236
- tree.push({ element, tagName: element.tagName.toLowerCase(), depth: 0 });
237
- for (let i = 0; i < element.children.length; i++) {
238
- const child = element.children[i];
239
- if (hasSourceLocation(child)) {
240
- tree.push({ element: child, tagName: child.tagName.toLowerCase(), depth: 0 });
241
- }
242
- }
243
- return tree;
244
- }
245
- function removeLayerDropdown(state) {
246
- if (state.layerDropdown) {
247
- const parentOverlay = state.layerDropdown.parentElement;
248
- if (parentOverlay) {
249
- const arrowEl = parentOverlay.querySelector("[data-tag-arrow]");
250
- if (arrowEl) arrowEl.textContent = "\u2304";
251
- }
252
- state.layerDropdown.remove();
253
- state.layerDropdown = null;
254
- document.removeEventListener("keydown", handleLayerKeyboard);
255
- }
256
- }
257
- function toggleLayerDropdown(state, element, anchor, onSelectElement) {
258
- if (state.layerDropdown) {
259
- removeLayerDropdown(state);
260
- return;
261
- }
262
- const layers = buildLayerTree(element);
263
- renderLayerDropdown(state, anchor, layers, element, onSelectElement);
264
- }
265
- function renderLayerDropdown(state, anchor, layers, currentElement, onSelectElement) {
266
- const dropdown = document.createElement("div");
267
- dropdown.setAttribute("data-layer-dropdown", "true");
268
- dropdown.setAttribute(AGENT_ATTR, "");
269
- Object.assign(dropdown.style, {
270
- position: "absolute",
271
- backgroundColor: "#ffffff",
272
- border: "1px solid #e2e8f0",
273
- borderRadius: "6px",
274
- boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
275
- fontSize: "12px",
276
- zIndex: "99999",
277
- pointerEvents: "auto",
278
- padding: "4px 0",
279
- minWidth: "120px",
280
- maxHeight: "320px",
281
- overflowY: "auto"
282
- });
283
- let focusedIndex = -1;
284
- const items = [];
285
- layers.forEach((layer, idx) => {
286
- const item = document.createElement("div");
287
- item.setAttribute(AGENT_ATTR, "");
288
- item.textContent = layer.tagName;
289
- item.style.padding = "6px 16px";
290
- item.style.cursor = "pointer";
291
- item.style.whiteSpace = "nowrap";
292
- if (layer.element === currentElement) {
293
- item.style.color = "#000000";
294
- item.style.backgroundColor = "rgba(255, 204, 0, 0.2)";
295
- item.style.fontWeight = "600";
296
- focusedIndex = idx;
297
- } else {
298
- item.style.color = "#64748b";
299
- }
300
- item.addEventListener("click", (e) => {
301
- e.stopPropagation();
302
- removeLayerDropdown(state);
303
- onSelectElement(layer.element);
304
- });
305
- item.addEventListener("mouseenter", () => {
306
- if (layer.element !== currentElement) {
307
- item.style.backgroundColor = "#f1f5f9";
308
- item.style.color = "#334155";
309
- }
310
- });
311
- item.addEventListener("mouseleave", () => {
312
- if (layer.element !== currentElement) {
313
- item.style.backgroundColor = "transparent";
314
- item.style.color = "#64748b";
315
- }
316
- });
317
- items.push(item);
318
- dropdown.appendChild(item);
319
- });
320
- document.body.appendChild(dropdown);
321
- const anchorRect = anchor.getBoundingClientRect();
322
- dropdown.style.top = `${anchorRect.bottom + window.scrollY + 2}px`;
323
- dropdown.style.left = `${anchorRect.left + window.scrollX}px`;
324
- requestAnimationFrame(() => {
325
- const ddRect = dropdown.getBoundingClientRect();
326
- if (ddRect.right > window.innerWidth - 4) {
327
- dropdown.style.left = `${window.innerWidth - ddRect.width - 4 + window.scrollX}px`;
328
- }
329
- if (ddRect.left < 4) {
330
- dropdown.style.left = `${4 + window.scrollX}px`;
331
- }
332
- if (ddRect.bottom > window.innerHeight) {
333
- dropdown.style.top = `${anchorRect.top + window.scrollY - ddRect.height - 2}px`;
334
- }
335
- });
336
- state.layerDropdown = dropdown;
337
- const handleKeydown = (e) => {
338
- if (!state.layerDropdown) return;
339
- switch (e.key) {
340
- case "ArrowDown":
341
- e.preventDefault();
342
- focusedIndex = Math.min(focusedIndex + 1, items.length - 1);
343
- highlightItem(items, focusedIndex, layers, currentElement);
344
- break;
345
- case "ArrowUp":
346
- e.preventDefault();
347
- focusedIndex = Math.max(focusedIndex - 1, 0);
348
- highlightItem(items, focusedIndex, layers, currentElement);
349
- break;
350
- case "Enter":
351
- e.preventDefault();
352
- if (focusedIndex >= 0 && focusedIndex < layers.length) {
353
- removeLayerDropdown(state);
354
- onSelectElement(layers[focusedIndex].element);
355
- }
356
- break;
357
- case "Escape":
358
- e.preventDefault();
359
- removeLayerDropdown(state);
360
- break;
361
- }
362
- };
363
- handleLayerKeyboard.current = handleKeydown;
364
- document.addEventListener("keydown", handleLayerKeyboard);
365
- }
366
- function handleLayerKeyboard(e) {
367
- const current = handleLayerKeyboard.current;
368
- if (current) current(e);
369
- }
370
- function highlightItem(items, index, layers, currentElement) {
371
- items.forEach((item, i) => {
372
- if (layers[i].element === currentElement) {
373
- item.style.color = "#000000";
374
- item.style.backgroundColor = i === index ? "rgba(255, 204, 0, 0.35)" : "rgba(255, 204, 0, 0.2)";
375
- item.style.fontWeight = "600";
376
- } else {
377
- item.style.backgroundColor = i === index ? "#f1f5f9" : "transparent";
378
- item.style.color = i === index ? "#334155" : "#64748b";
379
- item.style.fontWeight = "normal";
380
- }
381
- });
382
- }
383
-
384
221
  // src/runtime/messages.ts
385
222
  function reportElementSelected(state, element) {
386
223
  const el = element;
@@ -439,6 +276,18 @@ function reportPositionUpdate(state) {
439
276
  } catch {
440
277
  }
441
278
  }
279
+ function reportDropdownState(state, isOpen) {
280
+ try {
281
+ window.parent.postMessage(
282
+ {
283
+ type: "dropdown-state",
284
+ data: { isOpen }
285
+ },
286
+ state.targetOrigin
287
+ );
288
+ } catch {
289
+ }
290
+ }
442
291
  function handleMessage(state, e, callbacks) {
443
292
  if (state.targetOrigin !== "*" && e.origin !== state.targetOrigin) return;
444
293
  const msg = e.data;
@@ -472,10 +321,7 @@ function handleMessage(state, e, callbacks) {
472
321
  break;
473
322
  case "unselect-element":
474
323
  if (state.editingElement) callbacks.stopInlineEditing();
475
- state.selectionOverlays.forEach((o) => o.remove());
476
- state.selectionOverlays = [];
477
- state.selectedId = null;
478
- state.selectedElement = null;
324
+ callbacks.clearSelectionState();
479
325
  break;
480
326
  case "update-theme-variables":
481
327
  if (msg.data?.variables) {
@@ -565,6 +411,27 @@ function createOverlay(opts) {
565
411
  }
566
412
  return overlay;
567
413
  }
414
+ function setTagArrowExpanded(arrow, expanded) {
415
+ arrow.style.transform = expanded ? "rotate(0deg)" : "rotate(180deg)";
416
+ }
417
+ function createTagArrowSvg() {
418
+ const svgNs = "http://www.w3.org/2000/svg";
419
+ const svg = document.createElementNS(svgNs, "svg");
420
+ svg.setAttribute("xmlns", svgNs);
421
+ svg.setAttribute("width", "12");
422
+ svg.setAttribute("height", "12");
423
+ svg.setAttribute("viewBox", "0 0 12 12");
424
+ svg.setAttribute("fill", "none");
425
+ svg.style.display = "block";
426
+ const path2 = document.createElementNS(svgNs, "path");
427
+ path2.setAttribute("stroke", "rgba(51, 51, 51, 1)");
428
+ path2.setAttribute("stroke-width", "0.8325");
429
+ path2.setAttribute("stroke-linejoin", "round");
430
+ path2.setAttribute("stroke-linecap", "round");
431
+ path2.setAttribute("d", "M3.24994 7.5L6.24994 4.5L9.24994 7.5");
432
+ svg.appendChild(path2);
433
+ return svg;
434
+ }
568
435
  function positionOverlay(overlay, target, tagMode = "none", callbacks) {
569
436
  const rect = target.getBoundingClientRect();
570
437
  overlay.style.top = `${rect.top + window.scrollY}px`;
@@ -587,8 +454,10 @@ function positionOverlay(overlay, target, tagMode = "none", callbacks) {
587
454
  textAlign: "center",
588
455
  display: "flex",
589
456
  alignItems: "center",
457
+ justifyContent: "center",
590
458
  gap: "3px",
591
- lineHeight: "1.4"
459
+ lineHeight: "1.4",
460
+ whiteSpace: "nowrap"
592
461
  });
593
462
  if (tagMode === "selected") {
594
463
  tag.style.backgroundColor = "#FC0";
@@ -597,12 +466,23 @@ function positionOverlay(overlay, target, tagMode = "none", callbacks) {
597
466
  tag.style.pointerEvents = "auto";
598
467
  const textSpan = document.createElement("span");
599
468
  textSpan.textContent = target.tagName.toLowerCase();
469
+ textSpan.style.display = "inline-flex";
470
+ textSpan.style.alignItems = "center";
471
+ textSpan.style.lineHeight = "1";
600
472
  tag.appendChild(textSpan);
601
473
  const arrow = document.createElement("span");
602
474
  arrow.setAttribute("data-tag-arrow", "");
603
- arrow.textContent = "\u2304";
604
- arrow.style.fontSize = "10px";
475
+ arrow.textContent = "";
476
+ arrow.style.display = "inline-flex";
477
+ arrow.style.alignItems = "center";
478
+ arrow.style.justifyContent = "center";
479
+ arrow.style.width = "12px";
480
+ arrow.style.height = "12px";
481
+ arrow.style.flex = "0 0 auto";
482
+ arrow.style.transformOrigin = "center";
605
483
  arrow.style.lineHeight = "1";
484
+ arrow.appendChild(createTagArrowSvg());
485
+ setTagArrowExpanded(arrow, false);
606
486
  tag.appendChild(arrow);
607
487
  if (callbacks?.onTagClick) {
608
488
  const onTagClick = callbacks.onTagClick;
@@ -725,6 +605,171 @@ function unfreezeAnimations() {
725
605
  if (overflowStyle) overflowStyle.remove();
726
606
  }
727
607
 
608
+ // src/runtime/layer-navigation.ts
609
+ function buildLayerTree(element) {
610
+ const tree = [];
611
+ const ancestors = [];
612
+ let parent = element.parentElement;
613
+ while (parent && parent !== document.body) {
614
+ if (hasSourceLocation(parent)) {
615
+ ancestors.push(parent);
616
+ }
617
+ parent = parent.parentElement;
618
+ }
619
+ ancestors.reverse();
620
+ ancestors.forEach((el) => {
621
+ tree.push({ element: el, tagName: el.tagName.toLowerCase(), depth: 0 });
622
+ });
623
+ tree.push({ element, tagName: element.tagName.toLowerCase(), depth: 0 });
624
+ for (let i = 0; i < element.children.length; i++) {
625
+ const child = element.children[i];
626
+ if (hasSourceLocation(child)) {
627
+ tree.push({ element: child, tagName: child.tagName.toLowerCase(), depth: 0 });
628
+ }
629
+ }
630
+ return tree;
631
+ }
632
+ function removeLayerDropdown(state) {
633
+ if (state.layerDropdown) {
634
+ const parentOverlay = state.layerDropdown.parentElement;
635
+ if (parentOverlay) {
636
+ const arrowEl = parentOverlay.querySelector("[data-tag-arrow]");
637
+ if (arrowEl) setTagArrowExpanded(arrowEl, false);
638
+ }
639
+ state.layerDropdown.remove();
640
+ state.layerDropdown = null;
641
+ reportDropdownState(state, false);
642
+ document.removeEventListener("keydown", handleLayerKeyboard);
643
+ }
644
+ }
645
+ function toggleLayerDropdown(state, element, anchor, onSelectElement) {
646
+ if (state.layerDropdown) {
647
+ removeLayerDropdown(state);
648
+ return;
649
+ }
650
+ const layers = buildLayerTree(element);
651
+ renderLayerDropdown(state, anchor, layers, element, onSelectElement);
652
+ }
653
+ function renderLayerDropdown(state, anchor, layers, currentElement, onSelectElement) {
654
+ const dropdown = document.createElement("div");
655
+ dropdown.setAttribute("data-layer-dropdown", "true");
656
+ dropdown.setAttribute(AGENT_ATTR, "");
657
+ Object.assign(dropdown.style, {
658
+ position: "absolute",
659
+ backgroundColor: "#ffffff",
660
+ border: "1px solid #e2e8f0",
661
+ borderRadius: "6px",
662
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
663
+ fontSize: "12px",
664
+ zIndex: "2147483647",
665
+ pointerEvents: "auto",
666
+ padding: "4px 0",
667
+ minWidth: "120px",
668
+ maxHeight: "320px",
669
+ overflowY: "auto"
670
+ });
671
+ let focusedIndex = -1;
672
+ const items = [];
673
+ layers.forEach((layer, idx) => {
674
+ const item = document.createElement("div");
675
+ item.setAttribute(AGENT_ATTR, "");
676
+ item.textContent = layer.tagName;
677
+ item.style.padding = "6px 16px";
678
+ item.style.cursor = "pointer";
679
+ item.style.whiteSpace = "nowrap";
680
+ if (layer.element === currentElement) {
681
+ item.style.color = "#000000";
682
+ item.style.backgroundColor = "rgba(255, 204, 0, 0.2)";
683
+ item.style.fontWeight = "600";
684
+ focusedIndex = idx;
685
+ } else {
686
+ item.style.color = "#64748b";
687
+ }
688
+ item.addEventListener("click", (e) => {
689
+ e.stopPropagation();
690
+ removeLayerDropdown(state);
691
+ onSelectElement(layer.element);
692
+ });
693
+ item.addEventListener("mouseenter", () => {
694
+ if (layer.element !== currentElement) {
695
+ item.style.backgroundColor = "#f1f5f9";
696
+ item.style.color = "#334155";
697
+ }
698
+ });
699
+ item.addEventListener("mouseleave", () => {
700
+ if (layer.element !== currentElement) {
701
+ item.style.backgroundColor = "transparent";
702
+ item.style.color = "#64748b";
703
+ }
704
+ });
705
+ items.push(item);
706
+ dropdown.appendChild(item);
707
+ });
708
+ document.body.appendChild(dropdown);
709
+ const anchorRect = anchor.getBoundingClientRect();
710
+ dropdown.style.top = `${anchorRect.bottom + window.scrollY + 2}px`;
711
+ dropdown.style.left = `${anchorRect.left + window.scrollX}px`;
712
+ requestAnimationFrame(() => {
713
+ const ddRect = dropdown.getBoundingClientRect();
714
+ if (ddRect.right > window.innerWidth - 4) {
715
+ dropdown.style.left = `${window.innerWidth - ddRect.width - 4 + window.scrollX}px`;
716
+ }
717
+ if (ddRect.left < 4) {
718
+ dropdown.style.left = `${4 + window.scrollX}px`;
719
+ }
720
+ if (ddRect.bottom > window.innerHeight) {
721
+ dropdown.style.top = `${anchorRect.top + window.scrollY - ddRect.height - 2}px`;
722
+ }
723
+ });
724
+ state.layerDropdown = dropdown;
725
+ reportDropdownState(state, true);
726
+ const handleKeydown = (e) => {
727
+ if (!state.layerDropdown) return;
728
+ switch (e.key) {
729
+ case "ArrowDown":
730
+ e.preventDefault();
731
+ focusedIndex = Math.min(focusedIndex + 1, items.length - 1);
732
+ highlightItem(items, focusedIndex, layers, currentElement);
733
+ break;
734
+ case "ArrowUp":
735
+ e.preventDefault();
736
+ focusedIndex = Math.max(focusedIndex - 1, 0);
737
+ highlightItem(items, focusedIndex, layers, currentElement);
738
+ break;
739
+ case "Enter":
740
+ e.preventDefault();
741
+ if (focusedIndex >= 0 && focusedIndex < layers.length) {
742
+ removeLayerDropdown(state);
743
+ onSelectElement(layers[focusedIndex].element);
744
+ }
745
+ break;
746
+ case "Escape":
747
+ e.preventDefault();
748
+ removeLayerDropdown(state);
749
+ break;
750
+ }
751
+ };
752
+ handleLayerKeyboard.current = handleKeydown;
753
+ document.addEventListener("keydown", handleLayerKeyboard);
754
+ }
755
+ function handleLayerKeyboard(e) {
756
+ const current = handleLayerKeyboard.current;
757
+ if (current) current(e);
758
+ }
759
+ function highlightItem(items, index, layers, currentElement) {
760
+ items.forEach((item, i) => {
761
+ if (layers[i].element === currentElement) {
762
+ item.style.color = "#000000";
763
+ item.style.backgroundColor = i === index ? "rgba(255, 204, 0, 0.35)" : "rgba(255, 204, 0, 0.2)";
764
+ item.style.fontWeight = "600";
765
+ } else {
766
+ item.style.backgroundColor = i === index ? "#f1f5f9" : "transparent";
767
+ item.style.color = i === index ? "#334155" : "#64748b";
768
+ item.style.fontWeight = "normal";
769
+ }
770
+ });
771
+ }
772
+
728
773
  // src/runtime/state.ts
729
774
  function createAgentState(options = {}) {
730
775
  return {
@@ -738,13 +783,36 @@ function createAgentState(options = {}) {
738
783
  layerDropdown: null,
739
784
  mutationObserver: null,
740
785
  attributeName: options.attributeName ?? DEFAULT_ATTRIBUTE_NAME,
741
- targetOrigin: options.targetOrigin ?? "*"
786
+ targetOrigin: options.targetOrigin ?? "*",
787
+ runtimeIdCounter: 0
742
788
  };
743
789
  }
744
790
 
745
791
  // src/runtime/index.ts
746
792
  function setupVisualEditAgent(options = {}) {
747
793
  const state = createAgentState(options);
794
+ const trackedSelector = `[${state.attributeName}], [data-visual-selector-id]`;
795
+ function shouldAssignRuntimeId(element) {
796
+ return !element.closest(`[${AGENT_ATTR}]`) && !element.hasAttribute(state.attributeName) && !element.hasAttribute("data-visual-selector-id");
797
+ }
798
+ function assignRuntimeId(element) {
799
+ if (!shouldAssignRuntimeId(element)) return;
800
+ state.runtimeIdCounter += 1;
801
+ element.setAttribute("data-visual-selector-id", `runtime:${state.runtimeIdCounter}`);
802
+ }
803
+ function trackElementSubtree(root) {
804
+ assignRuntimeId(root);
805
+ root.querySelectorAll("*").forEach((element) => assignRuntimeId(element));
806
+ }
807
+ function trackCurrentDom() {
808
+ if (!document.body) return;
809
+ trackElementSubtree(document.body);
810
+ }
811
+ function ensureElementTracked(element) {
812
+ if (!element.closest(`[${AGENT_ATTR}]`)) {
813
+ assignRuntimeId(element);
814
+ }
815
+ }
748
816
  function updateAllOverlayPositions() {
749
817
  if (state.selectedId && state.selectedElement?.isConnected) {
750
818
  const siblings = findAllElementsById(state.selectedId);
@@ -761,7 +829,7 @@ function setupVisualEditAgent(options = {}) {
761
829
  function onTagClick(target, tag) {
762
830
  const arrowEl = tag.querySelector("[data-tag-arrow]");
763
831
  if (arrowEl) {
764
- arrowEl.textContent = state.layerDropdown ? "\u2304" : "\u2303";
832
+ setTagArrowExpanded(arrowEl, !state.layerDropdown);
765
833
  }
766
834
  toggleLayerDropdown(state, target, tag, selectElement);
767
835
  }
@@ -772,7 +840,10 @@ function setupVisualEditAgent(options = {}) {
772
840
  if (freezeStyle) freezeStyle.disabled = false;
773
841
  if (!element) return null;
774
842
  if (element.closest(`[${AGENT_ATTR}]`)) return null;
775
- return element.closest(`[${state.attributeName}], [data-visual-selector-id]`) ?? null;
843
+ const trackedElement = element.closest(trackedSelector);
844
+ if (trackedElement) return trackedElement;
845
+ ensureElementTracked(element);
846
+ return element.hasAttribute("data-visual-selector-id") ? element : null;
776
847
  }
777
848
  function findHoverTarget(x, y, excludeId) {
778
849
  const element = findElementAtPoint(x, y);
@@ -820,6 +891,7 @@ function setupVisualEditAgent(options = {}) {
820
891
  selectElement(element);
821
892
  }
822
893
  function selectElement(element) {
894
+ ensureElementTracked(element);
823
895
  const id = getSourceId(element);
824
896
  if (!id) return;
825
897
  if (state.editingElement) {
@@ -855,6 +927,7 @@ function setupVisualEditAgent(options = {}) {
855
927
  if (enabled) {
856
928
  document.body.style.cursor = "crosshair";
857
929
  freezeAnimations();
930
+ trackCurrentDom();
858
931
  document.addEventListener("mousemove", onMouseMove);
859
932
  document.addEventListener("mouseleave", onMouseLeave);
860
933
  document.addEventListener("click", onClick, true);
@@ -881,6 +954,13 @@ function setupVisualEditAgent(options = {}) {
881
954
  function startMutationObserver() {
882
955
  if (state.mutationObserver) return;
883
956
  state.mutationObserver = new MutationObserver((mutations) => {
957
+ mutations.forEach((mutation) => {
958
+ mutation.addedNodes.forEach((node) => {
959
+ if (node instanceof Element) {
960
+ trackElementSubtree(node);
961
+ }
962
+ });
963
+ });
884
964
  const hasRelevantChange = mutations.some((m) => {
885
965
  if (m.type === "attributes" && ["style", "class", "width", "height"].includes(m.attributeName ?? "") && containsTrackedElement(m.target))
886
966
  return true;
@@ -906,8 +986,8 @@ function setupVisualEditAgent(options = {}) {
906
986
  }
907
987
  function containsTrackedElement(node) {
908
988
  if (!(node instanceof Element)) return false;
909
- if (node.hasAttribute(AGENT_ATTR)) return false;
910
- return hasSourceLocation(node) || !!node.querySelector(`[${state.attributeName}]`);
989
+ if (node.closest(`[${AGENT_ATTR}]`)) return false;
990
+ return node.hasAttribute(state.attributeName) || node.hasAttribute("data-visual-selector-id") || !!node.querySelector(trackedSelector);
911
991
  }
912
992
  function setupSandboxMountObserver() {
913
993
  if (window.self === window.top) return;
@@ -916,7 +996,9 @@ function setupVisualEditAgent(options = {}) {
916
996
  (m) => m.addedNodes.length > 0 || m.removedNodes.length > 0
917
997
  );
918
998
  if (!hasChanges) return;
919
- const hasTrackedElements = document.body.querySelectorAll("[data-source-location], [data-dynamic-content]").length > 0;
999
+ const hasTrackedElements = document.body.querySelectorAll(
1000
+ `[${state.attributeName}], [data-dynamic-content], [data-visual-selector-id]`
1001
+ ).length > 0;
920
1002
  try {
921
1003
  window.parent.postMessage(
922
1004
  {
@@ -936,18 +1018,24 @@ function setupVisualEditAgent(options = {}) {
936
1018
  }
937
1019
  }
938
1020
  function selectElementById(id) {
939
- const element = document.querySelector(`[${state.attributeName}="${id}"]`);
1021
+ const element = document.querySelector(
1022
+ `[${state.attributeName}="${id}"], [data-visual-selector-id="${id}"]`
1023
+ );
940
1024
  if (element) {
941
1025
  selectElement(element);
942
1026
  }
943
1027
  }
1028
+ function clearSelectionState() {
1029
+ clearAllOverlays(state, () => removeLayerDropdown(state));
1030
+ }
944
1031
  const onMessage = (e) => {
945
1032
  handleMessage(state, e, {
946
1033
  enableEditMode,
947
1034
  updateAllOverlayPositions,
948
1035
  stopInlineEditing: () => stopInlineEditing(state, updateAllOverlayPositions),
949
1036
  handleInlineEdit: (data) => handleInlineEdit(state, data, updateAllOverlayPositions),
950
- selectElementById
1037
+ selectElementById,
1038
+ clearSelectionState
951
1039
  });
952
1040
  };
953
1041
  window.addEventListener("message", onMessage);
@@ -966,7 +1054,7 @@ function setupVisualEditAgent(options = {}) {
966
1054
  enableEditMode,
967
1055
  selectElement,
968
1056
  clearSelection() {
969
- clearAllOverlays(state, () => removeLayerDropdown(state));
1057
+ clearSelectionState();
970
1058
  },
971
1059
  getSelectedId() {
972
1060
  return state.selectedId;