@base44-preview/vite-plugin 1.0.20-pr.84.a80f99c → 1.0.21-pr.86.3f04404

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/vite-plugin",
3
- "version": "1.0.20-pr.84.a80f99c",
3
+ "version": "1.0.21-pr.86.3f04404",
4
4
  "description": "The Vite plugin for base44 based applications",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,26 +32,6 @@ if (window.self !== window.top) {
32
32
  // Handle browser back/forward navigation
33
33
  window.addEventListener("popstate", notifyNavigation);
34
34
 
35
- // Parent-driven CLIENT-SIDE navigation (no full reload). The canvas keeps a
36
- // single pre-booted iframe and switches which page it shows by posting
37
- // `navigate-to-route` instead of swapping `src`. We pushState (or replaceState)
38
- // to the new path and dispatch a synthetic popstate so client routers
39
- // (React Router et al.) re-render the matched route. `pushState`/`replaceState`
40
- // are already patched above to fire `notifyNavigation`, so the parent still
41
- // receives the resulting `app_changed_url` ack and can confirm the switch.
42
- window.addEventListener("message", (event) => {
43
- const data = event.data;
44
- if (!data || data.type !== "navigate-to-route") return;
45
- const path = data.path;
46
- if (typeof path !== "string" || !path.startsWith("/")) return;
47
- if (data.replace) {
48
- history.replaceState(history.state, "", path);
49
- } else {
50
- history.pushState(history.state, "", path);
51
- }
52
- window.dispatchEvent(new PopStateEvent("popstate"));
53
- });
54
-
55
35
  // Notify initial URL on load
56
36
  window.parent?.postMessage(
57
37
  {
@@ -82,13 +82,19 @@ export function updateElementClasses(elements: Element[], classes: string): void
82
82
  }
83
83
 
84
84
  /** Set a single attribute on all provided elements. */
85
- export function updateElementAttribute(elements: Element[], attribute: string, value: string): void {
85
+ export function updateElementAttribute(elements: Element[], attribute: string, value: string, arrIndex?: number | string): void {
86
86
  if (!ALLOWED_ATTRIBUTES.includes(attribute)) {
87
87
  return;
88
88
  }
89
89
 
90
+ const targetArrIndex = arrIndex != null ? String(arrIndex) : null;
90
91
  elements.forEach((element) => {
91
- element.setAttribute(attribute, value);
92
+ if (
93
+ targetArrIndex === null ||
94
+ (element as HTMLElement).dataset.arrIndex === targetArrIndex
95
+ ) {
96
+ element.setAttribute(attribute, value);
97
+ }
92
98
  });
93
99
  }
94
100
 
@@ -368,12 +368,19 @@ export function setupVisualEditAgent() {
368
368
  const updateElementAttributeAndReposition = (
369
369
  visualSelectorId: string,
370
370
  attribute: string,
371
- value: string
371
+ value: string,
372
+ arrIndex?: number | string
372
373
  ) => {
373
374
  const elements = findElementsById(visualSelectorId);
374
375
  if (elements.length === 0) return;
375
376
 
376
- updateElementAttribute(elements, attribute, value);
377
+ const targetArrIndex =
378
+ arrIndex ??
379
+ (selectedElementId === visualSelectorId
380
+ ? (selectedElement as HTMLElement | null)?.dataset.arrIndex
381
+ : undefined);
382
+
383
+ updateElementAttribute(elements, attribute, value, targetArrIndex);
377
384
 
378
385
  // Reposition overlays after attribute change (e.g. image src swap can affect layout)
379
386
  setTimeout(() => {
@@ -529,7 +536,8 @@ export function setupVisualEditAgent() {
529
536
  updateElementAttributeAndReposition(
530
537
  message.data.visualSelectorId,
531
538
  message.data.attribute,
532
- message.data.value
539
+ message.data.value,
540
+ message.data.arrIndex
533
541
  );
534
542
  } else {
535
543
  console.warn(
@@ -4,10 +4,10 @@ import {
4
4
  DATA_ARR_INDEX,
5
5
  DATA_ARR_VARIABLE_NAME,
6
6
  DATA_ARR_FIELD,
7
+ MAX_JSX_DEPTH,
7
8
  } from "../consts.js";
8
9
  import { JSXAttributeUtils, StaticValueUtils } from "./utils/shared-utils.js";
9
10
 
10
-
11
11
  const GENERATED_INDEX_PARAM = "__arrIdx__";
12
12
 
13
13
  interface ArrayMapInfo {
@@ -69,6 +69,9 @@ export class StaticArrayProcessor {
69
69
  path: NodePath<t.JSXOpeningElement>,
70
70
  callbackParam: string
71
71
  ): string | null {
72
+ const imageSrcFieldPath = this.findImageSrcFieldPath(path, callbackParam);
73
+ if (imageSrcFieldPath) return imageSrcFieldPath;
74
+
72
75
  const parentElement = path.parentPath;
73
76
  if (!parentElement?.isJSXElement()) return null;
74
77
 
@@ -80,6 +83,35 @@ export class StaticArrayProcessor {
80
83
  return null;
81
84
  }
82
85
 
86
+ private findImageSrcFieldPath(
87
+ path: NodePath<t.JSXOpeningElement>,
88
+ callbackParam: string
89
+ ): string | null {
90
+ const elementName = this.types.isJSXIdentifier(path.node.name)
91
+ ? path.node.name.name
92
+ : null;
93
+ if (elementName !== "img" && elementName !== "Image") return null;
94
+
95
+ for (const attr of path.get("attributes")) {
96
+ if (!attr.isJSXAttribute()) continue;
97
+
98
+ const attrName = attr.get("name");
99
+ if (!attrName.isJSXIdentifier() || attrName.node.name !== "src") {
100
+ continue;
101
+ }
102
+
103
+ const value = attr.get("value");
104
+ if (!value.isJSXExpressionContainer()) return null;
105
+
106
+ const expression = value.get("expression");
107
+ if (!expression.isMemberExpression()) return null;
108
+
109
+ return this.extractFieldPath(expression, callbackParam);
110
+ }
111
+
112
+ return null;
113
+ }
114
+
83
115
  private extractFieldPathFromChild(
84
116
  child: NodePath<t.JSXElement["children"][number]>,
85
117
  callbackParam: string
@@ -96,6 +128,9 @@ export class StaticArrayProcessor {
96
128
  expr: NodePath<t.MemberExpression>,
97
129
  callbackParam: string
98
130
  ): string | null {
131
+ const keyedLookup = this.extractKeyedLookupFieldPath(expr, callbackParam);
132
+ if (keyedLookup) return keyedLookup;
133
+
99
134
  const parts = this.collectMemberExpressionParts(expr);
100
135
  if (!parts) return null;
101
136
 
@@ -103,6 +138,20 @@ export class StaticArrayProcessor {
103
138
  return rootName === callbackParam ? propertyNames.join(".") : null;
104
139
  }
105
140
 
141
+ private extractKeyedLookupFieldPath(
142
+ expr: NodePath<t.MemberExpression>,
143
+ callbackParam: string
144
+ ): string | null {
145
+ const object = expr.get("object");
146
+ if (!expr.node.computed || !object.isIdentifier()) return null;
147
+
148
+ const property = expr.get("property");
149
+ if (!property.isMemberExpression()) return null;
150
+
151
+ const keyFieldPath = this.extractFieldPath(property, callbackParam);
152
+ return keyFieldPath ? `${object.node.name}[${keyFieldPath}]` : null;
153
+ }
154
+
106
155
  private collectMemberExpressionParts(
107
156
  expr: NodePath<t.MemberExpression>
108
157
  ): { rootName: string; propertyNames: string[] } | null {
@@ -156,7 +205,7 @@ export class StaticArrayProcessor {
156
205
 
157
206
  private findParentArrayMap(
158
207
  path: NodePath<t.JSXOpeningElement>,
159
- maxDepth: number = 5
208
+ maxDepth: number = MAX_JSX_DEPTH
160
209
  ): ArrayMapInfo | null {
161
210
  let currentPath: NodePath = path;
162
211
  let depth = 0;