@base44/vite-plugin 0.2.24 → 0.2.26
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/injections/layer-dropdown/consts.d.ts +19 -0
- package/dist/injections/layer-dropdown/consts.d.ts.map +1 -0
- package/dist/injections/layer-dropdown/consts.js +40 -0
- package/dist/injections/layer-dropdown/consts.js.map +1 -0
- package/dist/injections/layer-dropdown/controller.d.ts +4 -0
- package/dist/injections/layer-dropdown/controller.d.ts.map +1 -0
- package/dist/injections/layer-dropdown/controller.js +88 -0
- package/dist/injections/layer-dropdown/controller.js.map +1 -0
- package/dist/injections/layer-dropdown/dropdown-ui.d.ts +13 -0
- package/dist/injections/layer-dropdown/dropdown-ui.d.ts.map +1 -0
- package/dist/injections/layer-dropdown/dropdown-ui.js +176 -0
- package/dist/injections/layer-dropdown/dropdown-ui.js.map +1 -0
- package/dist/injections/layer-dropdown/types.d.ts +26 -0
- package/dist/injections/layer-dropdown/types.d.ts.map +1 -0
- package/dist/injections/layer-dropdown/types.js +3 -0
- package/dist/injections/layer-dropdown/types.js.map +1 -0
- package/dist/injections/layer-dropdown/utils.d.ts +25 -0
- package/dist/injections/layer-dropdown/utils.d.ts.map +1 -0
- package/dist/injections/layer-dropdown/utils.js +143 -0
- package/dist/injections/layer-dropdown/utils.js.map +1 -0
- package/dist/injections/utils.d.ts +9 -0
- package/dist/injections/utils.d.ts.map +1 -1
- package/dist/injections/utils.js +33 -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 +115 -69
- package/dist/injections/visual-edit-agent.js.map +1 -1
- package/dist/statics/index.mjs +1 -1
- package/dist/statics/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/injections/layer-dropdown/LAYERS.md +258 -0
- package/src/injections/layer-dropdown/consts.ts +49 -0
- package/src/injections/layer-dropdown/controller.ts +109 -0
- package/src/injections/layer-dropdown/dropdown-ui.ts +230 -0
- package/src/injections/layer-dropdown/types.ts +30 -0
- package/src/injections/layer-dropdown/utils.ts +175 -0
- package/src/injections/utils.ts +44 -1
- package/src/injections/visual-edit-agent.ts +141 -80
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { findElementsById, updateElementClasses } from "./utils.js";
|
|
1
|
+
import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, ALLOWED_ATTRIBUTES, getElementSelectorId } from "./utils.js";
|
|
2
|
+
import { createLayerController } from "./layer-dropdown/controller.js";
|
|
3
|
+
import { LAYER_DROPDOWN_ATTR } from "./layer-dropdown/consts.js";
|
|
2
4
|
|
|
3
5
|
export function setupVisualEditAgent() {
|
|
4
6
|
// State variables (replacing React useState/useRef)
|
|
@@ -78,6 +80,76 @@ export function setupVisualEditAgent() {
|
|
|
78
80
|
currentHighlightedElements = [];
|
|
79
81
|
};
|
|
80
82
|
|
|
83
|
+
const clearSelectedOverlays = () => {
|
|
84
|
+
selectedOverlays.forEach((overlay) => {
|
|
85
|
+
if (overlay && overlay.parentNode) {
|
|
86
|
+
overlay.remove();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
selectedOverlays = [];
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const TEXT_TAGS = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'a', 'label'];
|
|
93
|
+
|
|
94
|
+
const notifyElementSelected = (element: Element) => {
|
|
95
|
+
const htmlElement = element as HTMLElement;
|
|
96
|
+
const rect = element.getBoundingClientRect();
|
|
97
|
+
const svgElement = element as SVGElement;
|
|
98
|
+
const isTextElement = TEXT_TAGS.includes(element.tagName?.toLowerCase());
|
|
99
|
+
window.parent.postMessage({
|
|
100
|
+
type: "element-selected",
|
|
101
|
+
tagName: element.tagName,
|
|
102
|
+
classes:
|
|
103
|
+
(svgElement.className as unknown as SVGAnimatedString)?.baseVal ||
|
|
104
|
+
element.className ||
|
|
105
|
+
"",
|
|
106
|
+
visualSelectorId: getElementSelectorId(element),
|
|
107
|
+
content: isTextElement ? htmlElement.innerText : undefined,
|
|
108
|
+
dataSourceLocation: htmlElement.dataset.sourceLocation,
|
|
109
|
+
isDynamicContent: htmlElement.dataset.dynamicContent === "true",
|
|
110
|
+
linenumber: htmlElement.dataset.linenumber,
|
|
111
|
+
filename: htmlElement.dataset.filename,
|
|
112
|
+
position: {
|
|
113
|
+
top: rect.top,
|
|
114
|
+
left: rect.left,
|
|
115
|
+
right: rect.right,
|
|
116
|
+
bottom: rect.bottom,
|
|
117
|
+
width: rect.width,
|
|
118
|
+
height: rect.height,
|
|
119
|
+
centerX: rect.left + rect.width / 2,
|
|
120
|
+
centerY: rect.top + rect.height / 2,
|
|
121
|
+
},
|
|
122
|
+
attributes: collectAllowedAttributes(element, ALLOWED_ATTRIBUTES),
|
|
123
|
+
isTextElement,
|
|
124
|
+
}, "*");
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Select an element: create overlays, update state, notify parent
|
|
128
|
+
const selectElement = (element: Element): HTMLDivElement | undefined => {
|
|
129
|
+
const visualSelectorId = getElementSelectorId(element);
|
|
130
|
+
|
|
131
|
+
clearSelectedOverlays();
|
|
132
|
+
|
|
133
|
+
const elements = findElementsById(visualSelectorId || null);
|
|
134
|
+
elements.forEach((el) => {
|
|
135
|
+
const overlay = createOverlay(true);
|
|
136
|
+
document.body.appendChild(overlay);
|
|
137
|
+
selectedOverlays.push(overlay);
|
|
138
|
+
positionOverlay(overlay, el, true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
selectedElementId = visualSelectorId || null;
|
|
142
|
+
clearHoverOverlays();
|
|
143
|
+
notifyElementSelected(element);
|
|
144
|
+
|
|
145
|
+
return selectedOverlays[0];
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const notifyDeselection = (): void => {
|
|
149
|
+
selectedElementId = null;
|
|
150
|
+
window.parent.postMessage({ type: "unselect-element" }, "*");
|
|
151
|
+
};
|
|
152
|
+
|
|
81
153
|
// Handle mouse over event
|
|
82
154
|
const handleMouseOver = (e: MouseEvent) => {
|
|
83
155
|
if (!isVisualEditMode || isPopoverDragging) return;
|
|
@@ -146,6 +218,9 @@ export function setupVisualEditAgent() {
|
|
|
146
218
|
|
|
147
219
|
const target = e.target as Element;
|
|
148
220
|
|
|
221
|
+
// Let layer dropdown clicks pass through without interference
|
|
222
|
+
if (target.closest(`[${LAYER_DROPDOWN_ATTR}]`)) return;
|
|
223
|
+
|
|
149
224
|
// Close dropdowns when clicking anywhere in iframe if a dropdown is open
|
|
150
225
|
if (isDropdownOpen) {
|
|
151
226
|
e.preventDefault();
|
|
@@ -174,79 +249,13 @@ export function setupVisualEditAgent() {
|
|
|
174
249
|
return;
|
|
175
250
|
}
|
|
176
251
|
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
htmlElement.dataset.sourceLocation ||
|
|
180
|
-
htmlElement.dataset.visualSelectorId;
|
|
181
|
-
|
|
182
|
-
// Clear any existing selected overlays
|
|
183
|
-
selectedOverlays.forEach((overlay) => {
|
|
184
|
-
if (overlay && overlay.parentNode) {
|
|
185
|
-
overlay.remove();
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
selectedOverlays = [];
|
|
189
|
-
|
|
190
|
-
// Find all elements with the same ID
|
|
191
|
-
const elements = findElementsById(visualSelectorId || null);
|
|
192
|
-
|
|
193
|
-
// Create selected overlays for all matching elements
|
|
194
|
-
elements.forEach((el) => {
|
|
195
|
-
const overlay = createOverlay(true);
|
|
196
|
-
document.body.appendChild(overlay);
|
|
197
|
-
selectedOverlays.push(overlay);
|
|
198
|
-
positionOverlay(overlay, el, true);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
selectedElementId = visualSelectorId || null;
|
|
202
|
-
|
|
203
|
-
// Clear hover overlays
|
|
204
|
-
clearHoverOverlays();
|
|
205
|
-
|
|
206
|
-
// Calculate element position for popover positioning
|
|
207
|
-
const rect = element.getBoundingClientRect();
|
|
208
|
-
const elementPosition = {
|
|
209
|
-
top: rect.top,
|
|
210
|
-
left: rect.left,
|
|
211
|
-
right: rect.right,
|
|
212
|
-
bottom: rect.bottom,
|
|
213
|
-
width: rect.width,
|
|
214
|
-
height: rect.height,
|
|
215
|
-
centerX: rect.left + rect.width / 2,
|
|
216
|
-
centerY: rect.top + rect.height / 2,
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
const isTextElement = ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'a', 'label'].includes(element.tagName?.toLowerCase())
|
|
220
|
-
|
|
221
|
-
// Send message to parent window with element info including position
|
|
222
|
-
const svgElement = element as SVGElement;
|
|
223
|
-
const elementData = {
|
|
224
|
-
type: "element-selected",
|
|
225
|
-
tagName: element.tagName,
|
|
226
|
-
classes:
|
|
227
|
-
(svgElement.className as unknown as SVGAnimatedString)?.baseVal ||
|
|
228
|
-
element.className ||
|
|
229
|
-
"",
|
|
230
|
-
visualSelectorId: visualSelectorId,
|
|
231
|
-
content: isTextElement ? (element as HTMLElement).innerText : undefined,
|
|
232
|
-
dataSourceLocation: htmlElement.dataset.sourceLocation,
|
|
233
|
-
isDynamicContent: htmlElement.dataset.dynamicContent === "true",
|
|
234
|
-
linenumber: htmlElement.dataset.linenumber,
|
|
235
|
-
filename: htmlElement.dataset.filename,
|
|
236
|
-
position: elementPosition,
|
|
237
|
-
isTextElement: isTextElement,
|
|
238
|
-
};
|
|
239
|
-
window.parent.postMessage(elementData, "*");
|
|
252
|
+
const selectedOverlay = selectElement(element);
|
|
253
|
+
layerController.attachToOverlay(selectedOverlay, element);
|
|
240
254
|
};
|
|
241
255
|
|
|
242
|
-
//
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
if (overlay && overlay.parentNode) {
|
|
246
|
-
overlay.remove();
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
selectedOverlays = [];
|
|
256
|
+
// Clear the current selection
|
|
257
|
+
const clearSelection = () => {
|
|
258
|
+
clearSelectedOverlays();
|
|
250
259
|
selectedElementId = null;
|
|
251
260
|
};
|
|
252
261
|
|
|
@@ -282,6 +291,29 @@ export function setupVisualEditAgent() {
|
|
|
282
291
|
}, 50);
|
|
283
292
|
};
|
|
284
293
|
|
|
294
|
+
// Update element attribute by visual selector ID
|
|
295
|
+
const updateElementAttributeAndReposition = (
|
|
296
|
+
visualSelectorId: string,
|
|
297
|
+
attribute: string,
|
|
298
|
+
value: string
|
|
299
|
+
) => {
|
|
300
|
+
const elements = findElementsById(visualSelectorId);
|
|
301
|
+
if (elements.length === 0) return;
|
|
302
|
+
|
|
303
|
+
updateElementAttribute(elements, attribute, value);
|
|
304
|
+
|
|
305
|
+
// Reposition overlays after attribute change (e.g. image src swap can affect layout)
|
|
306
|
+
setTimeout(() => {
|
|
307
|
+
if (selectedElementId === visualSelectorId) {
|
|
308
|
+
selectedOverlays.forEach((overlay, index) => {
|
|
309
|
+
if (index < elements.length) {
|
|
310
|
+
positionOverlay(overlay, elements[index]!);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}, 50);
|
|
315
|
+
};
|
|
316
|
+
|
|
285
317
|
// Update element content by visual selector ID
|
|
286
318
|
const updateElementContent = (visualSelectorId: string, content: string) => {
|
|
287
319
|
const elements = findElementsById(visualSelectorId);
|
|
@@ -305,19 +337,28 @@ export function setupVisualEditAgent() {
|
|
|
305
337
|
}, 50);
|
|
306
338
|
};
|
|
307
339
|
|
|
340
|
+
// --- Layer dropdown controller ---
|
|
341
|
+
const layerController = createLayerController({
|
|
342
|
+
createPreviewOverlay: (element: Element) => {
|
|
343
|
+
const overlay = createOverlay(false);
|
|
344
|
+
overlay.style.zIndex = "9998";
|
|
345
|
+
document.body.appendChild(overlay);
|
|
346
|
+
positionOverlay(overlay, element);
|
|
347
|
+
return overlay;
|
|
348
|
+
},
|
|
349
|
+
getSelectedElementId: () => selectedElementId,
|
|
350
|
+
selectElement,
|
|
351
|
+
onDeselect: notifyDeselection,
|
|
352
|
+
});
|
|
353
|
+
|
|
308
354
|
// Toggle visual edit mode
|
|
309
355
|
const toggleVisualEditMode = (isEnabled: boolean) => {
|
|
310
356
|
isVisualEditMode = isEnabled;
|
|
311
357
|
|
|
312
358
|
if (!isEnabled) {
|
|
359
|
+
layerController.cleanup();
|
|
313
360
|
clearHoverOverlays();
|
|
314
|
-
|
|
315
|
-
selectedOverlays.forEach((overlay) => {
|
|
316
|
-
if (overlay && overlay.parentNode) {
|
|
317
|
-
overlay.remove();
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
selectedOverlays = [];
|
|
361
|
+
clearSelectedOverlays();
|
|
321
362
|
|
|
322
363
|
currentHighlightedElements = [];
|
|
323
364
|
selectedElementId = null;
|
|
@@ -397,8 +438,28 @@ export function setupVisualEditAgent() {
|
|
|
397
438
|
}
|
|
398
439
|
break;
|
|
399
440
|
|
|
441
|
+
case "update-attribute":
|
|
442
|
+
if (
|
|
443
|
+
message.data &&
|
|
444
|
+
message.data.visualSelectorId &&
|
|
445
|
+
message.data.attribute !== undefined &&
|
|
446
|
+
message.data.value !== undefined
|
|
447
|
+
) {
|
|
448
|
+
updateElementAttributeAndReposition(
|
|
449
|
+
message.data.visualSelectorId,
|
|
450
|
+
message.data.attribute,
|
|
451
|
+
message.data.value
|
|
452
|
+
);
|
|
453
|
+
} else {
|
|
454
|
+
console.warn(
|
|
455
|
+
"[VisualEditAgent] Invalid update-attribute message:",
|
|
456
|
+
message
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
460
|
+
|
|
400
461
|
case "unselect-element":
|
|
401
|
-
|
|
462
|
+
clearSelection();
|
|
402
463
|
break;
|
|
403
464
|
|
|
404
465
|
case "refresh-page":
|