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 +2 -2
- package/dist/index.js +267 -179
- package/dist/index.js.map +1 -1
- package/dist/{runtime-DpE5pSIp.d.ts → runtime-D695qvel.d.ts} +1 -1
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +267 -179
- package/dist/runtime.js.map +1 -1
- package/package.json +1 -1
package/dist/runtime.js
CHANGED
|
@@ -141,169 +141,6 @@ function handleInlineEdit(state, data, updatePositions) {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
// src/runtime/layer-navigation.ts
|
|
145
|
-
function buildLayerTree(element) {
|
|
146
|
-
const tree = [];
|
|
147
|
-
const ancestors = [];
|
|
148
|
-
let parent = element.parentElement;
|
|
149
|
-
while (parent && parent !== document.body) {
|
|
150
|
-
if (hasSourceLocation(parent)) {
|
|
151
|
-
ancestors.push(parent);
|
|
152
|
-
}
|
|
153
|
-
parent = parent.parentElement;
|
|
154
|
-
}
|
|
155
|
-
ancestors.reverse();
|
|
156
|
-
ancestors.forEach((el) => {
|
|
157
|
-
tree.push({ element: el, tagName: el.tagName.toLowerCase(), depth: 0 });
|
|
158
|
-
});
|
|
159
|
-
tree.push({ element, tagName: element.tagName.toLowerCase(), depth: 0 });
|
|
160
|
-
for (let i = 0; i < element.children.length; i++) {
|
|
161
|
-
const child = element.children[i];
|
|
162
|
-
if (hasSourceLocation(child)) {
|
|
163
|
-
tree.push({ element: child, tagName: child.tagName.toLowerCase(), depth: 0 });
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return tree;
|
|
167
|
-
}
|
|
168
|
-
function removeLayerDropdown(state) {
|
|
169
|
-
if (state.layerDropdown) {
|
|
170
|
-
const parentOverlay = state.layerDropdown.parentElement;
|
|
171
|
-
if (parentOverlay) {
|
|
172
|
-
const arrowEl = parentOverlay.querySelector("[data-tag-arrow]");
|
|
173
|
-
if (arrowEl) arrowEl.textContent = "\u2304";
|
|
174
|
-
}
|
|
175
|
-
state.layerDropdown.remove();
|
|
176
|
-
state.layerDropdown = null;
|
|
177
|
-
document.removeEventListener("keydown", handleLayerKeyboard);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
function toggleLayerDropdown(state, element, anchor, onSelectElement) {
|
|
181
|
-
if (state.layerDropdown) {
|
|
182
|
-
removeLayerDropdown(state);
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
const layers = buildLayerTree(element);
|
|
186
|
-
renderLayerDropdown(state, anchor, layers, element, onSelectElement);
|
|
187
|
-
}
|
|
188
|
-
function renderLayerDropdown(state, anchor, layers, currentElement, onSelectElement) {
|
|
189
|
-
const dropdown = document.createElement("div");
|
|
190
|
-
dropdown.setAttribute("data-layer-dropdown", "true");
|
|
191
|
-
dropdown.setAttribute(AGENT_ATTR, "");
|
|
192
|
-
Object.assign(dropdown.style, {
|
|
193
|
-
position: "absolute",
|
|
194
|
-
backgroundColor: "#ffffff",
|
|
195
|
-
border: "1px solid #e2e8f0",
|
|
196
|
-
borderRadius: "6px",
|
|
197
|
-
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
198
|
-
fontSize: "12px",
|
|
199
|
-
zIndex: "99999",
|
|
200
|
-
pointerEvents: "auto",
|
|
201
|
-
padding: "4px 0",
|
|
202
|
-
minWidth: "120px",
|
|
203
|
-
maxHeight: "320px",
|
|
204
|
-
overflowY: "auto"
|
|
205
|
-
});
|
|
206
|
-
let focusedIndex = -1;
|
|
207
|
-
const items = [];
|
|
208
|
-
layers.forEach((layer, idx) => {
|
|
209
|
-
const item = document.createElement("div");
|
|
210
|
-
item.setAttribute(AGENT_ATTR, "");
|
|
211
|
-
item.textContent = layer.tagName;
|
|
212
|
-
item.style.padding = "6px 16px";
|
|
213
|
-
item.style.cursor = "pointer";
|
|
214
|
-
item.style.whiteSpace = "nowrap";
|
|
215
|
-
if (layer.element === currentElement) {
|
|
216
|
-
item.style.color = "#000000";
|
|
217
|
-
item.style.backgroundColor = "rgba(255, 204, 0, 0.2)";
|
|
218
|
-
item.style.fontWeight = "600";
|
|
219
|
-
focusedIndex = idx;
|
|
220
|
-
} else {
|
|
221
|
-
item.style.color = "#64748b";
|
|
222
|
-
}
|
|
223
|
-
item.addEventListener("click", (e) => {
|
|
224
|
-
e.stopPropagation();
|
|
225
|
-
removeLayerDropdown(state);
|
|
226
|
-
onSelectElement(layer.element);
|
|
227
|
-
});
|
|
228
|
-
item.addEventListener("mouseenter", () => {
|
|
229
|
-
if (layer.element !== currentElement) {
|
|
230
|
-
item.style.backgroundColor = "#f1f5f9";
|
|
231
|
-
item.style.color = "#334155";
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
item.addEventListener("mouseleave", () => {
|
|
235
|
-
if (layer.element !== currentElement) {
|
|
236
|
-
item.style.backgroundColor = "transparent";
|
|
237
|
-
item.style.color = "#64748b";
|
|
238
|
-
}
|
|
239
|
-
});
|
|
240
|
-
items.push(item);
|
|
241
|
-
dropdown.appendChild(item);
|
|
242
|
-
});
|
|
243
|
-
document.body.appendChild(dropdown);
|
|
244
|
-
const anchorRect = anchor.getBoundingClientRect();
|
|
245
|
-
dropdown.style.top = `${anchorRect.bottom + window.scrollY + 2}px`;
|
|
246
|
-
dropdown.style.left = `${anchorRect.left + window.scrollX}px`;
|
|
247
|
-
requestAnimationFrame(() => {
|
|
248
|
-
const ddRect = dropdown.getBoundingClientRect();
|
|
249
|
-
if (ddRect.right > window.innerWidth - 4) {
|
|
250
|
-
dropdown.style.left = `${window.innerWidth - ddRect.width - 4 + window.scrollX}px`;
|
|
251
|
-
}
|
|
252
|
-
if (ddRect.left < 4) {
|
|
253
|
-
dropdown.style.left = `${4 + window.scrollX}px`;
|
|
254
|
-
}
|
|
255
|
-
if (ddRect.bottom > window.innerHeight) {
|
|
256
|
-
dropdown.style.top = `${anchorRect.top + window.scrollY - ddRect.height - 2}px`;
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
state.layerDropdown = dropdown;
|
|
260
|
-
const handleKeydown = (e) => {
|
|
261
|
-
if (!state.layerDropdown) return;
|
|
262
|
-
switch (e.key) {
|
|
263
|
-
case "ArrowDown":
|
|
264
|
-
e.preventDefault();
|
|
265
|
-
focusedIndex = Math.min(focusedIndex + 1, items.length - 1);
|
|
266
|
-
highlightItem(items, focusedIndex, layers, currentElement);
|
|
267
|
-
break;
|
|
268
|
-
case "ArrowUp":
|
|
269
|
-
e.preventDefault();
|
|
270
|
-
focusedIndex = Math.max(focusedIndex - 1, 0);
|
|
271
|
-
highlightItem(items, focusedIndex, layers, currentElement);
|
|
272
|
-
break;
|
|
273
|
-
case "Enter":
|
|
274
|
-
e.preventDefault();
|
|
275
|
-
if (focusedIndex >= 0 && focusedIndex < layers.length) {
|
|
276
|
-
removeLayerDropdown(state);
|
|
277
|
-
onSelectElement(layers[focusedIndex].element);
|
|
278
|
-
}
|
|
279
|
-
break;
|
|
280
|
-
case "Escape":
|
|
281
|
-
e.preventDefault();
|
|
282
|
-
removeLayerDropdown(state);
|
|
283
|
-
break;
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
handleLayerKeyboard.current = handleKeydown;
|
|
287
|
-
document.addEventListener("keydown", handleLayerKeyboard);
|
|
288
|
-
}
|
|
289
|
-
function handleLayerKeyboard(e) {
|
|
290
|
-
const current = handleLayerKeyboard.current;
|
|
291
|
-
if (current) current(e);
|
|
292
|
-
}
|
|
293
|
-
function highlightItem(items, index, layers, currentElement) {
|
|
294
|
-
items.forEach((item, i) => {
|
|
295
|
-
if (layers[i].element === currentElement) {
|
|
296
|
-
item.style.color = "#000000";
|
|
297
|
-
item.style.backgroundColor = i === index ? "rgba(255, 204, 0, 0.35)" : "rgba(255, 204, 0, 0.2)";
|
|
298
|
-
item.style.fontWeight = "600";
|
|
299
|
-
} else {
|
|
300
|
-
item.style.backgroundColor = i === index ? "#f1f5f9" : "transparent";
|
|
301
|
-
item.style.color = i === index ? "#334155" : "#64748b";
|
|
302
|
-
item.style.fontWeight = "normal";
|
|
303
|
-
}
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
144
|
// src/runtime/messages.ts
|
|
308
145
|
function reportElementSelected(state, element) {
|
|
309
146
|
const el = element;
|
|
@@ -362,6 +199,18 @@ function reportPositionUpdate(state) {
|
|
|
362
199
|
} catch {
|
|
363
200
|
}
|
|
364
201
|
}
|
|
202
|
+
function reportDropdownState(state, isOpen) {
|
|
203
|
+
try {
|
|
204
|
+
window.parent.postMessage(
|
|
205
|
+
{
|
|
206
|
+
type: "dropdown-state",
|
|
207
|
+
data: { isOpen }
|
|
208
|
+
},
|
|
209
|
+
state.targetOrigin
|
|
210
|
+
);
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
213
|
+
}
|
|
365
214
|
function handleMessage(state, e, callbacks) {
|
|
366
215
|
if (state.targetOrigin !== "*" && e.origin !== state.targetOrigin) return;
|
|
367
216
|
const msg = e.data;
|
|
@@ -395,10 +244,7 @@ function handleMessage(state, e, callbacks) {
|
|
|
395
244
|
break;
|
|
396
245
|
case "unselect-element":
|
|
397
246
|
if (state.editingElement) callbacks.stopInlineEditing();
|
|
398
|
-
|
|
399
|
-
state.selectionOverlays = [];
|
|
400
|
-
state.selectedId = null;
|
|
401
|
-
state.selectedElement = null;
|
|
247
|
+
callbacks.clearSelectionState();
|
|
402
248
|
break;
|
|
403
249
|
case "update-theme-variables":
|
|
404
250
|
if (msg.data?.variables) {
|
|
@@ -488,6 +334,27 @@ function createOverlay(opts) {
|
|
|
488
334
|
}
|
|
489
335
|
return overlay;
|
|
490
336
|
}
|
|
337
|
+
function setTagArrowExpanded(arrow, expanded) {
|
|
338
|
+
arrow.style.transform = expanded ? "rotate(0deg)" : "rotate(180deg)";
|
|
339
|
+
}
|
|
340
|
+
function createTagArrowSvg() {
|
|
341
|
+
const svgNs = "http://www.w3.org/2000/svg";
|
|
342
|
+
const svg = document.createElementNS(svgNs, "svg");
|
|
343
|
+
svg.setAttribute("xmlns", svgNs);
|
|
344
|
+
svg.setAttribute("width", "12");
|
|
345
|
+
svg.setAttribute("height", "12");
|
|
346
|
+
svg.setAttribute("viewBox", "0 0 12 12");
|
|
347
|
+
svg.setAttribute("fill", "none");
|
|
348
|
+
svg.style.display = "block";
|
|
349
|
+
const path = document.createElementNS(svgNs, "path");
|
|
350
|
+
path.setAttribute("stroke", "rgba(51, 51, 51, 1)");
|
|
351
|
+
path.setAttribute("stroke-width", "0.8325");
|
|
352
|
+
path.setAttribute("stroke-linejoin", "round");
|
|
353
|
+
path.setAttribute("stroke-linecap", "round");
|
|
354
|
+
path.setAttribute("d", "M3.24994 7.5L6.24994 4.5L9.24994 7.5");
|
|
355
|
+
svg.appendChild(path);
|
|
356
|
+
return svg;
|
|
357
|
+
}
|
|
491
358
|
function positionOverlay(overlay, target, tagMode = "none", callbacks) {
|
|
492
359
|
const rect = target.getBoundingClientRect();
|
|
493
360
|
overlay.style.top = `${rect.top + window.scrollY}px`;
|
|
@@ -510,8 +377,10 @@ function positionOverlay(overlay, target, tagMode = "none", callbacks) {
|
|
|
510
377
|
textAlign: "center",
|
|
511
378
|
display: "flex",
|
|
512
379
|
alignItems: "center",
|
|
380
|
+
justifyContent: "center",
|
|
513
381
|
gap: "3px",
|
|
514
|
-
lineHeight: "1.4"
|
|
382
|
+
lineHeight: "1.4",
|
|
383
|
+
whiteSpace: "nowrap"
|
|
515
384
|
});
|
|
516
385
|
if (tagMode === "selected") {
|
|
517
386
|
tag.style.backgroundColor = "#FC0";
|
|
@@ -520,12 +389,23 @@ function positionOverlay(overlay, target, tagMode = "none", callbacks) {
|
|
|
520
389
|
tag.style.pointerEvents = "auto";
|
|
521
390
|
const textSpan = document.createElement("span");
|
|
522
391
|
textSpan.textContent = target.tagName.toLowerCase();
|
|
392
|
+
textSpan.style.display = "inline-flex";
|
|
393
|
+
textSpan.style.alignItems = "center";
|
|
394
|
+
textSpan.style.lineHeight = "1";
|
|
523
395
|
tag.appendChild(textSpan);
|
|
524
396
|
const arrow = document.createElement("span");
|
|
525
397
|
arrow.setAttribute("data-tag-arrow", "");
|
|
526
|
-
arrow.textContent = "
|
|
527
|
-
arrow.style.
|
|
398
|
+
arrow.textContent = "";
|
|
399
|
+
arrow.style.display = "inline-flex";
|
|
400
|
+
arrow.style.alignItems = "center";
|
|
401
|
+
arrow.style.justifyContent = "center";
|
|
402
|
+
arrow.style.width = "12px";
|
|
403
|
+
arrow.style.height = "12px";
|
|
404
|
+
arrow.style.flex = "0 0 auto";
|
|
405
|
+
arrow.style.transformOrigin = "center";
|
|
528
406
|
arrow.style.lineHeight = "1";
|
|
407
|
+
arrow.appendChild(createTagArrowSvg());
|
|
408
|
+
setTagArrowExpanded(arrow, false);
|
|
529
409
|
tag.appendChild(arrow);
|
|
530
410
|
if (callbacks?.onTagClick) {
|
|
531
411
|
const onTagClick = callbacks.onTagClick;
|
|
@@ -648,6 +528,171 @@ function unfreezeAnimations() {
|
|
|
648
528
|
if (overflowStyle) overflowStyle.remove();
|
|
649
529
|
}
|
|
650
530
|
|
|
531
|
+
// src/runtime/layer-navigation.ts
|
|
532
|
+
function buildLayerTree(element) {
|
|
533
|
+
const tree = [];
|
|
534
|
+
const ancestors = [];
|
|
535
|
+
let parent = element.parentElement;
|
|
536
|
+
while (parent && parent !== document.body) {
|
|
537
|
+
if (hasSourceLocation(parent)) {
|
|
538
|
+
ancestors.push(parent);
|
|
539
|
+
}
|
|
540
|
+
parent = parent.parentElement;
|
|
541
|
+
}
|
|
542
|
+
ancestors.reverse();
|
|
543
|
+
ancestors.forEach((el) => {
|
|
544
|
+
tree.push({ element: el, tagName: el.tagName.toLowerCase(), depth: 0 });
|
|
545
|
+
});
|
|
546
|
+
tree.push({ element, tagName: element.tagName.toLowerCase(), depth: 0 });
|
|
547
|
+
for (let i = 0; i < element.children.length; i++) {
|
|
548
|
+
const child = element.children[i];
|
|
549
|
+
if (hasSourceLocation(child)) {
|
|
550
|
+
tree.push({ element: child, tagName: child.tagName.toLowerCase(), depth: 0 });
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return tree;
|
|
554
|
+
}
|
|
555
|
+
function removeLayerDropdown(state) {
|
|
556
|
+
if (state.layerDropdown) {
|
|
557
|
+
const parentOverlay = state.layerDropdown.parentElement;
|
|
558
|
+
if (parentOverlay) {
|
|
559
|
+
const arrowEl = parentOverlay.querySelector("[data-tag-arrow]");
|
|
560
|
+
if (arrowEl) setTagArrowExpanded(arrowEl, false);
|
|
561
|
+
}
|
|
562
|
+
state.layerDropdown.remove();
|
|
563
|
+
state.layerDropdown = null;
|
|
564
|
+
reportDropdownState(state, false);
|
|
565
|
+
document.removeEventListener("keydown", handleLayerKeyboard);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
function toggleLayerDropdown(state, element, anchor, onSelectElement) {
|
|
569
|
+
if (state.layerDropdown) {
|
|
570
|
+
removeLayerDropdown(state);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
const layers = buildLayerTree(element);
|
|
574
|
+
renderLayerDropdown(state, anchor, layers, element, onSelectElement);
|
|
575
|
+
}
|
|
576
|
+
function renderLayerDropdown(state, anchor, layers, currentElement, onSelectElement) {
|
|
577
|
+
const dropdown = document.createElement("div");
|
|
578
|
+
dropdown.setAttribute("data-layer-dropdown", "true");
|
|
579
|
+
dropdown.setAttribute(AGENT_ATTR, "");
|
|
580
|
+
Object.assign(dropdown.style, {
|
|
581
|
+
position: "absolute",
|
|
582
|
+
backgroundColor: "#ffffff",
|
|
583
|
+
border: "1px solid #e2e8f0",
|
|
584
|
+
borderRadius: "6px",
|
|
585
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
|
|
586
|
+
fontSize: "12px",
|
|
587
|
+
zIndex: "2147483647",
|
|
588
|
+
pointerEvents: "auto",
|
|
589
|
+
padding: "4px 0",
|
|
590
|
+
minWidth: "120px",
|
|
591
|
+
maxHeight: "320px",
|
|
592
|
+
overflowY: "auto"
|
|
593
|
+
});
|
|
594
|
+
let focusedIndex = -1;
|
|
595
|
+
const items = [];
|
|
596
|
+
layers.forEach((layer, idx) => {
|
|
597
|
+
const item = document.createElement("div");
|
|
598
|
+
item.setAttribute(AGENT_ATTR, "");
|
|
599
|
+
item.textContent = layer.tagName;
|
|
600
|
+
item.style.padding = "6px 16px";
|
|
601
|
+
item.style.cursor = "pointer";
|
|
602
|
+
item.style.whiteSpace = "nowrap";
|
|
603
|
+
if (layer.element === currentElement) {
|
|
604
|
+
item.style.color = "#000000";
|
|
605
|
+
item.style.backgroundColor = "rgba(255, 204, 0, 0.2)";
|
|
606
|
+
item.style.fontWeight = "600";
|
|
607
|
+
focusedIndex = idx;
|
|
608
|
+
} else {
|
|
609
|
+
item.style.color = "#64748b";
|
|
610
|
+
}
|
|
611
|
+
item.addEventListener("click", (e) => {
|
|
612
|
+
e.stopPropagation();
|
|
613
|
+
removeLayerDropdown(state);
|
|
614
|
+
onSelectElement(layer.element);
|
|
615
|
+
});
|
|
616
|
+
item.addEventListener("mouseenter", () => {
|
|
617
|
+
if (layer.element !== currentElement) {
|
|
618
|
+
item.style.backgroundColor = "#f1f5f9";
|
|
619
|
+
item.style.color = "#334155";
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
item.addEventListener("mouseleave", () => {
|
|
623
|
+
if (layer.element !== currentElement) {
|
|
624
|
+
item.style.backgroundColor = "transparent";
|
|
625
|
+
item.style.color = "#64748b";
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
items.push(item);
|
|
629
|
+
dropdown.appendChild(item);
|
|
630
|
+
});
|
|
631
|
+
document.body.appendChild(dropdown);
|
|
632
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
633
|
+
dropdown.style.top = `${anchorRect.bottom + window.scrollY + 2}px`;
|
|
634
|
+
dropdown.style.left = `${anchorRect.left + window.scrollX}px`;
|
|
635
|
+
requestAnimationFrame(() => {
|
|
636
|
+
const ddRect = dropdown.getBoundingClientRect();
|
|
637
|
+
if (ddRect.right > window.innerWidth - 4) {
|
|
638
|
+
dropdown.style.left = `${window.innerWidth - ddRect.width - 4 + window.scrollX}px`;
|
|
639
|
+
}
|
|
640
|
+
if (ddRect.left < 4) {
|
|
641
|
+
dropdown.style.left = `${4 + window.scrollX}px`;
|
|
642
|
+
}
|
|
643
|
+
if (ddRect.bottom > window.innerHeight) {
|
|
644
|
+
dropdown.style.top = `${anchorRect.top + window.scrollY - ddRect.height - 2}px`;
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
state.layerDropdown = dropdown;
|
|
648
|
+
reportDropdownState(state, true);
|
|
649
|
+
const handleKeydown = (e) => {
|
|
650
|
+
if (!state.layerDropdown) return;
|
|
651
|
+
switch (e.key) {
|
|
652
|
+
case "ArrowDown":
|
|
653
|
+
e.preventDefault();
|
|
654
|
+
focusedIndex = Math.min(focusedIndex + 1, items.length - 1);
|
|
655
|
+
highlightItem(items, focusedIndex, layers, currentElement);
|
|
656
|
+
break;
|
|
657
|
+
case "ArrowUp":
|
|
658
|
+
e.preventDefault();
|
|
659
|
+
focusedIndex = Math.max(focusedIndex - 1, 0);
|
|
660
|
+
highlightItem(items, focusedIndex, layers, currentElement);
|
|
661
|
+
break;
|
|
662
|
+
case "Enter":
|
|
663
|
+
e.preventDefault();
|
|
664
|
+
if (focusedIndex >= 0 && focusedIndex < layers.length) {
|
|
665
|
+
removeLayerDropdown(state);
|
|
666
|
+
onSelectElement(layers[focusedIndex].element);
|
|
667
|
+
}
|
|
668
|
+
break;
|
|
669
|
+
case "Escape":
|
|
670
|
+
e.preventDefault();
|
|
671
|
+
removeLayerDropdown(state);
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
handleLayerKeyboard.current = handleKeydown;
|
|
676
|
+
document.addEventListener("keydown", handleLayerKeyboard);
|
|
677
|
+
}
|
|
678
|
+
function handleLayerKeyboard(e) {
|
|
679
|
+
const current = handleLayerKeyboard.current;
|
|
680
|
+
if (current) current(e);
|
|
681
|
+
}
|
|
682
|
+
function highlightItem(items, index, layers, currentElement) {
|
|
683
|
+
items.forEach((item, i) => {
|
|
684
|
+
if (layers[i].element === currentElement) {
|
|
685
|
+
item.style.color = "#000000";
|
|
686
|
+
item.style.backgroundColor = i === index ? "rgba(255, 204, 0, 0.35)" : "rgba(255, 204, 0, 0.2)";
|
|
687
|
+
item.style.fontWeight = "600";
|
|
688
|
+
} else {
|
|
689
|
+
item.style.backgroundColor = i === index ? "#f1f5f9" : "transparent";
|
|
690
|
+
item.style.color = i === index ? "#334155" : "#64748b";
|
|
691
|
+
item.style.fontWeight = "normal";
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
|
|
651
696
|
// src/runtime/state.ts
|
|
652
697
|
function createAgentState(options = {}) {
|
|
653
698
|
return {
|
|
@@ -661,13 +706,36 @@ function createAgentState(options = {}) {
|
|
|
661
706
|
layerDropdown: null,
|
|
662
707
|
mutationObserver: null,
|
|
663
708
|
attributeName: options.attributeName ?? DEFAULT_ATTRIBUTE_NAME,
|
|
664
|
-
targetOrigin: options.targetOrigin ?? "*"
|
|
709
|
+
targetOrigin: options.targetOrigin ?? "*",
|
|
710
|
+
runtimeIdCounter: 0
|
|
665
711
|
};
|
|
666
712
|
}
|
|
667
713
|
|
|
668
714
|
// src/runtime/index.ts
|
|
669
715
|
function setupVisualEditAgent(options = {}) {
|
|
670
716
|
const state = createAgentState(options);
|
|
717
|
+
const trackedSelector = `[${state.attributeName}], [data-visual-selector-id]`;
|
|
718
|
+
function shouldAssignRuntimeId(element) {
|
|
719
|
+
return !element.closest(`[${AGENT_ATTR}]`) && !element.hasAttribute(state.attributeName) && !element.hasAttribute("data-visual-selector-id");
|
|
720
|
+
}
|
|
721
|
+
function assignRuntimeId(element) {
|
|
722
|
+
if (!shouldAssignRuntimeId(element)) return;
|
|
723
|
+
state.runtimeIdCounter += 1;
|
|
724
|
+
element.setAttribute("data-visual-selector-id", `runtime:${state.runtimeIdCounter}`);
|
|
725
|
+
}
|
|
726
|
+
function trackElementSubtree(root) {
|
|
727
|
+
assignRuntimeId(root);
|
|
728
|
+
root.querySelectorAll("*").forEach((element) => assignRuntimeId(element));
|
|
729
|
+
}
|
|
730
|
+
function trackCurrentDom() {
|
|
731
|
+
if (!document.body) return;
|
|
732
|
+
trackElementSubtree(document.body);
|
|
733
|
+
}
|
|
734
|
+
function ensureElementTracked(element) {
|
|
735
|
+
if (!element.closest(`[${AGENT_ATTR}]`)) {
|
|
736
|
+
assignRuntimeId(element);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
671
739
|
function updateAllOverlayPositions() {
|
|
672
740
|
if (state.selectedId && state.selectedElement?.isConnected) {
|
|
673
741
|
const siblings = findAllElementsById(state.selectedId);
|
|
@@ -684,7 +752,7 @@ function setupVisualEditAgent(options = {}) {
|
|
|
684
752
|
function onTagClick(target, tag) {
|
|
685
753
|
const arrowEl = tag.querySelector("[data-tag-arrow]");
|
|
686
754
|
if (arrowEl) {
|
|
687
|
-
arrowEl
|
|
755
|
+
setTagArrowExpanded(arrowEl, !state.layerDropdown);
|
|
688
756
|
}
|
|
689
757
|
toggleLayerDropdown(state, target, tag, selectElement);
|
|
690
758
|
}
|
|
@@ -695,7 +763,10 @@ function setupVisualEditAgent(options = {}) {
|
|
|
695
763
|
if (freezeStyle) freezeStyle.disabled = false;
|
|
696
764
|
if (!element) return null;
|
|
697
765
|
if (element.closest(`[${AGENT_ATTR}]`)) return null;
|
|
698
|
-
|
|
766
|
+
const trackedElement = element.closest(trackedSelector);
|
|
767
|
+
if (trackedElement) return trackedElement;
|
|
768
|
+
ensureElementTracked(element);
|
|
769
|
+
return element.hasAttribute("data-visual-selector-id") ? element : null;
|
|
699
770
|
}
|
|
700
771
|
function findHoverTarget(x, y, excludeId) {
|
|
701
772
|
const element = findElementAtPoint(x, y);
|
|
@@ -743,6 +814,7 @@ function setupVisualEditAgent(options = {}) {
|
|
|
743
814
|
selectElement(element);
|
|
744
815
|
}
|
|
745
816
|
function selectElement(element) {
|
|
817
|
+
ensureElementTracked(element);
|
|
746
818
|
const id = getSourceId(element);
|
|
747
819
|
if (!id) return;
|
|
748
820
|
if (state.editingElement) {
|
|
@@ -778,6 +850,7 @@ function setupVisualEditAgent(options = {}) {
|
|
|
778
850
|
if (enabled) {
|
|
779
851
|
document.body.style.cursor = "crosshair";
|
|
780
852
|
freezeAnimations();
|
|
853
|
+
trackCurrentDom();
|
|
781
854
|
document.addEventListener("mousemove", onMouseMove);
|
|
782
855
|
document.addEventListener("mouseleave", onMouseLeave);
|
|
783
856
|
document.addEventListener("click", onClick, true);
|
|
@@ -804,6 +877,13 @@ function setupVisualEditAgent(options = {}) {
|
|
|
804
877
|
function startMutationObserver() {
|
|
805
878
|
if (state.mutationObserver) return;
|
|
806
879
|
state.mutationObserver = new MutationObserver((mutations) => {
|
|
880
|
+
mutations.forEach((mutation) => {
|
|
881
|
+
mutation.addedNodes.forEach((node) => {
|
|
882
|
+
if (node instanceof Element) {
|
|
883
|
+
trackElementSubtree(node);
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
});
|
|
807
887
|
const hasRelevantChange = mutations.some((m) => {
|
|
808
888
|
if (m.type === "attributes" && ["style", "class", "width", "height"].includes(m.attributeName ?? "") && containsTrackedElement(m.target))
|
|
809
889
|
return true;
|
|
@@ -829,8 +909,8 @@ function setupVisualEditAgent(options = {}) {
|
|
|
829
909
|
}
|
|
830
910
|
function containsTrackedElement(node) {
|
|
831
911
|
if (!(node instanceof Element)) return false;
|
|
832
|
-
if (node.
|
|
833
|
-
return
|
|
912
|
+
if (node.closest(`[${AGENT_ATTR}]`)) return false;
|
|
913
|
+
return node.hasAttribute(state.attributeName) || node.hasAttribute("data-visual-selector-id") || !!node.querySelector(trackedSelector);
|
|
834
914
|
}
|
|
835
915
|
function setupSandboxMountObserver() {
|
|
836
916
|
if (window.self === window.top) return;
|
|
@@ -839,7 +919,9 @@ function setupVisualEditAgent(options = {}) {
|
|
|
839
919
|
(m) => m.addedNodes.length > 0 || m.removedNodes.length > 0
|
|
840
920
|
);
|
|
841
921
|
if (!hasChanges) return;
|
|
842
|
-
const hasTrackedElements = document.body.querySelectorAll(
|
|
922
|
+
const hasTrackedElements = document.body.querySelectorAll(
|
|
923
|
+
`[${state.attributeName}], [data-dynamic-content], [data-visual-selector-id]`
|
|
924
|
+
).length > 0;
|
|
843
925
|
try {
|
|
844
926
|
window.parent.postMessage(
|
|
845
927
|
{
|
|
@@ -859,18 +941,24 @@ function setupVisualEditAgent(options = {}) {
|
|
|
859
941
|
}
|
|
860
942
|
}
|
|
861
943
|
function selectElementById(id) {
|
|
862
|
-
const element = document.querySelector(
|
|
944
|
+
const element = document.querySelector(
|
|
945
|
+
`[${state.attributeName}="${id}"], [data-visual-selector-id="${id}"]`
|
|
946
|
+
);
|
|
863
947
|
if (element) {
|
|
864
948
|
selectElement(element);
|
|
865
949
|
}
|
|
866
950
|
}
|
|
951
|
+
function clearSelectionState() {
|
|
952
|
+
clearAllOverlays(state, () => removeLayerDropdown(state));
|
|
953
|
+
}
|
|
867
954
|
const onMessage = (e) => {
|
|
868
955
|
handleMessage(state, e, {
|
|
869
956
|
enableEditMode,
|
|
870
957
|
updateAllOverlayPositions,
|
|
871
958
|
stopInlineEditing: () => stopInlineEditing(state, updateAllOverlayPositions),
|
|
872
959
|
handleInlineEdit: (data) => handleInlineEdit(state, data, updateAllOverlayPositions),
|
|
873
|
-
selectElementById
|
|
960
|
+
selectElementById,
|
|
961
|
+
clearSelectionState
|
|
874
962
|
});
|
|
875
963
|
};
|
|
876
964
|
window.addEventListener("message", onMessage);
|
|
@@ -889,7 +977,7 @@ function setupVisualEditAgent(options = {}) {
|
|
|
889
977
|
enableEditMode,
|
|
890
978
|
selectElement,
|
|
891
979
|
clearSelection() {
|
|
892
|
-
|
|
980
|
+
clearSelectionState();
|
|
893
981
|
},
|
|
894
982
|
getSelectedId() {
|
|
895
983
|
return state.selectedId;
|