@base44/vite-plugin 0.2.26 → 0.2.27
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 +3 -0
- package/dist/capabilities/inline-edit/controller.d.ts.map +1 -0
- package/dist/capabilities/inline-edit/controller.js +194 -0
- package/dist/capabilities/inline-edit/controller.js.map +1 -0
- package/dist/capabilities/inline-edit/dom-utils.d.ts +6 -0
- package/dist/capabilities/inline-edit/dom-utils.d.ts.map +1 -0
- package/dist/capabilities/inline-edit/dom-utils.js +49 -0
- package/dist/capabilities/inline-edit/dom-utils.js.map +1 -0
- package/dist/capabilities/inline-edit/index.d.ts +3 -0
- package/dist/capabilities/inline-edit/index.d.ts.map +1 -0
- package/dist/capabilities/inline-edit/index.js +2 -0
- package/dist/capabilities/inline-edit/index.js.map +1 -0
- package/dist/capabilities/inline-edit/types.d.ts +25 -0
- package/dist/capabilities/inline-edit/types.d.ts.map +1 -0
- package/dist/capabilities/inline-edit/types.js +2 -0
- package/dist/capabilities/inline-edit/types.js.map +1 -0
- package/dist/injections/visual-edit-agent.d.ts.map +1 -1
- package/dist/injections/visual-edit-agent.js +72 -12
- package/dist/injections/visual-edit-agent.js.map +1 -1
- package/dist/statics/index.mjs +5 -1
- package/dist/statics/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/capabilities/inline-edit/controller.ts +245 -0
- package/src/capabilities/inline-edit/dom-utils.ts +48 -0
- package/src/capabilities/inline-edit/index.ts +2 -0
- package/src/capabilities/inline-edit/types.ts +30 -0
- package/src/injections/visual-edit-agent.ts +85 -12
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import type { InlineEditHost, InlineEditController } from "./types.js";
|
|
2
|
+
import {
|
|
3
|
+
injectFocusOutlineCSS,
|
|
4
|
+
removeFocusOutlineCSS,
|
|
5
|
+
selectText,
|
|
6
|
+
shouldEnterInlineEditingMode,
|
|
7
|
+
} from "./dom-utils.js";
|
|
8
|
+
|
|
9
|
+
const DEBOUNCE_MS = 500;
|
|
10
|
+
|
|
11
|
+
export function createInlineEditController(
|
|
12
|
+
host: InlineEditHost
|
|
13
|
+
): InlineEditController {
|
|
14
|
+
let currentEditingElement: HTMLElement | null = null;
|
|
15
|
+
let debouncedSendTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
16
|
+
let enabled = false;
|
|
17
|
+
const listenerAbortControllers = new WeakMap<HTMLElement, AbortController>();
|
|
18
|
+
|
|
19
|
+
// --- Private helpers ---
|
|
20
|
+
|
|
21
|
+
const repositionOverlays = () => {
|
|
22
|
+
const selectedId = host.getSelectedElementId();
|
|
23
|
+
if (!selectedId) return;
|
|
24
|
+
const elements = host.findElementsById(selectedId);
|
|
25
|
+
const overlays = host.getSelectedOverlays();
|
|
26
|
+
overlays.forEach((overlay, i) => {
|
|
27
|
+
if (i < elements.length && elements[i]) {
|
|
28
|
+
host.positionOverlay(overlay, elements[i]);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const reportEdit = (element: HTMLElement) => {
|
|
34
|
+
const originalContent = element.dataset.originalTextContent;
|
|
35
|
+
const newContent = element.textContent;
|
|
36
|
+
|
|
37
|
+
const svgElement = element as unknown as SVGElement;
|
|
38
|
+
const rect = element.getBoundingClientRect();
|
|
39
|
+
|
|
40
|
+
window.parent.postMessage(
|
|
41
|
+
{
|
|
42
|
+
type: "inline-edit",
|
|
43
|
+
elementInfo: {
|
|
44
|
+
tagName: element.tagName,
|
|
45
|
+
classes:
|
|
46
|
+
(svgElement.className as unknown as SVGAnimatedString)?.baseVal ||
|
|
47
|
+
element.className ||
|
|
48
|
+
"",
|
|
49
|
+
visualSelectorId: host.getSelectedElementId(),
|
|
50
|
+
content: newContent,
|
|
51
|
+
dataSourceLocation: element.dataset.sourceLocation,
|
|
52
|
+
isDynamicContent: element.dataset.dynamicContent === "true",
|
|
53
|
+
linenumber: element.dataset.linenumber,
|
|
54
|
+
filename: element.dataset.filename,
|
|
55
|
+
position: {
|
|
56
|
+
top: rect.top,
|
|
57
|
+
left: rect.left,
|
|
58
|
+
right: rect.right,
|
|
59
|
+
bottom: rect.bottom,
|
|
60
|
+
width: rect.width,
|
|
61
|
+
height: rect.height,
|
|
62
|
+
centerX: rect.left + rect.width / 2,
|
|
63
|
+
centerY: rect.top + rect.height / 2,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
originalContent,
|
|
67
|
+
newContent,
|
|
68
|
+
},
|
|
69
|
+
"*"
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
element.dataset.originalTextContent = newContent || "";
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const debouncedReport = (element: HTMLElement) => {
|
|
76
|
+
if (debouncedSendTimeout) clearTimeout(debouncedSendTimeout);
|
|
77
|
+
debouncedSendTimeout = setTimeout(() => reportEdit(element), DEBOUNCE_MS);
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const onTextInput = (element: HTMLElement) => {
|
|
81
|
+
repositionOverlays();
|
|
82
|
+
debouncedReport(element);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const handleInputEvent = function (this: HTMLElement) {
|
|
86
|
+
onTextInput(this);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const makeEditable = (element: HTMLElement) => {
|
|
90
|
+
injectFocusOutlineCSS();
|
|
91
|
+
|
|
92
|
+
element.dataset.originalTextContent = element.textContent || "";
|
|
93
|
+
element.dataset.originalCursor = element.style.cursor;
|
|
94
|
+
element.contentEditable = "true";
|
|
95
|
+
|
|
96
|
+
const abortController = new AbortController();
|
|
97
|
+
listenerAbortControllers.set(element, abortController);
|
|
98
|
+
element.addEventListener("input", handleInputEvent, {
|
|
99
|
+
signal: abortController.signal,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
element.style.cursor = "text";
|
|
103
|
+
selectText(element);
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
if (element.isConnected) {
|
|
106
|
+
element.focus();
|
|
107
|
+
}
|
|
108
|
+
}, 0);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const makeNonEditable = (element: HTMLElement) => {
|
|
112
|
+
const abortController = listenerAbortControllers.get(element);
|
|
113
|
+
if (abortController) {
|
|
114
|
+
abortController.abort();
|
|
115
|
+
listenerAbortControllers.delete(element);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!element.isConnected) return;
|
|
119
|
+
|
|
120
|
+
removeFocusOutlineCSS();
|
|
121
|
+
element.contentEditable = "false";
|
|
122
|
+
delete element.dataset.originalTextContent;
|
|
123
|
+
|
|
124
|
+
if (element.dataset.originalCursor !== undefined) {
|
|
125
|
+
element.style.cursor = element.dataset.originalCursor;
|
|
126
|
+
delete element.dataset.originalCursor;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// --- Public API ---
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
get enabled() {
|
|
134
|
+
return enabled;
|
|
135
|
+
},
|
|
136
|
+
set enabled(value: boolean) {
|
|
137
|
+
enabled = value;
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
isEditing() {
|
|
141
|
+
return currentEditingElement !== null;
|
|
142
|
+
},
|
|
143
|
+
|
|
144
|
+
getCurrentElement() {
|
|
145
|
+
return currentEditingElement;
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
canEdit(element: Element) {
|
|
149
|
+
return shouldEnterInlineEditingMode(element);
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
startEditing(element: HTMLElement) {
|
|
153
|
+
currentEditingElement = element;
|
|
154
|
+
|
|
155
|
+
host.getSelectedOverlays().forEach((o) => {
|
|
156
|
+
o.style.display = "none";
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
makeEditable(element);
|
|
160
|
+
|
|
161
|
+
window.parent.postMessage(
|
|
162
|
+
{
|
|
163
|
+
type: "content-editing-started",
|
|
164
|
+
visualSelectorId: host.getSelectedElementId(),
|
|
165
|
+
},
|
|
166
|
+
"*"
|
|
167
|
+
);
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
stopEditing() {
|
|
171
|
+
if (!currentEditingElement) return;
|
|
172
|
+
|
|
173
|
+
if (debouncedSendTimeout) {
|
|
174
|
+
clearTimeout(debouncedSendTimeout);
|
|
175
|
+
debouncedSendTimeout = null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const element = currentEditingElement;
|
|
179
|
+
makeNonEditable(element);
|
|
180
|
+
|
|
181
|
+
host.getSelectedOverlays().forEach((o) => {
|
|
182
|
+
o.style.display = "";
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
repositionOverlays();
|
|
186
|
+
|
|
187
|
+
window.parent.postMessage(
|
|
188
|
+
{
|
|
189
|
+
type: "content-editing-ended",
|
|
190
|
+
visualSelectorId: host.getSelectedElementId(),
|
|
191
|
+
},
|
|
192
|
+
"*"
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
currentEditingElement = null;
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
markElementsSelected(elements: Element[]) {
|
|
199
|
+
elements.forEach((el) => {
|
|
200
|
+
if (el instanceof HTMLElement) {
|
|
201
|
+
el.dataset.selected = "true";
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
clearSelectedMarks(elementId: string | null) {
|
|
207
|
+
if (!elementId) return;
|
|
208
|
+
host.findElementsById(elementId).forEach((el) => {
|
|
209
|
+
if (el instanceof HTMLElement) {
|
|
210
|
+
delete el.dataset.selected;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
handleToggleMessage(data: { dataSourceLocation: string; inlineEditingMode: boolean }) {
|
|
216
|
+
if (!enabled) return;
|
|
217
|
+
|
|
218
|
+
const elements = host.findElementsById(data.dataSourceLocation);
|
|
219
|
+
if (elements.length === 0 || !(elements[0] instanceof HTMLElement)) return;
|
|
220
|
+
|
|
221
|
+
const element = elements[0];
|
|
222
|
+
|
|
223
|
+
if (data.inlineEditingMode) {
|
|
224
|
+
if (!shouldEnterInlineEditingMode(element)) return;
|
|
225
|
+
|
|
226
|
+
// Select the element first if not already selected
|
|
227
|
+
if (host.getSelectedElementId() !== data.dataSourceLocation) {
|
|
228
|
+
this.stopEditing();
|
|
229
|
+
host.clearSelection();
|
|
230
|
+
this.markElementsSelected(elements);
|
|
231
|
+
host.createSelectionOverlays(elements, data.dataSourceLocation);
|
|
232
|
+
}
|
|
233
|
+
this.startEditing(element);
|
|
234
|
+
} else {
|
|
235
|
+
if (currentEditingElement === element) {
|
|
236
|
+
this.stopEditing();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
cleanup() {
|
|
242
|
+
this.stopEditing();
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const FOCUS_STYLE_ID = "visual-edit-focus-styles";
|
|
2
|
+
|
|
3
|
+
const EDITABLE_TAGS = [
|
|
4
|
+
"div", "p", "h1", "h2", "h3", "h4", "h5", "h6",
|
|
5
|
+
"span", "li", "td", "a", "button", "label",
|
|
6
|
+
];
|
|
7
|
+
|
|
8
|
+
export const injectFocusOutlineCSS = () => {
|
|
9
|
+
if (document.getElementById(FOCUS_STYLE_ID)) return;
|
|
10
|
+
|
|
11
|
+
const style = document.createElement("style");
|
|
12
|
+
style.id = FOCUS_STYLE_ID;
|
|
13
|
+
style.textContent = `
|
|
14
|
+
[data-selected="true"][contenteditable="true"]:focus {
|
|
15
|
+
outline: none !important;
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
document.head.appendChild(style);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const removeFocusOutlineCSS = () => {
|
|
22
|
+
document.getElementById(FOCUS_STYLE_ID)?.remove();
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const selectText = (element: HTMLElement) => {
|
|
26
|
+
const range = document.createRange();
|
|
27
|
+
range.selectNodeContents(element);
|
|
28
|
+
const selection = window.getSelection();
|
|
29
|
+
selection?.removeAllRanges();
|
|
30
|
+
selection?.addRange(range);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const isEditableTextElement = (element: Element): boolean => {
|
|
34
|
+
if (!(element instanceof HTMLElement)) return false;
|
|
35
|
+
if (!EDITABLE_TAGS.includes(element.tagName.toLowerCase())) return false;
|
|
36
|
+
if (!element.textContent?.trim()) return false;
|
|
37
|
+
if (element.querySelector("img, video, canvas, svg")) return false;
|
|
38
|
+
if (element.children?.length > 0) return false;
|
|
39
|
+
if (element.dataset.dynamicContent === "true") return false;
|
|
40
|
+
return true;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const shouldEnterInlineEditingMode = (element: Element): boolean => {
|
|
44
|
+
if (!(element instanceof HTMLElement) || element.dataset.selected !== "true") {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return isEditableTextElement(element);
|
|
48
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface InlineEditHost {
|
|
2
|
+
findElementsById(id: string | null): Element[];
|
|
3
|
+
getSelectedElementId(): string | null;
|
|
4
|
+
getSelectedOverlays(): HTMLDivElement[];
|
|
5
|
+
positionOverlay(
|
|
6
|
+
overlay: HTMLDivElement,
|
|
7
|
+
element: Element,
|
|
8
|
+
isSelected?: boolean
|
|
9
|
+
): void;
|
|
10
|
+
clearSelection(): void;
|
|
11
|
+
createSelectionOverlays(elements: Element[], elementId: string): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ToggleInlineEditData {
|
|
15
|
+
dataSourceLocation: string;
|
|
16
|
+
inlineEditingMode: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface InlineEditController {
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
isEditing(): boolean;
|
|
22
|
+
getCurrentElement(): HTMLElement | null;
|
|
23
|
+
canEdit(element: Element): boolean;
|
|
24
|
+
startEditing(element: HTMLElement): void;
|
|
25
|
+
stopEditing(): void;
|
|
26
|
+
markElementsSelected(elements: Element[]): void;
|
|
27
|
+
clearSelectedMarks(elementId: string | null): void;
|
|
28
|
+
handleToggleMessage(data: ToggleInlineEditData): void;
|
|
29
|
+
cleanup(): void;
|
|
30
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, ALLOWED_ATTRIBUTES, getElementSelectorId } from "./utils.js";
|
|
2
2
|
import { createLayerController } from "./layer-dropdown/controller.js";
|
|
3
3
|
import { LAYER_DROPDOWN_ATTR } from "./layer-dropdown/consts.js";
|
|
4
|
+
import { createInlineEditController } from "../capabilities/inline-edit/index.js";
|
|
4
5
|
|
|
5
6
|
export function setupVisualEditAgent() {
|
|
6
7
|
// State variables (replacing React useState/useRef)
|
|
@@ -12,6 +13,8 @@ export function setupVisualEditAgent() {
|
|
|
12
13
|
let currentHighlightedElements: Element[] = [];
|
|
13
14
|
let selectedElementId: string | null = null;
|
|
14
15
|
|
|
16
|
+
const REPOSITION_DELAY_MS = 50;
|
|
17
|
+
|
|
15
18
|
// Create overlay element
|
|
16
19
|
const createOverlay = (isSelected = false): HTMLDivElement => {
|
|
17
20
|
const overlay = document.createElement("div");
|
|
@@ -69,6 +72,34 @@ export function setupVisualEditAgent() {
|
|
|
69
72
|
}
|
|
70
73
|
};
|
|
71
74
|
|
|
75
|
+
// --- Inline edit controller ---
|
|
76
|
+
const inlineEdit = createInlineEditController({
|
|
77
|
+
findElementsById,
|
|
78
|
+
getSelectedElementId: () => selectedElementId,
|
|
79
|
+
getSelectedOverlays: () => selectedOverlays,
|
|
80
|
+
positionOverlay,
|
|
81
|
+
clearSelection: () => {
|
|
82
|
+
inlineEdit.clearSelectedMarks(selectedElementId);
|
|
83
|
+
clearSelectedOverlays();
|
|
84
|
+
selectedElementId = null;
|
|
85
|
+
},
|
|
86
|
+
createSelectionOverlays: (elements, elementId) => {
|
|
87
|
+
elements.forEach((el) => {
|
|
88
|
+
const overlay = createOverlay(true);
|
|
89
|
+
document.body.appendChild(overlay);
|
|
90
|
+
selectedOverlays.push(overlay);
|
|
91
|
+
positionOverlay(overlay, el, true);
|
|
92
|
+
});
|
|
93
|
+
selectedElementId = elementId;
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const clearSelection = () => {
|
|
98
|
+
inlineEdit.clearSelectedMarks(selectedElementId);
|
|
99
|
+
clearSelectedOverlays();
|
|
100
|
+
selectedElementId = null;
|
|
101
|
+
};
|
|
102
|
+
|
|
72
103
|
// Clear hover overlays
|
|
73
104
|
const clearHoverOverlays = () => {
|
|
74
105
|
hoverOverlays.forEach((overlay) => {
|
|
@@ -152,7 +183,8 @@ export function setupVisualEditAgent() {
|
|
|
152
183
|
|
|
153
184
|
// Handle mouse over event
|
|
154
185
|
const handleMouseOver = (e: MouseEvent) => {
|
|
155
|
-
if (!isVisualEditMode || isPopoverDragging) return;
|
|
186
|
+
if (!isVisualEditMode || isPopoverDragging || inlineEdit.isEditing()) return;
|
|
187
|
+
|
|
156
188
|
|
|
157
189
|
const target = e.target as Element;
|
|
158
190
|
|
|
@@ -221,6 +253,21 @@ export function setupVisualEditAgent() {
|
|
|
221
253
|
// Let layer dropdown clicks pass through without interference
|
|
222
254
|
if (target.closest(`[${LAYER_DROPDOWN_ATTR}]`)) return;
|
|
223
255
|
|
|
256
|
+
// Let clicks inside the editable element pass through to the browser
|
|
257
|
+
// so the user can reposition the cursor and select text naturally.
|
|
258
|
+
if (inlineEdit.enabled && target instanceof HTMLElement && target.contentEditable === "true") {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Clicking outside the editable element exits inline editing mode.
|
|
263
|
+
if (inlineEdit.isEditing()) {
|
|
264
|
+
e.preventDefault();
|
|
265
|
+
e.stopPropagation();
|
|
266
|
+
e.stopImmediatePropagation();
|
|
267
|
+
inlineEdit.stopEditing();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
|
|
224
271
|
// Close dropdowns when clicking anywhere in iframe if a dropdown is open
|
|
225
272
|
if (isDropdownOpen) {
|
|
226
273
|
e.preventDefault();
|
|
@@ -249,14 +296,31 @@ export function setupVisualEditAgent() {
|
|
|
249
296
|
return;
|
|
250
297
|
}
|
|
251
298
|
|
|
299
|
+
const htmlElement = element as HTMLElement;
|
|
300
|
+
const visualSelectorId = getElementSelectorId(element);
|
|
301
|
+
|
|
302
|
+
const isAlreadySelected =
|
|
303
|
+
selectedElementId === visualSelectorId &&
|
|
304
|
+
htmlElement.dataset.selected === "true";
|
|
305
|
+
|
|
306
|
+
if (isAlreadySelected && inlineEdit.enabled && inlineEdit.canEdit(htmlElement)) {
|
|
307
|
+
inlineEdit.startEditing(htmlElement);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
inlineEdit.stopEditing();
|
|
312
|
+
|
|
313
|
+
if (inlineEdit.enabled) {
|
|
314
|
+
inlineEdit.markElementsSelected(findElementsById(visualSelectorId));
|
|
315
|
+
}
|
|
316
|
+
|
|
252
317
|
const selectedOverlay = selectElement(element);
|
|
253
318
|
layerController.attachToOverlay(selectedOverlay, element);
|
|
254
319
|
};
|
|
255
320
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
selectedElementId = null;
|
|
321
|
+
const unselectElement = () => {
|
|
322
|
+
inlineEdit.stopEditing();
|
|
323
|
+
clearSelection();
|
|
260
324
|
};
|
|
261
325
|
|
|
262
326
|
const updateElementClassesAndReposition = (visualSelectorId: string, classes: string) => {
|
|
@@ -288,7 +352,7 @@ export function setupVisualEditAgent() {
|
|
|
288
352
|
});
|
|
289
353
|
}
|
|
290
354
|
}
|
|
291
|
-
},
|
|
355
|
+
}, REPOSITION_DELAY_MS);
|
|
292
356
|
};
|
|
293
357
|
|
|
294
358
|
// Update element attribute by visual selector ID
|
|
@@ -311,7 +375,7 @@ export function setupVisualEditAgent() {
|
|
|
311
375
|
}
|
|
312
376
|
});
|
|
313
377
|
}
|
|
314
|
-
},
|
|
378
|
+
}, REPOSITION_DELAY_MS);
|
|
315
379
|
};
|
|
316
380
|
|
|
317
381
|
// Update element content by visual selector ID
|
|
@@ -334,7 +398,7 @@ export function setupVisualEditAgent() {
|
|
|
334
398
|
}
|
|
335
399
|
});
|
|
336
400
|
}
|
|
337
|
-
},
|
|
401
|
+
}, REPOSITION_DELAY_MS);
|
|
338
402
|
};
|
|
339
403
|
|
|
340
404
|
// --- Layer dropdown controller ---
|
|
@@ -356,12 +420,12 @@ export function setupVisualEditAgent() {
|
|
|
356
420
|
isVisualEditMode = isEnabled;
|
|
357
421
|
|
|
358
422
|
if (!isEnabled) {
|
|
423
|
+
inlineEdit.stopEditing();
|
|
424
|
+
clearSelection();
|
|
359
425
|
layerController.cleanup();
|
|
360
426
|
clearHoverOverlays();
|
|
361
|
-
clearSelectedOverlays();
|
|
362
427
|
|
|
363
428
|
currentHighlightedElements = [];
|
|
364
|
-
selectedElementId = null;
|
|
365
429
|
document.body.style.cursor = "default";
|
|
366
430
|
|
|
367
431
|
document.removeEventListener("mouseover", handleMouseOver);
|
|
@@ -422,6 +486,9 @@ export function setupVisualEditAgent() {
|
|
|
422
486
|
switch (message.type) {
|
|
423
487
|
case "toggle-visual-edit-mode":
|
|
424
488
|
toggleVisualEditMode(message.data.enabled);
|
|
489
|
+
if (message.data.specs?.newInlineEditEnabled !== undefined) {
|
|
490
|
+
inlineEdit.enabled = message.data.specs.newInlineEditEnabled;
|
|
491
|
+
}
|
|
425
492
|
break;
|
|
426
493
|
|
|
427
494
|
case "update-classes":
|
|
@@ -459,7 +526,7 @@ export function setupVisualEditAgent() {
|
|
|
459
526
|
break;
|
|
460
527
|
|
|
461
528
|
case "unselect-element":
|
|
462
|
-
|
|
529
|
+
unselectElement();
|
|
463
530
|
break;
|
|
464
531
|
|
|
465
532
|
case "refresh-page":
|
|
@@ -537,6 +604,12 @@ export function setupVisualEditAgent() {
|
|
|
537
604
|
}
|
|
538
605
|
break;
|
|
539
606
|
|
|
607
|
+
case "toggle-inline-edit-mode":
|
|
608
|
+
if (message.data) {
|
|
609
|
+
inlineEdit.handleToggleMessage(message.data);
|
|
610
|
+
}
|
|
611
|
+
break;
|
|
612
|
+
|
|
540
613
|
default:
|
|
541
614
|
break;
|
|
542
615
|
}
|
|
@@ -601,7 +674,7 @@ export function setupVisualEditAgent() {
|
|
|
601
674
|
});
|
|
602
675
|
|
|
603
676
|
if (needsUpdate) {
|
|
604
|
-
setTimeout(handleResize,
|
|
677
|
+
setTimeout(handleResize, REPOSITION_DELAY_MS);
|
|
605
678
|
}
|
|
606
679
|
});
|
|
607
680
|
|