@base44/vite-plugin 0.2.26 → 0.2.28

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.
Files changed (27) hide show
  1. package/dist/capabilities/inline-edit/controller.d.ts +3 -0
  2. package/dist/capabilities/inline-edit/controller.d.ts.map +1 -0
  3. package/dist/capabilities/inline-edit/controller.js +200 -0
  4. package/dist/capabilities/inline-edit/controller.js.map +1 -0
  5. package/dist/capabilities/inline-edit/dom-utils.d.ts +7 -0
  6. package/dist/capabilities/inline-edit/dom-utils.d.ts.map +1 -0
  7. package/dist/capabilities/inline-edit/dom-utils.js +59 -0
  8. package/dist/capabilities/inline-edit/dom-utils.js.map +1 -0
  9. package/dist/capabilities/inline-edit/index.d.ts +3 -0
  10. package/dist/capabilities/inline-edit/index.d.ts.map +1 -0
  11. package/dist/capabilities/inline-edit/index.js +2 -0
  12. package/dist/capabilities/inline-edit/index.js.map +1 -0
  13. package/dist/capabilities/inline-edit/types.d.ts +25 -0
  14. package/dist/capabilities/inline-edit/types.d.ts.map +1 -0
  15. package/dist/capabilities/inline-edit/types.js +2 -0
  16. package/dist/capabilities/inline-edit/types.js.map +1 -0
  17. package/dist/injections/visual-edit-agent.d.ts.map +1 -1
  18. package/dist/injections/visual-edit-agent.js +86 -16
  19. package/dist/injections/visual-edit-agent.js.map +1 -1
  20. package/dist/statics/index.mjs +5 -1
  21. package/dist/statics/index.mjs.map +1 -1
  22. package/package.json +1 -1
  23. package/src/capabilities/inline-edit/controller.ts +251 -0
  24. package/src/capabilities/inline-edit/dom-utils.ts +58 -0
  25. package/src/capabilities/inline-edit/index.ts +2 -0
  26. package/src/capabilities/inline-edit/types.ts +30 -0
  27. package/src/injections/visual-edit-agent.ts +105 -16
@@ -0,0 +1,3 @@
1
+ import type { InlineEditHost, InlineEditController } from "./types.js";
2
+ export declare function createInlineEditController(host: InlineEditHost): InlineEditController;
3
+ //# sourceMappingURL=controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAWvE,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,cAAc,GACnB,oBAAoB,CA6OtB"}
@@ -0,0 +1,200 @@
1
+ import { injectFocusOutlineCSS, removeFocusOutlineCSS, selectText, shouldEnterInlineEditingMode, isStaticArrayTextElement, } from "./dom-utils.js";
2
+ const DEBOUNCE_MS = 500;
3
+ export function createInlineEditController(host) {
4
+ let currentEditingElement = null;
5
+ let debouncedSendTimeout = null;
6
+ let enabled = false;
7
+ const listenerAbortControllers = new WeakMap();
8
+ // --- Private helpers ---
9
+ const repositionOverlays = () => {
10
+ const selectedId = host.getSelectedElementId();
11
+ if (!selectedId)
12
+ return;
13
+ const elements = host.findElementsById(selectedId);
14
+ const overlays = host.getSelectedOverlays();
15
+ overlays.forEach((overlay, i) => {
16
+ if (i < elements.length && elements[i]) {
17
+ host.positionOverlay(overlay, elements[i]);
18
+ }
19
+ });
20
+ };
21
+ const reportEdit = (element) => {
22
+ const originalContent = element.dataset.originalTextContent;
23
+ const newContent = element.textContent;
24
+ const svgElement = element;
25
+ const rect = element.getBoundingClientRect();
26
+ const message = {
27
+ type: "inline-edit",
28
+ elementInfo: {
29
+ tagName: element.tagName,
30
+ classes: svgElement.className?.baseVal ||
31
+ element.className ||
32
+ "",
33
+ visualSelectorId: host.getSelectedElementId(),
34
+ content: newContent,
35
+ dataSourceLocation: element.dataset.sourceLocation,
36
+ isDynamicContent: element.dataset.dynamicContent === "true",
37
+ linenumber: element.dataset.linenumber,
38
+ filename: element.dataset.filename,
39
+ position: {
40
+ top: rect.top,
41
+ left: rect.left,
42
+ right: rect.right,
43
+ bottom: rect.bottom,
44
+ width: rect.width,
45
+ height: rect.height,
46
+ centerX: rect.left + rect.width / 2,
47
+ centerY: rect.top + rect.height / 2,
48
+ },
49
+ },
50
+ originalContent,
51
+ newContent,
52
+ };
53
+ if (isStaticArrayTextElement(element)) {
54
+ message.arrIndex = element.dataset.arrIndex;
55
+ message.arrVariableName = element.dataset.arrVariableName;
56
+ message.arrField = element.dataset.arrField;
57
+ }
58
+ window.parent.postMessage(message, "*");
59
+ element.dataset.originalTextContent = newContent || "";
60
+ };
61
+ const debouncedReport = (element) => {
62
+ if (debouncedSendTimeout)
63
+ clearTimeout(debouncedSendTimeout);
64
+ debouncedSendTimeout = setTimeout(() => reportEdit(element), DEBOUNCE_MS);
65
+ };
66
+ const onTextInput = (element) => {
67
+ repositionOverlays();
68
+ debouncedReport(element);
69
+ };
70
+ const handleInputEvent = function () {
71
+ onTextInput(this);
72
+ };
73
+ const makeEditable = (element) => {
74
+ injectFocusOutlineCSS();
75
+ element.dataset.originalTextContent = element.textContent || "";
76
+ element.dataset.originalCursor = element.style.cursor;
77
+ element.contentEditable = "true";
78
+ const abortController = new AbortController();
79
+ listenerAbortControllers.set(element, abortController);
80
+ element.addEventListener("input", handleInputEvent, {
81
+ signal: abortController.signal,
82
+ });
83
+ element.style.cursor = "text";
84
+ selectText(element);
85
+ setTimeout(() => {
86
+ if (element.isConnected) {
87
+ element.focus();
88
+ }
89
+ }, 0);
90
+ };
91
+ const makeNonEditable = (element) => {
92
+ const abortController = listenerAbortControllers.get(element);
93
+ if (abortController) {
94
+ abortController.abort();
95
+ listenerAbortControllers.delete(element);
96
+ }
97
+ if (!element.isConnected)
98
+ return;
99
+ removeFocusOutlineCSS();
100
+ element.contentEditable = "false";
101
+ delete element.dataset.originalTextContent;
102
+ if (element.dataset.originalCursor !== undefined) {
103
+ element.style.cursor = element.dataset.originalCursor;
104
+ delete element.dataset.originalCursor;
105
+ }
106
+ };
107
+ // --- Public API ---
108
+ return {
109
+ get enabled() {
110
+ return enabled;
111
+ },
112
+ set enabled(value) {
113
+ enabled = value;
114
+ },
115
+ isEditing() {
116
+ return currentEditingElement !== null;
117
+ },
118
+ getCurrentElement() {
119
+ return currentEditingElement;
120
+ },
121
+ canEdit(element) {
122
+ return shouldEnterInlineEditingMode(element);
123
+ },
124
+ startEditing(element) {
125
+ currentEditingElement = element;
126
+ host.getSelectedOverlays().forEach((o) => {
127
+ o.style.display = "none";
128
+ });
129
+ makeEditable(element);
130
+ window.parent.postMessage({
131
+ type: "content-editing-started",
132
+ visualSelectorId: host.getSelectedElementId(),
133
+ }, "*");
134
+ },
135
+ stopEditing() {
136
+ if (!currentEditingElement)
137
+ return;
138
+ if (debouncedSendTimeout) {
139
+ clearTimeout(debouncedSendTimeout);
140
+ debouncedSendTimeout = null;
141
+ }
142
+ const element = currentEditingElement;
143
+ makeNonEditable(element);
144
+ host.getSelectedOverlays().forEach((o) => {
145
+ o.style.display = "";
146
+ });
147
+ repositionOverlays();
148
+ window.parent.postMessage({
149
+ type: "content-editing-ended",
150
+ visualSelectorId: host.getSelectedElementId(),
151
+ }, "*");
152
+ currentEditingElement = null;
153
+ },
154
+ markElementsSelected(elements) {
155
+ elements.forEach((el) => {
156
+ if (el instanceof HTMLElement) {
157
+ el.dataset.selected = "true";
158
+ }
159
+ });
160
+ },
161
+ clearSelectedMarks(elementId) {
162
+ if (!elementId)
163
+ return;
164
+ host.findElementsById(elementId).forEach((el) => {
165
+ if (el instanceof HTMLElement) {
166
+ delete el.dataset.selected;
167
+ }
168
+ });
169
+ },
170
+ handleToggleMessage(data) {
171
+ if (!enabled)
172
+ return;
173
+ const elements = host.findElementsById(data.dataSourceLocation);
174
+ if (elements.length === 0 || !(elements[0] instanceof HTMLElement))
175
+ return;
176
+ const element = elements[0];
177
+ if (data.inlineEditingMode) {
178
+ if (!shouldEnterInlineEditingMode(element))
179
+ return;
180
+ // Select the element first if not already selected
181
+ if (host.getSelectedElementId() !== data.dataSourceLocation) {
182
+ this.stopEditing();
183
+ host.clearSelection();
184
+ this.markElementsSelected(elements);
185
+ host.createSelectionOverlays(elements, data.dataSourceLocation);
186
+ }
187
+ this.startEditing(element);
188
+ }
189
+ else {
190
+ if (currentEditingElement === element) {
191
+ this.stopEditing();
192
+ }
193
+ }
194
+ },
195
+ cleanup() {
196
+ this.stopEditing();
197
+ },
198
+ };
199
+ }
200
+ //# sourceMappingURL=controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const isStaticArrayTextElement: (element: HTMLElement) => boolean;
2
+ export declare const injectFocusOutlineCSS: () => void;
3
+ export declare const removeFocusOutlineCSS: () => void;
4
+ export declare const selectText: (element: HTMLElement) => void;
5
+ export declare const isEditableTextElement: (element: Element) => boolean;
6
+ export declare const shouldEnterInlineEditingMode: (element: Element) => boolean;
7
+ //# sourceMappingURL=dom-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-utils.d.ts","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/dom-utils.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,wBAAwB,GAAI,SAAS,WAAW,KAAG,OAE/D,CAAC;AAUF,eAAO,MAAM,qBAAqB,YAWjC,CAAC;AAEF,eAAO,MAAM,qBAAqB,YAEjC,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,SAAS,WAAW,SAM9C,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,SAAS,OAAO,KAAG,OAMxD,CAAC;AAEF,eAAO,MAAM,4BAA4B,GAAI,SAAS,OAAO,KAAG,OAK/D,CAAC"}
@@ -0,0 +1,59 @@
1
+ const FOCUS_STYLE_ID = "visual-edit-focus-styles";
2
+ const EDITABLE_TAGS = [
3
+ "div", "p", "h1", "h2", "h3", "h4", "h5", "h6",
4
+ "span", "li", "td", "a", "button", "label",
5
+ ];
6
+ export const isStaticArrayTextElement = (element) => {
7
+ return !!element.dataset.arrField;
8
+ };
9
+ const passesStructuralChecks = (element) => {
10
+ if (!EDITABLE_TAGS.includes(element.tagName.toLowerCase()))
11
+ return false;
12
+ if (!element.textContent?.trim())
13
+ return false;
14
+ if (element.querySelector("img, video, canvas, svg"))
15
+ return false;
16
+ if (element.children?.length > 0)
17
+ return false;
18
+ return true;
19
+ };
20
+ export const injectFocusOutlineCSS = () => {
21
+ if (document.getElementById(FOCUS_STYLE_ID))
22
+ return;
23
+ const style = document.createElement("style");
24
+ style.id = FOCUS_STYLE_ID;
25
+ style.textContent = `
26
+ [data-selected="true"][contenteditable="true"]:focus {
27
+ outline: none !important;
28
+ }
29
+ `;
30
+ document.head.appendChild(style);
31
+ };
32
+ export const removeFocusOutlineCSS = () => {
33
+ document.getElementById(FOCUS_STYLE_ID)?.remove();
34
+ };
35
+ export const selectText = (element) => {
36
+ const range = document.createRange();
37
+ range.selectNodeContents(element);
38
+ const selection = window.getSelection();
39
+ selection?.removeAllRanges();
40
+ selection?.addRange(range);
41
+ };
42
+ export const isEditableTextElement = (element) => {
43
+ if (!(element instanceof HTMLElement))
44
+ return false;
45
+ if (!passesStructuralChecks(element))
46
+ return false;
47
+ if (isStaticArrayTextElement(element))
48
+ return true;
49
+ if (element.dataset.dynamicContent === "true")
50
+ return false;
51
+ return true;
52
+ };
53
+ export const shouldEnterInlineEditingMode = (element) => {
54
+ if (!(element instanceof HTMLElement) || element.dataset.selected !== "true") {
55
+ return false;
56
+ }
57
+ return isEditableTextElement(element);
58
+ };
59
+ //# sourceMappingURL=dom-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-utils.js","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/dom-utils.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAElD,MAAM,aAAa,GAAG;IACpB,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC9C,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO;CAC3C,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,OAAoB,EAAW,EAAE;IACxE,OAAO,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,CAAC,OAAoB,EAAW,EAAE;IAC/D,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IACzE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IAC/C,IAAI,OAAO,CAAC,aAAa,CAAC,yBAAyB,CAAC;QAAE,OAAO,KAAK,CAAC;IACnE,IAAI,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/C,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,EAAE;IACxC,IAAI,QAAQ,CAAC,cAAc,CAAC,cAAc,CAAC;QAAE,OAAO;IAEpD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,GAAG,cAAc,CAAC;IAC1B,KAAK,CAAC,WAAW,GAAG;;;;GAInB,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,EAAE;IACxC,QAAQ,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,OAAoB,EAAE,EAAE;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,KAAK,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACxC,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,OAAgB,EAAW,EAAE;IACjE,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,wBAAwB,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,OAAO,CAAC,OAAO,CAAC,cAAc,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,OAAgB,EAAW,EAAE;IACxE,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC7E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,qBAAqB,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { createInlineEditController } from "./controller.js";
2
+ export type { InlineEditController, InlineEditHost } from "./types.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC7D,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createInlineEditController } from "./controller.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface InlineEditHost {
2
+ findElementsById(id: string | null): Element[];
3
+ getSelectedElementId(): string | null;
4
+ getSelectedOverlays(): HTMLDivElement[];
5
+ positionOverlay(overlay: HTMLDivElement, element: Element, isSelected?: boolean): void;
6
+ clearSelection(): void;
7
+ createSelectionOverlays(elements: Element[], elementId: string): void;
8
+ }
9
+ export interface ToggleInlineEditData {
10
+ dataSourceLocation: string;
11
+ inlineEditingMode: boolean;
12
+ }
13
+ export interface InlineEditController {
14
+ enabled: boolean;
15
+ isEditing(): boolean;
16
+ getCurrentElement(): HTMLElement | null;
17
+ canEdit(element: Element): boolean;
18
+ startEditing(element: HTMLElement): void;
19
+ stopEditing(): void;
20
+ markElementsSelected(elements: Element[]): void;
21
+ clearSelectedMarks(elementId: string | null): void;
22
+ handleToggleMessage(data: ToggleInlineEditData): void;
23
+ cleanup(): void;
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE,CAAC;IAC/C,oBAAoB,IAAI,MAAM,GAAG,IAAI,CAAC;IACtC,mBAAmB,IAAI,cAAc,EAAE,CAAC;IACxC,eAAe,CACb,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,OAAO,EAChB,UAAU,CAAC,EAAE,OAAO,GACnB,IAAI,CAAC;IACR,cAAc,IAAI,IAAI,CAAC;IACvB,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACvE;AAED,MAAM,WAAW,oBAAoB;IACnC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,IAAI,OAAO,CAAC;IACrB,iBAAiB,IAAI,WAAW,GAAG,IAAI,CAAC;IACxC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IACnC,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACzC,WAAW,IAAI,IAAI,CAAC;IACpB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChD,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACnD,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtD,OAAO,IAAI,IAAI,CAAC;CACjB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/capabilities/inline-edit/types.ts"],"names":[],"mappings":""}
@@ -1 +1 @@
1
- {"version":3,"file":"visual-edit-agent.d.ts","sourceRoot":"","sources":["../../src/injections/visual-edit-agent.ts"],"names":[],"mappings":"AAIA,wBAAgB,oBAAoB,SA4mBnC"}
1
+ {"version":3,"file":"visual-edit-agent.d.ts","sourceRoot":"","sources":["../../src/injections/visual-edit-agent.ts"],"names":[],"mappings":"AAKA,wBAAgB,oBAAoB,SAosBnC"}
@@ -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
  export function setupVisualEditAgent() {
5
6
  // State variables (replacing React useState/useRef)
6
7
  let isVisualEditMode = false;
@@ -10,6 +11,7 @@ export function setupVisualEditAgent() {
10
11
  let selectedOverlays = [];
11
12
  let currentHighlightedElements = [];
12
13
  let selectedElementId = null;
14
+ const REPOSITION_DELAY_MS = 50;
13
15
  // Create overlay element
14
16
  const createOverlay = (isSelected = false) => {
15
17
  const overlay = document.createElement("div");
@@ -57,6 +59,32 @@ export function setupVisualEditAgent() {
57
59
  overlay.appendChild(label);
58
60
  }
59
61
  };
62
+ // --- Inline edit controller ---
63
+ const inlineEdit = createInlineEditController({
64
+ findElementsById,
65
+ getSelectedElementId: () => selectedElementId,
66
+ getSelectedOverlays: () => selectedOverlays,
67
+ positionOverlay,
68
+ clearSelection: () => {
69
+ inlineEdit.clearSelectedMarks(selectedElementId);
70
+ clearSelectedOverlays();
71
+ selectedElementId = null;
72
+ },
73
+ createSelectionOverlays: (elements, elementId) => {
74
+ elements.forEach((el) => {
75
+ const overlay = createOverlay(true);
76
+ document.body.appendChild(overlay);
77
+ selectedOverlays.push(overlay);
78
+ positionOverlay(overlay, el, true);
79
+ });
80
+ selectedElementId = elementId;
81
+ },
82
+ });
83
+ const clearSelection = () => {
84
+ inlineEdit.clearSelectedMarks(selectedElementId);
85
+ clearSelectedOverlays();
86
+ selectedElementId = null;
87
+ };
60
88
  // Clear hover overlays
61
89
  const clearHoverOverlays = () => {
62
90
  hoverOverlays.forEach((overlay) => {
@@ -81,6 +109,11 @@ export function setupVisualEditAgent() {
81
109
  const rect = element.getBoundingClientRect();
82
110
  const svgElement = element;
83
111
  const isTextElement = TEXT_TAGS.includes(element.tagName?.toLowerCase());
112
+ const arrEl = htmlElement.closest("[data-arr-variable-name]");
113
+ const staticArrayName = arrEl?.dataset?.arrVariableName || null;
114
+ const rawIdx = arrEl?.dataset?.arrIndex;
115
+ const staticArrayIndex = rawIdx != null ? parseInt(rawIdx, 10) : null;
116
+ const staticArrayField = htmlElement.dataset?.arrField || null;
84
117
  window.parent.postMessage({
85
118
  type: "element-selected",
86
119
  tagName: element.tagName,
@@ -105,6 +138,9 @@ export function setupVisualEditAgent() {
105
138
  },
106
139
  attributes: collectAllowedAttributes(element, ALLOWED_ATTRIBUTES),
107
140
  isTextElement,
141
+ staticArrayName,
142
+ staticArrayIndex,
143
+ staticArrayField,
108
144
  }, "*");
109
145
  };
110
146
  // Select an element: create overlays, update state, notify parent
@@ -129,7 +165,7 @@ export function setupVisualEditAgent() {
129
165
  };
130
166
  // Handle mouse over event
131
167
  const handleMouseOver = (e) => {
132
- if (!isVisualEditMode || isPopoverDragging)
168
+ if (!isVisualEditMode || isPopoverDragging || inlineEdit.isEditing())
133
169
  return;
134
170
  const target = e.target;
135
171
  // Prevent hover effects when a dropdown is open
@@ -184,6 +220,19 @@ export function setupVisualEditAgent() {
184
220
  // Let layer dropdown clicks pass through without interference
185
221
  if (target.closest(`[${LAYER_DROPDOWN_ATTR}]`))
186
222
  return;
223
+ // Let clicks inside the editable element pass through to the browser
224
+ // so the user can reposition the cursor and select text naturally.
225
+ if (inlineEdit.enabled && target instanceof HTMLElement && target.contentEditable === "true") {
226
+ return;
227
+ }
228
+ // Clicking outside the editable element exits inline editing mode.
229
+ if (inlineEdit.isEditing()) {
230
+ e.preventDefault();
231
+ e.stopPropagation();
232
+ e.stopImmediatePropagation();
233
+ inlineEdit.stopEditing();
234
+ return;
235
+ }
187
236
  // Close dropdowns when clicking anywhere in iframe if a dropdown is open
188
237
  if (isDropdownOpen) {
189
238
  e.preventDefault();
@@ -205,13 +254,24 @@ export function setupVisualEditAgent() {
205
254
  if (!element) {
206
255
  return;
207
256
  }
257
+ const htmlElement = element;
258
+ const visualSelectorId = getElementSelectorId(element);
259
+ const isAlreadySelected = selectedElementId === visualSelectorId &&
260
+ htmlElement.dataset.selected === "true";
261
+ if (isAlreadySelected && inlineEdit.enabled && inlineEdit.canEdit(htmlElement)) {
262
+ inlineEdit.startEditing(htmlElement);
263
+ return;
264
+ }
265
+ inlineEdit.stopEditing();
266
+ if (inlineEdit.enabled) {
267
+ inlineEdit.markElementsSelected(findElementsById(visualSelectorId));
268
+ }
208
269
  const selectedOverlay = selectElement(element);
209
270
  layerController.attachToOverlay(selectedOverlay, element);
210
271
  };
211
- // Clear the current selection
212
- const clearSelection = () => {
213
- clearSelectedOverlays();
214
- selectedElementId = null;
272
+ const unselectElement = () => {
273
+ inlineEdit.stopEditing();
274
+ clearSelection();
215
275
  };
216
276
  const updateElementClassesAndReposition = (visualSelectorId, classes) => {
217
277
  const elements = findElementsById(visualSelectorId);
@@ -240,7 +300,7 @@ export function setupVisualEditAgent() {
240
300
  });
241
301
  }
242
302
  }
243
- }, 50);
303
+ }, REPOSITION_DELAY_MS);
244
304
  };
245
305
  // Update element attribute by visual selector ID
246
306
  const updateElementAttributeAndReposition = (visualSelectorId, attribute, value) => {
@@ -257,14 +317,16 @@ export function setupVisualEditAgent() {
257
317
  }
258
318
  });
259
319
  }
260
- }, 50);
320
+ }, REPOSITION_DELAY_MS);
261
321
  };
262
- // Update element content by visual selector ID
263
- const updateElementContent = (visualSelectorId, content) => {
264
- const elements = findElementsById(visualSelectorId);
322
+ const updateElementContent = (visualSelectorId, content, arrIndex) => {
323
+ let elements = findElementsById(visualSelectorId);
265
324
  if (elements.length === 0) {
266
325
  return;
267
326
  }
327
+ if (arrIndex != null) {
328
+ elements = elements.filter((el) => el.dataset.arrIndex === String(arrIndex));
329
+ }
268
330
  elements.forEach((element) => {
269
331
  element.innerText = content;
270
332
  });
@@ -276,7 +338,7 @@ export function setupVisualEditAgent() {
276
338
  }
277
339
  });
278
340
  }
279
- }, 50);
341
+ }, REPOSITION_DELAY_MS);
280
342
  };
281
343
  // --- Layer dropdown controller ---
282
344
  const layerController = createLayerController({
@@ -295,11 +357,11 @@ export function setupVisualEditAgent() {
295
357
  const toggleVisualEditMode = (isEnabled) => {
296
358
  isVisualEditMode = isEnabled;
297
359
  if (!isEnabled) {
360
+ inlineEdit.stopEditing();
361
+ clearSelection();
298
362
  layerController.cleanup();
299
363
  clearHoverOverlays();
300
- clearSelectedOverlays();
301
364
  currentHighlightedElements = [];
302
- selectedElementId = null;
303
365
  document.body.style.cursor = "default";
304
366
  document.removeEventListener("mouseover", handleMouseOver);
305
367
  document.removeEventListener("mouseout", handleMouseOut);
@@ -350,6 +412,9 @@ export function setupVisualEditAgent() {
350
412
  switch (message.type) {
351
413
  case "toggle-visual-edit-mode":
352
414
  toggleVisualEditMode(message.data.enabled);
415
+ if (message.data.specs?.newInlineEditEnabled !== undefined) {
416
+ inlineEdit.enabled = message.data.specs.newInlineEditEnabled;
417
+ }
353
418
  break;
354
419
  case "update-classes":
355
420
  if (message.data && message.data.classes !== undefined) {
@@ -371,14 +436,14 @@ export function setupVisualEditAgent() {
371
436
  }
372
437
  break;
373
438
  case "unselect-element":
374
- clearSelection();
439
+ unselectElement();
375
440
  break;
376
441
  case "refresh-page":
377
442
  window.location.reload();
378
443
  break;
379
444
  case "update-content":
380
445
  if (message.data && message.data.content !== undefined) {
381
- updateElementContent(message.data.visualSelectorId, message.data.content);
446
+ updateElementContent(message.data.visualSelectorId, message.data.content, message.data.arrIndex);
382
447
  }
383
448
  else {
384
449
  console.warn("[VisualEditAgent] Invalid update-content message:", message);
@@ -431,6 +496,11 @@ export function setupVisualEditAgent() {
431
496
  }
432
497
  }
433
498
  break;
499
+ case "toggle-inline-edit-mode":
500
+ if (message.data) {
501
+ inlineEdit.handleToggleMessage(message.data);
502
+ }
503
+ break;
434
504
  default:
435
505
  break;
436
506
  }
@@ -485,7 +555,7 @@ export function setupVisualEditAgent() {
485
555
  return isLayoutChange && hasVisualId(mutation.target);
486
556
  });
487
557
  if (needsUpdate) {
488
- setTimeout(handleResize, 50);
558
+ setTimeout(handleResize, REPOSITION_DELAY_MS);
489
559
  }
490
560
  });
491
561
  // Set up event listeners