@base44-preview/vite-plugin 0.2.28-pr.43.f34d1cd → 0.2.29-pr.45.4649f89
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/capabilities/inline-edit/controller.d.ts.map +1 -1
- package/dist/capabilities/inline-edit/controller.js +3 -0
- package/dist/capabilities/inline-edit/controller.js.map +1 -1
- package/dist/injections/layer-dropdown/dropdown-ui.d.ts.map +1 -1
- package/dist/injections/layer-dropdown/dropdown-ui.js +3 -0
- package/dist/injections/layer-dropdown/dropdown-ui.js.map +1 -1
- package/dist/injections/utils.d.ts +6 -0
- package/dist/injections/utils.d.ts.map +1 -1
- package/dist/injections/utils.js +66 -0
- package/dist/injections/utils.js.map +1 -1
- package/dist/injections/visual-edit-agent.d.ts.map +1 -1
- package/dist/injections/visual-edit-agent.js +62 -46
- package/dist/injections/visual-edit-agent.js.map +1 -1
- package/dist/statics/index.mjs +19 -2
- package/dist/statics/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/inline-edit/controller.ts +3 -0
- package/src/injections/layer-dropdown/dropdown-ui.ts +3 -0
- package/src/injections/utils.ts +75 -0
- package/src/injections/visual-edit-agent.ts +60 -58
package/src/injections/utils.ts
CHANGED
|
@@ -18,6 +18,8 @@ export function getElementSelectorId(element: Element): string | null {
|
|
|
18
18
|
|
|
19
19
|
export const ALLOWED_ATTRIBUTES: string[] = ["src"];
|
|
20
20
|
|
|
21
|
+
export const PLUGIN_ELEMENT_ATTR = "data-vite-plugin-element";
|
|
22
|
+
|
|
21
23
|
/** Find elements by ID - first try data-source-location, fallback to data-visual-selector-id */
|
|
22
24
|
export function findElementsById(id: string | null): Element[] {
|
|
23
25
|
if (!id) return [];
|
|
@@ -64,3 +66,76 @@ export function collectAllowedAttributes(element: Element, allowedAttributes: st
|
|
|
64
66
|
}
|
|
65
67
|
return attributes;
|
|
66
68
|
}
|
|
69
|
+
|
|
70
|
+
export function stopAnimations(): void {
|
|
71
|
+
if (document.getElementById('freeze-animations')) return;
|
|
72
|
+
|
|
73
|
+
const animStyle = document.createElement('style');
|
|
74
|
+
animStyle.id = 'freeze-animations';
|
|
75
|
+
animStyle.textContent = `
|
|
76
|
+
*, *::before, *::after {
|
|
77
|
+
animation-play-state: paused !important;
|
|
78
|
+
transition: none !important;
|
|
79
|
+
}
|
|
80
|
+
[${PLUGIN_ELEMENT_ATTR}],
|
|
81
|
+
[${PLUGIN_ELEMENT_ATTR}] *,
|
|
82
|
+
[${PLUGIN_ELEMENT_ATTR}]::before,
|
|
83
|
+
[${PLUGIN_ELEMENT_ATTR}] *::before,
|
|
84
|
+
[${PLUGIN_ELEMENT_ATTR}]::after,
|
|
85
|
+
[${PLUGIN_ELEMENT_ATTR}] *::after {
|
|
86
|
+
animation-play-state: running !important;
|
|
87
|
+
transition: revert !important;
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
|
|
91
|
+
const pointerStyle = document.createElement('style');
|
|
92
|
+
pointerStyle.id = 'freeze-pointer-events';
|
|
93
|
+
pointerStyle.textContent = `
|
|
94
|
+
body * { pointer-events: none !important; }
|
|
95
|
+
[${PLUGIN_ELEMENT_ATTR}], [${PLUGIN_ELEMENT_ATTR}] * { pointer-events: auto !important; }
|
|
96
|
+
`;
|
|
97
|
+
|
|
98
|
+
const target = document.head || document.documentElement;
|
|
99
|
+
target.appendChild(animStyle);
|
|
100
|
+
target.appendChild(pointerStyle);
|
|
101
|
+
|
|
102
|
+
document.getAnimations().forEach((a) => a.pause());
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function resumeAnimations(): void {
|
|
106
|
+
const animStyle = document.getElementById('freeze-animations');
|
|
107
|
+
if (!animStyle) return;
|
|
108
|
+
|
|
109
|
+
animStyle.remove();
|
|
110
|
+
document.getElementById('freeze-pointer-events')?.remove();
|
|
111
|
+
|
|
112
|
+
document.getAnimations().forEach((a) => {
|
|
113
|
+
try { a.play(); } catch { /* animation target may have been removed */ }
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function findInstrumentedElement(x: number, y: number): Element | null {
|
|
118
|
+
const pointerStyle = document.getElementById('freeze-pointer-events') as HTMLStyleElement | null;
|
|
119
|
+
if (pointerStyle) pointerStyle.disabled = true;
|
|
120
|
+
|
|
121
|
+
const el = document.elementFromPoint(x, y);
|
|
122
|
+
|
|
123
|
+
if (pointerStyle) pointerStyle.disabled = false;
|
|
124
|
+
|
|
125
|
+
return el?.closest('[data-source-location], [data-visual-selector-id]') ?? null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Resolve which element should be hovered at (x, y), skipping the currently selected element. */
|
|
129
|
+
export function resolveHoverTarget(x: number, y: number, selectedElementId: string | null): string | null {
|
|
130
|
+
const element = findInstrumentedElement(x, y);
|
|
131
|
+
if (!element) return null;
|
|
132
|
+
|
|
133
|
+
const htmlElement = element as HTMLElement;
|
|
134
|
+
const selectorId =
|
|
135
|
+
htmlElement.dataset.sourceLocation ||
|
|
136
|
+
htmlElement.dataset.visualSelectorId || null;
|
|
137
|
+
|
|
138
|
+
if (selectorId === selectedElementId) return null;
|
|
139
|
+
|
|
140
|
+
return selectorId;
|
|
141
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, ALLOWED_ATTRIBUTES, getElementSelectorId } from "./utils.js";
|
|
1
|
+
import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, ALLOWED_ATTRIBUTES, getElementSelectorId, stopAnimations, resumeAnimations, findInstrumentedElement, resolveHoverTarget } from "./utils.js";
|
|
2
2
|
import { createLayerController } from "./layer-dropdown/controller.js";
|
|
3
3
|
import { LAYER_DROPDOWN_ATTR } from "./layer-dropdown/consts.js";
|
|
4
4
|
import { createInlineEditController } from "../capabilities/inline-edit/index.js";
|
|
@@ -191,53 +191,21 @@ export function setupVisualEditAgent() {
|
|
|
191
191
|
window.parent.postMessage({ type: "unselect-element" }, "*");
|
|
192
192
|
};
|
|
193
193
|
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const target = e.target as Element;
|
|
194
|
+
// Hover detection via mousemove + elementFromPoint (since app elements have pointer-events: none)
|
|
195
|
+
let lastHoveredSelectorId: string | null = null;
|
|
196
|
+
let pendingMouseMoveRaf: number | null = null;
|
|
200
197
|
|
|
201
|
-
|
|
202
|
-
if (
|
|
198
|
+
const clearHoverState = () => {
|
|
199
|
+
if (lastHoveredSelectorId !== null) {
|
|
203
200
|
clearHoverOverlays();
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Prevent hover effects on SVG path elements
|
|
208
|
-
if (target.tagName.toLowerCase() === "path") {
|
|
209
|
-
clearHoverOverlays();
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Support both data-source-location and data-visual-selector-id
|
|
214
|
-
const element = target.closest(
|
|
215
|
-
"[data-source-location], [data-visual-selector-id]"
|
|
216
|
-
);
|
|
217
|
-
if (!element) {
|
|
218
|
-
clearHoverOverlays();
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Prefer data-source-location, fallback to data-visual-selector-id
|
|
223
|
-
const htmlElement = element as HTMLElement;
|
|
224
|
-
const selectorId =
|
|
225
|
-
htmlElement.dataset.sourceLocation ||
|
|
226
|
-
htmlElement.dataset.visualSelectorId;
|
|
227
|
-
|
|
228
|
-
// Skip if this element is already selected
|
|
229
|
-
if (selectedElementId === selectorId) {
|
|
230
|
-
clearHoverOverlays();
|
|
231
|
-
return;
|
|
201
|
+
lastHoveredSelectorId = null;
|
|
232
202
|
}
|
|
203
|
+
};
|
|
233
204
|
|
|
234
|
-
|
|
235
|
-
const elements = findElementsById(selectorId
|
|
236
|
-
|
|
237
|
-
// Clear previous hover overlays
|
|
205
|
+
const applyHoverOverlays = (selectorId: string) => {
|
|
206
|
+
const elements = findElementsById(selectorId);
|
|
238
207
|
clearHoverOverlays();
|
|
239
208
|
|
|
240
|
-
// Create overlays for all matching elements
|
|
241
209
|
elements.forEach((el) => {
|
|
242
210
|
const overlay = createOverlay(false);
|
|
243
211
|
document.body.appendChild(overlay);
|
|
@@ -246,12 +214,34 @@ export function setupVisualEditAgent() {
|
|
|
246
214
|
});
|
|
247
215
|
|
|
248
216
|
currentHighlightedElements = elements;
|
|
217
|
+
lastHoveredSelectorId = selectorId;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const handleMouseMove = (e: MouseEvent) => {
|
|
221
|
+
if (!isVisualEditMode || isPopoverDragging || inlineEdit.isEditing()) return;
|
|
222
|
+
|
|
223
|
+
if (pendingMouseMoveRaf !== null) return;
|
|
224
|
+
pendingMouseMoveRaf = requestAnimationFrame(() => {
|
|
225
|
+
pendingMouseMoveRaf = null;
|
|
226
|
+
|
|
227
|
+
if (isDropdownOpen) { clearHoverState(); return; }
|
|
228
|
+
|
|
229
|
+
const selectorId = resolveHoverTarget(e.clientX, e.clientY, selectedElementId);
|
|
230
|
+
if (!selectorId) { clearHoverState(); return; }
|
|
231
|
+
if (lastHoveredSelectorId === selectorId) return;
|
|
232
|
+
|
|
233
|
+
applyHoverOverlays(selectorId);
|
|
234
|
+
});
|
|
249
235
|
};
|
|
250
236
|
|
|
251
|
-
//
|
|
252
|
-
const
|
|
253
|
-
if (
|
|
237
|
+
// Clear hover overlays when mouse leaves the viewport
|
|
238
|
+
const handleMouseLeave = () => {
|
|
239
|
+
if (pendingMouseMoveRaf !== null) {
|
|
240
|
+
cancelAnimationFrame(pendingMouseMoveRaf);
|
|
241
|
+
pendingMouseMoveRaf = null;
|
|
242
|
+
}
|
|
254
243
|
clearHoverOverlays();
|
|
244
|
+
lastHoveredSelectorId = null;
|
|
255
245
|
};
|
|
256
246
|
|
|
257
247
|
// Handle element click
|
|
@@ -288,20 +278,12 @@ export function setupVisualEditAgent() {
|
|
|
288
278
|
return;
|
|
289
279
|
}
|
|
290
280
|
|
|
291
|
-
// Prevent clicking on SVG path elements
|
|
292
|
-
if (target.tagName.toLowerCase() === "path") {
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
281
|
// Prevent default behavior immediately when in visual edit mode
|
|
297
282
|
e.preventDefault();
|
|
298
283
|
e.stopPropagation();
|
|
299
284
|
e.stopImmediatePropagation();
|
|
300
285
|
|
|
301
|
-
|
|
302
|
-
const element = target.closest(
|
|
303
|
-
"[data-source-location], [data-visual-selector-id]"
|
|
304
|
-
);
|
|
286
|
+
const element = findInstrumentedElement(e.clientX, e.clientY);
|
|
305
287
|
if (!element) {
|
|
306
288
|
return;
|
|
307
289
|
}
|
|
@@ -435,21 +417,28 @@ export function setupVisualEditAgent() {
|
|
|
435
417
|
isVisualEditMode = isEnabled;
|
|
436
418
|
|
|
437
419
|
if (!isEnabled) {
|
|
420
|
+
resumeAnimations();
|
|
438
421
|
inlineEdit.stopEditing();
|
|
439
422
|
clearSelection();
|
|
440
423
|
layerController.cleanup();
|
|
441
424
|
clearHoverOverlays();
|
|
442
425
|
|
|
443
426
|
currentHighlightedElements = [];
|
|
427
|
+
lastHoveredSelectorId = null;
|
|
428
|
+
if (pendingMouseMoveRaf !== null) {
|
|
429
|
+
cancelAnimationFrame(pendingMouseMoveRaf);
|
|
430
|
+
pendingMouseMoveRaf = null;
|
|
431
|
+
}
|
|
444
432
|
document.body.style.cursor = "default";
|
|
445
433
|
|
|
446
|
-
document.removeEventListener("
|
|
447
|
-
document.removeEventListener("
|
|
434
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
435
|
+
document.removeEventListener("mouseleave", handleMouseLeave);
|
|
448
436
|
document.removeEventListener("click", handleElementClick, true);
|
|
449
437
|
} else {
|
|
450
438
|
document.body.style.cursor = "crosshair";
|
|
451
|
-
|
|
452
|
-
document.addEventListener("
|
|
439
|
+
stopAnimations();
|
|
440
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
441
|
+
document.addEventListener("mouseleave", handleMouseLeave);
|
|
453
442
|
document.addEventListener("click", handleElementClick, true);
|
|
454
443
|
}
|
|
455
444
|
};
|
|
@@ -620,6 +609,19 @@ export function setupVisualEditAgent() {
|
|
|
620
609
|
}
|
|
621
610
|
break;
|
|
622
611
|
|
|
612
|
+
case "update-theme-variables":
|
|
613
|
+
if (message.data?.variables) {
|
|
614
|
+
const target = message.data.mode === 'dark'
|
|
615
|
+
? document.querySelector('.dark') as HTMLElement
|
|
616
|
+
: document.documentElement;
|
|
617
|
+
if (target) {
|
|
618
|
+
for (const [name, value] of Object.entries(message.data.variables)) {
|
|
619
|
+
target.style.setProperty(name, value as string);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
break;
|
|
624
|
+
|
|
623
625
|
case "toggle-inline-edit-mode":
|
|
624
626
|
if (message.data) {
|
|
625
627
|
inlineEdit.handleToggleMessage(message.data);
|