@base44/vite-plugin 0.2.27 → 0.2.29

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 (77) hide show
  1. package/dist/capabilities/inline-edit/controller.d.ts.map +1 -1
  2. package/dist/capabilities/inline-edit/controller.js +9 -3
  3. package/dist/capabilities/inline-edit/controller.js.map +1 -1
  4. package/dist/capabilities/inline-edit/dom-utils.d.ts +1 -0
  5. package/dist/capabilities/inline-edit/dom-utils.d.ts.map +1 -1
  6. package/dist/capabilities/inline-edit/dom-utils.js +17 -7
  7. package/dist/capabilities/inline-edit/dom-utils.js.map +1 -1
  8. package/dist/capabilities/inline-edit/index.d.ts +1 -1
  9. package/dist/capabilities/inline-edit/index.d.ts.map +1 -1
  10. package/dist/capabilities/inline-edit/types.d.ts +4 -0
  11. package/dist/capabilities/inline-edit/types.d.ts.map +1 -1
  12. package/dist/consts.d.ts +11 -0
  13. package/dist/consts.d.ts.map +1 -0
  14. package/dist/consts.js +11 -0
  15. package/dist/consts.js.map +1 -0
  16. package/dist/injections/visual-edit-agent.d.ts.map +1 -1
  17. package/dist/injections/visual-edit-agent.js +26 -4
  18. package/dist/injections/visual-edit-agent.js.map +1 -1
  19. package/dist/jsx-processor.d.ts +3 -1
  20. package/dist/jsx-processor.d.ts.map +1 -1
  21. package/dist/jsx-processor.js +29 -6
  22. package/dist/jsx-processor.js.map +1 -1
  23. package/dist/jsx-utils.d.ts +9 -0
  24. package/dist/jsx-utils.d.ts.map +1 -1
  25. package/dist/jsx-utils.js +86 -0
  26. package/dist/jsx-utils.js.map +1 -1
  27. package/dist/processors/collection-id-processor.d.ts +20 -0
  28. package/dist/processors/collection-id-processor.d.ts.map +1 -0
  29. package/dist/processors/collection-id-processor.js +182 -0
  30. package/dist/processors/collection-id-processor.js.map +1 -0
  31. package/dist/processors/collection-item-field-processor.d.ts +39 -0
  32. package/dist/processors/collection-item-field-processor.d.ts.map +1 -0
  33. package/dist/processors/collection-item-field-processor.js +281 -0
  34. package/dist/processors/collection-item-field-processor.js.map +1 -0
  35. package/dist/processors/collection-item-id-processor.d.ts +12 -0
  36. package/dist/processors/collection-item-id-processor.d.ts.map +1 -0
  37. package/dist/processors/collection-item-id-processor.js +50 -0
  38. package/dist/processors/collection-item-id-processor.js.map +1 -0
  39. package/dist/processors/static-array-processor.d.ts +0 -3
  40. package/dist/processors/static-array-processor.d.ts.map +1 -1
  41. package/dist/processors/static-array-processor.js +2 -4
  42. package/dist/processors/static-array-processor.js.map +1 -1
  43. package/dist/processors/utils/collection-tracing-utils.d.ts +36 -0
  44. package/dist/processors/utils/collection-tracing-utils.d.ts.map +1 -0
  45. package/dist/processors/utils/collection-tracing-utils.js +390 -0
  46. package/dist/processors/utils/collection-tracing-utils.js.map +1 -0
  47. package/dist/processors/utils/shared-utils.d.ts +96 -0
  48. package/dist/processors/utils/shared-utils.d.ts.map +1 -0
  49. package/dist/processors/utils/shared-utils.js +600 -0
  50. package/dist/processors/utils/shared-utils.js.map +1 -0
  51. package/dist/statics/index.mjs +2 -2
  52. package/dist/statics/index.mjs.map +1 -1
  53. package/dist/visual-edit-plugin.d.ts +0 -1
  54. package/dist/visual-edit-plugin.d.ts.map +1 -1
  55. package/dist/visual-edit-plugin.js +29 -178
  56. package/dist/visual-edit-plugin.js.map +1 -1
  57. package/package.json +1 -1
  58. package/src/capabilities/inline-edit/controller.ts +35 -29
  59. package/src/capabilities/inline-edit/dom-utils.ts +14 -4
  60. package/src/capabilities/inline-edit/index.ts +1 -1
  61. package/src/capabilities/inline-edit/types.ts +5 -0
  62. package/src/consts.ts +11 -0
  63. package/src/injections/visual-edit-agent.ts +33 -4
  64. package/src/jsx-processor.ts +36 -14
  65. package/src/jsx-utils.ts +116 -0
  66. package/src/processors/collection-id-processor.ts +261 -0
  67. package/src/processors/collection-item-field-processor.ts +433 -0
  68. package/src/processors/collection-item-id-processor.ts +69 -0
  69. package/src/processors/static-array-processor.ts +7 -4
  70. package/src/processors/utils/collection-tracing-utils.ts +507 -0
  71. package/src/processors/utils/shared-utils.ts +785 -0
  72. package/src/visual-edit-plugin.ts +34 -215
  73. package/dist/processors/shared-utils.d.ts +0 -19
  74. package/dist/processors/shared-utils.d.ts.map +0 -1
  75. package/dist/processors/shared-utils.js +0 -77
  76. package/dist/processors/shared-utils.js.map +0 -1
  77. package/src/processors/shared-utils.ts +0 -116
@@ -2,175 +2,27 @@ import { parse } from "@babel/parser";
2
2
  import { default as traverse } from "@babel/traverse";
3
3
  import { default as generate } from "@babel/generator";
4
4
  import * as t from "@babel/types";
5
- import { StaticArrayProcessor } from "./processors/static-array-processor.js";
5
+ import { JSXProcessor } from "./jsx-processor.js";
6
6
  import { JSXUtils } from "./jsx-utils.js";
7
- // Helper function to check if JSX element contains dynamic content
8
- export function checkIfElementHasDynamicContent(jsxElement) {
9
- let hasDynamicContent = false;
10
- // Helper function to check if any node contains dynamic patterns
11
- function checkNodeForDynamicContent(node) {
12
- // JSX expressions like {variable}, {func()}, {obj.prop}
13
- if (t.isJSXExpressionContainer(node)) {
14
- const expression = node.expression;
15
- // Skip empty expressions {}
16
- if (t.isJSXEmptyExpression(expression)) {
17
- return false;
18
- }
19
- // Any non-literal expression is considered dynamic
20
- if (!t.isLiteral(expression)) {
21
- return true;
22
- }
23
- }
24
- // Template literals with expressions `Hello ${name}`
25
- if (t.isTemplateLiteral(node) && node.expressions.length > 0) {
26
- return true;
27
- }
28
- // Member expressions like props.title, state.value
29
- if (t.isMemberExpression(node)) {
30
- return true;
31
- }
32
- // Function calls like getData(), format()
33
- if (t.isCallExpression(node)) {
34
- return true;
35
- }
36
- // Conditional expressions like condition ? "yes" : "no"
37
- if (t.isConditionalExpression(node)) {
38
- return true;
39
- }
40
- // Identifier references (could be props, state, variables)
41
- if (t.isIdentifier(node)) {
42
- // Common dynamic identifiers
43
- const dynamicNames = [
44
- "props",
45
- "state",
46
- "data",
47
- "item",
48
- "value",
49
- "text",
50
- "content",
51
- ];
52
- if (dynamicNames.some((name) => node.name.includes(name))) {
53
- return true;
54
- }
55
- }
56
- return false;
57
- }
58
- // Recursively traverse all child nodes
59
- function traverseNode(node) {
60
- if (checkNodeForDynamicContent(node)) {
61
- hasDynamicContent = true;
62
- return;
63
- }
64
- // Recursively check child nodes
65
- Object.keys(node).forEach((key) => {
66
- const value = node[key];
67
- if (Array.isArray(value)) {
68
- value.forEach((child) => {
69
- if (child && typeof child === "object" && child.type) {
70
- traverseNode(child);
71
- }
72
- });
73
- }
74
- else if (value && typeof value === "object" && value.type) {
75
- traverseNode(value);
76
- }
77
- });
78
- }
79
- // Check the element's own attributes for dynamic content
80
- const attributes = jsxElement.openingElement?.attributes || [];
81
- attributes.forEach((attr) => {
82
- if (hasDynamicContent)
83
- return; // Early exit if already found dynamic content
84
- // Spread attributes like {...props} are always dynamic
85
- if (t.isJSXSpreadAttribute(attr)) {
86
- hasDynamicContent = true;
87
- return;
88
- }
89
- // Check attribute values for dynamic expressions
90
- if (t.isJSXAttribute(attr) && attr.value) {
91
- traverseNode(attr.value);
92
- }
93
- });
94
- // Check all children of the JSX element
95
- jsxElement.children.forEach((child) => {
96
- if (hasDynamicContent)
97
- return; // Early exit if already found dynamic content
98
- traverseNode(child);
99
- });
100
- return hasDynamicContent;
101
- }
102
7
  export function visualEditPlugin() {
103
8
  return {
104
9
  name: "visual-edit-transform",
105
10
  apply: (config) => config.mode === "development",
106
11
  enforce: "pre",
107
12
  order: "pre",
108
- // Inject Tailwind CDN for visual editing capabilities
109
13
  transformIndexHtml(html) {
110
- // Inject the Tailwind CSS CDN script right before the closing </head> tag
111
14
  const tailwindScript = ` <!-- Tailwind CSS CDN for visual editing -->\n <script src="https://cdn.tailwindcss.com"></script>\n `;
112
15
  return html.replace("</head>", tailwindScript + "</head>");
113
16
  },
114
17
  transform(code, id) {
115
- // Skip node_modules and visual-edit-agent itself
116
18
  if (id.includes("node_modules") || id.includes("visual-edit-agent")) {
117
19
  return null;
118
20
  }
119
- // Process JS/JSX/TS/TSX files
120
21
  if (!id.match(/\.(jsx?|tsx?)$/)) {
121
22
  return null;
122
23
  }
123
- // Extract filename from path, preserving pages/ or components/ structure
124
- const pathParts = id.split("/");
125
- let filename;
126
- // Check if this is a pages or components file
127
- if (id.includes("/pages/")) {
128
- const pagesIndex = pathParts.findIndex((part) => part === "pages");
129
- if (pagesIndex >= 0 && pagesIndex < pathParts.length - 1) {
130
- // Get all parts from 'pages' to the file, preserving nested structure
131
- const relevantParts = pathParts.slice(pagesIndex, pathParts.length);
132
- const lastPart = relevantParts[relevantParts.length - 1];
133
- // Remove file extension from the last part
134
- relevantParts[relevantParts.length - 1] = lastPart.includes(".")
135
- ? lastPart.split(".")[0]
136
- : lastPart;
137
- filename = relevantParts.join("/");
138
- }
139
- else {
140
- filename = pathParts[pathParts.length - 1];
141
- if (filename.includes(".")) {
142
- filename = filename.split(".")[0];
143
- }
144
- }
145
- }
146
- else if (id.includes("/components/")) {
147
- const componentsIndex = pathParts.findIndex((part) => part === "components");
148
- if (componentsIndex >= 0 && componentsIndex < pathParts.length - 1) {
149
- // Get all parts from 'components' to the file, preserving nested structure
150
- const relevantParts = pathParts.slice(componentsIndex, pathParts.length);
151
- const lastPart = relevantParts[relevantParts.length - 1];
152
- // Remove file extension from the last part
153
- relevantParts[relevantParts.length - 1] = lastPart.includes(".")
154
- ? lastPart.split(".")[0]
155
- : lastPart;
156
- filename = relevantParts.join("/");
157
- }
158
- else {
159
- filename = pathParts[pathParts.length - 1];
160
- if (filename.includes(".")) {
161
- filename = filename.split(".")[0];
162
- }
163
- }
164
- }
165
- else {
166
- // For other files (like layout), just use the filename
167
- filename = pathParts[pathParts.length - 1];
168
- if (filename.includes(".")) {
169
- filename = filename.split(".")[0];
170
- }
171
- }
24
+ const filename = extractFilename(id);
172
25
  try {
173
- // Parse the code into an AST
174
26
  const ast = parse(code, {
175
27
  sourceType: "module",
176
28
  plugins: [
@@ -191,41 +43,16 @@ export function visualEditPlugin() {
191
43
  "throwExpressions",
192
44
  ],
193
45
  });
194
- // Traverse the AST and add source location and dynamic content attributes to JSX elements
195
46
  JSXUtils.init(t);
196
- const staticArrayProcessor = new StaticArrayProcessor(t);
197
- let elementsProcessed = 0;
47
+ const processor = new JSXProcessor(t, filename);
198
48
  traverse.default(ast, {
199
49
  JSXElement(path) {
200
50
  const jsxElement = path.node;
201
- const openingElement = jsxElement.openingElement;
202
- // Skip fragments
203
51
  if (t.isJSXFragment(jsxElement))
204
52
  return;
205
- // Skip if already has source location attribute
206
- const hasSourceLocation = openingElement.attributes.some((attr) => t.isJSXAttribute(attr) &&
207
- t.isJSXIdentifier(attr.name) &&
208
- attr.name.name === "data-source-location");
209
- if (hasSourceLocation)
210
- return;
211
- // Get line and column from AST node location
212
- const { line, column } = openingElement.loc?.start || {
213
- line: 1,
214
- column: 0,
215
- };
216
- // Create the source location attribute
217
- const sourceLocationAttr = t.jsxAttribute(t.jsxIdentifier("data-source-location"), t.stringLiteral(`${filename}:${line}:${column}`));
218
- // Check if element has dynamic content
219
- const isDynamic = checkIfElementHasDynamicContent(jsxElement);
220
- // Create the dynamic content attribute
221
- const dynamicContentAttr = t.jsxAttribute(t.jsxIdentifier("data-dynamic-content"), t.stringLiteral(isDynamic ? "true" : "false"));
222
- // Add both attributes to the beginning of the attributes array
223
- openingElement.attributes.unshift(sourceLocationAttr, dynamicContentAttr);
224
- staticArrayProcessor.process(path.get("openingElement"));
225
- elementsProcessed++;
53
+ processor.processJSXElement(path.get("openingElement"));
226
54
  },
227
55
  });
228
- // Generate the code back from the AST
229
56
  const result = generate.default(ast, {
230
57
  compact: false,
231
58
  concise: false,
@@ -239,11 +66,35 @@ export function visualEditPlugin() {
239
66
  catch (error) {
240
67
  console.error("Failed to add source location to JSX:", error);
241
68
  return {
242
- code: code, // Return original code on failure
69
+ code: code,
243
70
  map: null,
244
71
  };
245
72
  }
246
73
  },
247
74
  };
248
75
  }
76
+ function extractFilename(id) {
77
+ const pathParts = id.split("/");
78
+ const segmentIndex = findSegmentIndex(pathParts, ["pages", "components"]);
79
+ if (segmentIndex >= 0 && segmentIndex < pathParts.length - 1) {
80
+ const relevantParts = pathParts.slice(segmentIndex);
81
+ const last = relevantParts[relevantParts.length - 1];
82
+ relevantParts[relevantParts.length - 1] = stripExtension(last ?? "");
83
+ return relevantParts.join("/");
84
+ }
85
+ const lastPart = pathParts[pathParts.length - 1] ?? "";
86
+ return stripExtension(lastPart);
87
+ }
88
+ function findSegmentIndex(parts, segments) {
89
+ for (const segment of segments) {
90
+ const idx = parts.findIndex((part) => part === segment);
91
+ if (idx >= 0)
92
+ return idx;
93
+ }
94
+ return -1;
95
+ }
96
+ function stripExtension(filename) {
97
+ const dotIndex = filename.indexOf(".");
98
+ return dotIndex >= 0 ? filename.substring(0, dotIndex) : filename;
99
+ }
249
100
  //# sourceMappingURL=visual-edit-plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"visual-edit-plugin.js","sourceRoot":"","sources":["../src/visual-edit-plugin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"visual-edit-plugin.js","sourceRoot":"","sources":["../src/visual-edit-plugin.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44/vite-plugin",
3
- "version": "0.2.27",
3
+ "version": "0.2.29",
4
4
  "description": "The Vite plugin for base44 based applications",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -4,6 +4,7 @@ import {
4
4
  removeFocusOutlineCSS,
5
5
  selectText,
6
6
  shouldEnterInlineEditingMode,
7
+ isStaticArrayTextElement,
7
8
  } from "./dom-utils.js";
8
9
 
9
10
  const DEBOUNCE_MS = 500;
@@ -37,37 +38,42 @@ export function createInlineEditController(
37
38
  const svgElement = element as unknown as SVGElement;
38
39
  const rect = element.getBoundingClientRect();
39
40
 
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
- },
41
+ const message: Record<string, unknown> = {
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,
65
64
  },
66
- originalContent,
67
- newContent,
68
65
  },
69
- "*"
70
- );
66
+ originalContent,
67
+ newContent,
68
+ };
69
+
70
+ if (isStaticArrayTextElement(element)) {
71
+ message.arrIndex = element.dataset.arrIndex;
72
+ message.arrVariableName = element.dataset.arrVariableName;
73
+ message.arrField = element.dataset.arrField;
74
+ }
75
+
76
+ window.parent.postMessage(message, "*");
71
77
 
72
78
  element.dataset.originalTextContent = newContent || "";
73
79
  };
@@ -5,6 +5,18 @@ const EDITABLE_TAGS = [
5
5
  "span", "li", "td", "a", "button", "label",
6
6
  ];
7
7
 
8
+ export const isStaticArrayTextElement = (element: HTMLElement): boolean => {
9
+ return !!element.dataset.arrField;
10
+ };
11
+
12
+ const passesStructuralChecks = (element: HTMLElement): boolean => {
13
+ if (!EDITABLE_TAGS.includes(element.tagName.toLowerCase())) return false;
14
+ if (!element.textContent?.trim()) return false;
15
+ if (element.querySelector("img, video, canvas, svg")) return false;
16
+ if (element.children?.length > 0) return false;
17
+ return true;
18
+ };
19
+
8
20
  export const injectFocusOutlineCSS = () => {
9
21
  if (document.getElementById(FOCUS_STYLE_ID)) return;
10
22
 
@@ -32,10 +44,8 @@ export const selectText = (element: HTMLElement) => {
32
44
 
33
45
  export const isEditableTextElement = (element: Element): boolean => {
34
46
  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;
47
+ if (!passesStructuralChecks(element)) return false;
48
+ if (isStaticArrayTextElement(element)) return true;
39
49
  if (element.dataset.dynamicContent === "true") return false;
40
50
  return true;
41
51
  };
@@ -1,2 +1,2 @@
1
1
  export { createInlineEditController } from "./controller.js";
2
- export type { InlineEditController, InlineEditHost } from "./types.js";
2
+ export type { CollectionInfo, InlineEditController, InlineEditHost } from "./types.js";
@@ -1,3 +1,8 @@
1
+ export interface CollectionInfo {
2
+ id: string;
3
+ references: string[];
4
+ }
5
+
1
6
  export interface InlineEditHost {
2
7
  findElementsById(id: string | null): Element[];
3
8
  getSelectedElementId(): string | null;
package/src/consts.ts ADDED
@@ -0,0 +1,11 @@
1
+ export const DATA_COLLECTION_ID = "data-collection-id";
2
+ export const DATA_COLLECTION_ITEM_ID = "data-collection-item-id";
3
+ export const DATA_COLLECTION_ITEM_FIELD = "data-collection-item-field";
4
+ export const DATA_COLLECTION_REFERENCE = "data-collection-reference";
5
+ export const DATA_ARR_INDEX = "data-arr-index";
6
+ export const DATA_ARR_VARIABLE_NAME = "data-arr-variable-name";
7
+ export const DATA_ARR_FIELD = "data-arr-field";
8
+
9
+ export const ALLOWED_CUSTOM_COMPONENTS = ["Image", "Link"];
10
+ export const MAX_JSX_DEPTH = 10;
11
+ export const EXCLUDED_FIELDS = ["children", "length"];
@@ -127,6 +127,13 @@ export function setupVisualEditAgent() {
127
127
  const rect = element.getBoundingClientRect();
128
128
  const svgElement = element as SVGElement;
129
129
  const isTextElement = TEXT_TAGS.includes(element.tagName?.toLowerCase());
130
+
131
+ const arrEl = htmlElement.closest("[data-arr-variable-name]") as HTMLElement | null;
132
+ const staticArrayName = arrEl?.dataset?.arrVariableName || null;
133
+ const rawIdx = arrEl?.dataset?.arrIndex;
134
+ const staticArrayIndex = rawIdx != null ? parseInt(rawIdx, 10) : null;
135
+ const staticArrayField = htmlElement.dataset?.arrField || null;
136
+
130
137
  window.parent.postMessage({
131
138
  type: "element-selected",
132
139
  tagName: element.tagName,
@@ -152,6 +159,9 @@ export function setupVisualEditAgent() {
152
159
  },
153
160
  attributes: collectAllowedAttributes(element, ALLOWED_ATTRIBUTES),
154
161
  isTextElement,
162
+ staticArrayName,
163
+ staticArrayIndex,
164
+ staticArrayField,
155
165
  }, "*");
156
166
  };
157
167
 
@@ -378,14 +388,19 @@ export function setupVisualEditAgent() {
378
388
  }, REPOSITION_DELAY_MS);
379
389
  };
380
390
 
381
- // Update element content by visual selector ID
382
- const updateElementContent = (visualSelectorId: string, content: string) => {
383
- const elements = findElementsById(visualSelectorId);
391
+ const updateElementContent = (visualSelectorId: string, content: string, arrIndex?: number) => {
392
+ let elements = findElementsById(visualSelectorId);
384
393
 
385
394
  if (elements.length === 0) {
386
395
  return;
387
396
  }
388
397
 
398
+ if (arrIndex != null) {
399
+ elements = elements.filter(
400
+ (el) => (el as HTMLElement).dataset.arrIndex === String(arrIndex)
401
+ );
402
+ }
403
+
389
404
  elements.forEach((element) => {
390
405
  (element as HTMLElement).innerText = content;
391
406
  });
@@ -537,7 +552,8 @@ export function setupVisualEditAgent() {
537
552
  if (message.data && message.data.content !== undefined) {
538
553
  updateElementContent(
539
554
  message.data.visualSelectorId,
540
- message.data.content
555
+ message.data.content,
556
+ message.data.arrIndex
541
557
  );
542
558
  } else {
543
559
  console.warn(
@@ -604,6 +620,19 @@ export function setupVisualEditAgent() {
604
620
  }
605
621
  break;
606
622
 
623
+ case "update-theme-variables":
624
+ if (message.data?.variables) {
625
+ const target = message.data.mode === 'dark'
626
+ ? document.querySelector('.dark') as HTMLElement
627
+ : document.documentElement;
628
+ if (target) {
629
+ for (const [name, value] of Object.entries(message.data.variables)) {
630
+ target.style.setProperty(name, value as string);
631
+ }
632
+ }
633
+ }
634
+ break;
635
+
607
636
  case "toggle-inline-edit-mode":
608
637
  if (message.data) {
609
638
  inlineEdit.handleToggleMessage(message.data);
@@ -1,14 +1,23 @@
1
1
  import type { NodePath } from "@babel/traverse";
2
2
  import type * as t from "@babel/types";
3
+ import { CollectionIdProcessor } from "./processors/collection-id-processor.js";
4
+ import { DataItemIdProcessor } from "./processors/collection-item-id-processor.js";
5
+ import { DataItemFieldProcessor } from "./processors/collection-item-field-processor.js";
3
6
  import { StaticArrayProcessor } from "./processors/static-array-processor.js";
4
7
 
5
8
  export class JSXProcessor {
9
+ private collectionIdProcessor: CollectionIdProcessor;
10
+ private dataItemIdProcessor: DataItemIdProcessor;
11
+ private dataItemFieldProcessor: DataItemFieldProcessor;
6
12
  private staticArrayProcessor: StaticArrayProcessor;
7
13
 
8
14
  constructor(
9
15
  private types: typeof t,
10
16
  private filename: string
11
17
  ) {
18
+ this.collectionIdProcessor = new CollectionIdProcessor(types);
19
+ this.dataItemIdProcessor = new DataItemIdProcessor(types);
20
+ this.dataItemFieldProcessor = new DataItemFieldProcessor(types);
12
21
  this.staticArrayProcessor = new StaticArrayProcessor(types);
13
22
  }
14
23
 
@@ -17,7 +26,10 @@ export class JSXProcessor {
17
26
 
18
27
  this.addSourceLocationAttribute(path);
19
28
  this.addDynamicContentAttribute(path);
20
- this.addContentEditableAttribute(path);
29
+
30
+ this.collectionIdProcessor.process(path);
31
+ this.dataItemIdProcessor.process(path);
32
+ this.dataItemFieldProcessor.process(path);
21
33
  this.staticArrayProcessor.process(path);
22
34
  }
23
35
 
@@ -27,7 +39,7 @@ export class JSXProcessor {
27
39
  const { line, column } = path.node.loc?.start || { line: 1, column: 0 };
28
40
  const value = `${this.filename}:${line}:${column}`;
29
41
 
30
- path.node.attributes.push(
42
+ path.node.attributes.unshift(
31
43
  this.types.jsxAttribute(
32
44
  this.types.jsxIdentifier("data-source-location"),
33
45
  this.types.stringLiteral(value)
@@ -45,21 +57,19 @@ export class JSXProcessor {
45
57
  parentElement.node as t.JSXElement
46
58
  );
47
59
 
48
- path.node.attributes.push(
49
- this.types.jsxAttribute(
50
- this.types.jsxIdentifier("data-dynamic-content"),
51
- this.types.stringLiteral(isDynamic ? "true" : "false")
52
- )
60
+ const sourceLocIdx = path.node.attributes.findIndex(
61
+ (attr) =>
62
+ this.types.isJSXAttribute(attr) &&
63
+ this.types.isJSXIdentifier(attr.name) &&
64
+ attr.name.name === "data-source-location"
53
65
  );
54
- }
55
66
 
56
- private addContentEditableAttribute(
57
- path: NodePath<t.JSXOpeningElement>
58
- ): void {
59
- path.node.attributes.push(
67
+ path.node.attributes.splice(
68
+ sourceLocIdx + 1,
69
+ 0,
60
70
  this.types.jsxAttribute(
61
- this.types.jsxIdentifier("content-editable"),
62
- this.types.stringLiteral("true")
71
+ this.types.jsxIdentifier("data-dynamic-content"),
72
+ this.types.stringLiteral(isDynamic ? "true" : "false")
63
73
  )
64
74
  );
65
75
  }
@@ -137,6 +147,18 @@ export class JSXProcessor {
137
147
  }
138
148
  };
139
149
 
150
+ const attributes = jsxElement.openingElement?.attributes || [];
151
+ for (const attr of attributes) {
152
+ if (hasDynamicContent) break;
153
+ if (this.types.isJSXSpreadAttribute(attr)) {
154
+ hasDynamicContent = true;
155
+ break;
156
+ }
157
+ if (this.types.isJSXAttribute(attr) && attr.value) {
158
+ traverseNode(attr.value as unknown as Record<string, unknown>);
159
+ }
160
+ }
161
+
140
162
  for (const child of jsxElement.children) {
141
163
  if (hasDynamicContent) break;
142
164
  traverseNode(child as unknown as Record<string, unknown>);