@base44/vite-plugin 1.0.35 → 1.0.36
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/controller.js +2 -2
- package/dist/injections/layer-dropdown/controller.js.map +1 -1
- package/dist/injections/layer-dropdown/utils.js +3 -3
- package/dist/injections/layer-dropdown/utils.js.map +1 -1
- package/dist/injections/utils.d.ts +2 -0
- package/dist/injections/utils.d.ts.map +1 -1
- package/dist/injections/utils.js +15 -2
- 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 +18 -8
- package/dist/injections/visual-edit-agent.js.map +1 -1
- package/dist/statics/index.mjs +7 -7
- package/dist/statics/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/injections/layer-dropdown/controller.ts +2 -2
- package/src/injections/layer-dropdown/utils.ts +3 -3
- package/src/injections/utils.ts +16 -2
- package/src/injections/visual-edit-agent.ts +19 -8
- package/src/visual-edit-plugin.md +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Controller that encapsulates layer-dropdown integration logic */
|
|
2
2
|
|
|
3
|
-
import { getElementSelectorId } from "../utils.js";
|
|
3
|
+
import { readVisualEditTagName, getElementSelectorId } from "../utils.js";
|
|
4
4
|
import { buildLayerChain } from "./utils.js";
|
|
5
5
|
import {
|
|
6
6
|
enhanceLabelWithChevron,
|
|
@@ -62,7 +62,7 @@ export function createLayerController(config: LayerControllerConfig): LayerContr
|
|
|
62
62
|
} else {
|
|
63
63
|
dropdownSourceLayer = {
|
|
64
64
|
element,
|
|
65
|
-
tagName: element.
|
|
65
|
+
tagName: readVisualEditTagName(element).toLowerCase(),
|
|
66
66
|
selectorId: currentId,
|
|
67
67
|
};
|
|
68
68
|
config.onDeselect();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** DOM utilities for the layer-dropdown module */
|
|
2
2
|
|
|
3
|
-
import { isInstrumentedElement, getElementSelectorId } from "../utils.js";
|
|
3
|
+
import { readVisualEditTagName, isInstrumentedElement, getElementSelectorId } from "../utils.js";
|
|
4
4
|
import { MAX_PARENT_DEPTH, MAX_CHILD_DEPTH } from "./consts.js";
|
|
5
5
|
|
|
6
6
|
import type { LayerInfo } from "./types.js";
|
|
@@ -23,7 +23,7 @@ export function getLayerDisplayName(layer: LayerInfo): string {
|
|
|
23
23
|
function toLayerInfo(element: Element, depth?: number): LayerInfo {
|
|
24
24
|
const info: LayerInfo = {
|
|
25
25
|
element,
|
|
26
|
-
tagName: element.
|
|
26
|
+
tagName: readVisualEditTagName(element).toLowerCase(),
|
|
27
27
|
selectorId: getElementSelectorId(element),
|
|
28
28
|
};
|
|
29
29
|
if (depth !== undefined) info.depth = depth;
|
|
@@ -50,7 +50,7 @@ export function getInstrumentedDescendants(
|
|
|
50
50
|
if (isInstrumentedElement(child)) {
|
|
51
51
|
const info: LayerInfo = {
|
|
52
52
|
element: child,
|
|
53
|
-
tagName: child.
|
|
53
|
+
tagName: readVisualEditTagName(child).toLowerCase(),
|
|
54
54
|
selectorId: getElementSelectorId(child),
|
|
55
55
|
};
|
|
56
56
|
if (startDepth !== undefined) {
|
package/src/injections/utils.ts
CHANGED
|
@@ -53,6 +53,14 @@ export function getElementSelectorId(element: Element): string | null {
|
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
export function isImageComponent(element: Element): boolean {
|
|
57
|
+
return element.hasAttribute("data-base44-image");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function readVisualEditTagName(element: Element): string {
|
|
61
|
+
return isImageComponent(element) ? "IMG" : element.tagName;
|
|
62
|
+
}
|
|
63
|
+
|
|
56
64
|
export const ALLOWED_ATTRIBUTES: string[] = ["src"];
|
|
57
65
|
|
|
58
66
|
export const PLUGIN_ELEMENT_ATTR = "data-vite-plugin-element";
|
|
@@ -93,7 +101,11 @@ export function updateElementAttribute(elements: Element[], attribute: string, v
|
|
|
93
101
|
targetArrIndex === null ||
|
|
94
102
|
(element as HTMLElement).dataset.arrIndex === targetArrIndex
|
|
95
103
|
) {
|
|
96
|
-
|
|
104
|
+
if (attribute === "src" && isImageComponent(element)) {
|
|
105
|
+
element.dispatchEvent(new CustomEvent("base44:image-replace", { detail: { src: value } }));
|
|
106
|
+
} else {
|
|
107
|
+
element.setAttribute(attribute, value);
|
|
108
|
+
}
|
|
97
109
|
}
|
|
98
110
|
});
|
|
99
111
|
}
|
|
@@ -111,7 +123,9 @@ export function readElementClasses(element: Element): string {
|
|
|
111
123
|
export function collectAllowedAttributes(element: Element, allowedAttributes: string[]): Record<string, string> {
|
|
112
124
|
const attributes: Record<string, string> = {};
|
|
113
125
|
for (const attr of allowedAttributes) {
|
|
114
|
-
const val = element
|
|
126
|
+
const val = attr === "src" && isImageComponent(element)
|
|
127
|
+
? element.getAttribute("data-base44-image-src")
|
|
128
|
+
: element.getAttribute(attr);
|
|
115
129
|
if (val !== null) {
|
|
116
130
|
attributes[attr] = val;
|
|
117
131
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, readElementClasses, ALLOWED_ATTRIBUTES, getElementSelectorId, stopAnimations, resumeAnimations, findInstrumentedElement, resolveHoverTarget, positionLabel, injectFontFaceCss } from "./utils.js";
|
|
1
|
+
import { readVisualEditTagName, findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, readElementClasses, ALLOWED_ATTRIBUTES, getElementSelectorId, stopAnimations, resumeAnimations, findInstrumentedElement, resolveHoverTarget, positionLabel, injectFontFaceCss } 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";
|
|
@@ -65,7 +65,7 @@ export function setupVisualEditAgent() {
|
|
|
65
65
|
|
|
66
66
|
if (!label) {
|
|
67
67
|
label = document.createElement("div");
|
|
68
|
-
label.textContent = element.
|
|
68
|
+
label.textContent = readVisualEditTagName(element).toLowerCase();
|
|
69
69
|
label.style.position = "absolute";
|
|
70
70
|
label.style.left = "-2px";
|
|
71
71
|
label.style.padding = "2px 8px";
|
|
@@ -137,7 +137,7 @@ export function setupVisualEditAgent() {
|
|
|
137
137
|
const notifyElementSelected = (element: Element) => {
|
|
138
138
|
const htmlElement = element as HTMLElement;
|
|
139
139
|
const rect = element.getBoundingClientRect();
|
|
140
|
-
const isTextElement = TEXT_TAGS.includes(element.
|
|
140
|
+
const isTextElement = TEXT_TAGS.includes(readVisualEditTagName(element).toLowerCase());
|
|
141
141
|
|
|
142
142
|
const arrEl = htmlElement.closest("[data-arr-variable-name]") as HTMLElement | null;
|
|
143
143
|
const staticArrayName = arrEl?.dataset?.arrVariableName || null;
|
|
@@ -151,7 +151,7 @@ export function setupVisualEditAgent() {
|
|
|
151
151
|
|
|
152
152
|
window.parent.postMessage({
|
|
153
153
|
type: "element-selected",
|
|
154
|
-
tagName: element
|
|
154
|
+
tagName: readVisualEditTagName(element),
|
|
155
155
|
classes: readElementClasses(element),
|
|
156
156
|
visualSelectorId: getElementSelectorId(element),
|
|
157
157
|
content: isTextElement ? htmlElement.innerText : undefined,
|
|
@@ -181,7 +181,7 @@ export function setupVisualEditAgent() {
|
|
|
181
181
|
};
|
|
182
182
|
|
|
183
183
|
// Select an element: create overlays, update state, notify parent
|
|
184
|
-
const selectElement = (element: Element): HTMLDivElement | undefined => {
|
|
184
|
+
const selectElement = (element: Element, notifyParent = true): HTMLDivElement | undefined => {
|
|
185
185
|
const visualSelectorId = getElementSelectorId(element);
|
|
186
186
|
|
|
187
187
|
clearSelectedOverlays();
|
|
@@ -197,7 +197,7 @@ export function setupVisualEditAgent() {
|
|
|
197
197
|
selectedElementId = visualSelectorId || null;
|
|
198
198
|
selectedElement = element;
|
|
199
199
|
clearHoverOverlays();
|
|
200
|
-
notifyElementSelected(element);
|
|
200
|
+
if (notifyParent) notifyElementSelected(element);
|
|
201
201
|
|
|
202
202
|
return selectedOverlays[0];
|
|
203
203
|
};
|
|
@@ -381,9 +381,20 @@ export function setupVisualEditAgent() {
|
|
|
381
381
|
// Reposition overlays after attribute change (e.g. image src swap can affect layout)
|
|
382
382
|
setTimeout(() => {
|
|
383
383
|
if (selectedElementId === visualSelectorId) {
|
|
384
|
+
const currentElements = findElementsById(visualSelectorId);
|
|
385
|
+
if (selectedElement && !selectedElement.isConnected) {
|
|
386
|
+
const selectedIndex = (selectedElement as HTMLElement).dataset.arrIndex;
|
|
387
|
+
const replacement = currentElements.find(
|
|
388
|
+
(element) => (element as HTMLElement).dataset.arrIndex === selectedIndex
|
|
389
|
+
);
|
|
390
|
+
if (replacement) {
|
|
391
|
+
const overlay = selectElement(replacement, false);
|
|
392
|
+
layerController.attachToOverlay(overlay, replacement);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
384
395
|
selectedOverlays.forEach((overlay, index) => {
|
|
385
|
-
if (index <
|
|
386
|
-
positionOverlay(overlay,
|
|
396
|
+
if (index < currentElements.length) {
|
|
397
|
+
positionOverlay(overlay, currentElements[index]!);
|
|
387
398
|
}
|
|
388
399
|
});
|
|
389
400
|
}
|
|
@@ -356,3 +356,18 @@ The `transformIndexHtml` hook injects the Tailwind CSS CDN, enabling visual edit
|
|
|
356
356
|
| `src/injections/sandbox-mount-observer.ts` | Detects when instrumented elements mount in DOM |
|
|
357
357
|
| `src/injections/utils.ts` | `findElementsById()`, `updateElementClasses()` utilities |
|
|
358
358
|
| `tests/visual-edit-agent.test.ts` | Unit tests for element finding and class updates |
|
|
359
|
+
|
|
360
|
+
### Seeded Image components
|
|
361
|
+
|
|
362
|
+
A `data-base44-image` wrapper is one logical image edit target. Its classes and
|
|
363
|
+
source location refer to the app's `<Image>` call site; report its tag as `IMG`
|
|
364
|
+
for the image toolbar and layer labels. Read `src` from `data-base44-image-src`,
|
|
365
|
+
which preserves the original prop rather than the inner image's transformed CDN
|
|
366
|
+
URL. The template keeps all instrumentation on the wrapper and suppresses source
|
|
367
|
+
locations on the placeholder and main image.
|
|
368
|
+
|
|
369
|
+
For `src` edits, dispatch `base44:image-replace` with `detail: { src }` on the
|
|
370
|
+
wrapper, retaining the selected-array-index filter. The template updates React
|
|
371
|
+
state so the replacement survives responsive resizes. Native images continue to
|
|
372
|
+
use direct attribute updates. Publish this support before seeding a template
|
|
373
|
+
that uses the wrapper contract.
|