@base44-preview/vite-plugin 1.0.20-pr.85.5e3dff7 → 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.85.5e3dff7",
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,12 +32,6 @@ if (window.self !== window.top) {
32
32
  // Handle browser back/forward navigation
33
33
  window.addEventListener("popstate", notifyNavigation);
34
34
 
35
- // NOTE: parent-driven `navigate-to-route` (client-side navigation) is handled
36
- // in the visual-edit agent (`visual-edit-agent.ts`), not here, so it can also
37
- // clean up stale edit selection/overlays after the route change. The
38
- // `pushState` patch above still fires `app_changed_url` when the agent
39
- // navigates, so the parent gets its ack.
40
-
41
35
  // Notify initial URL on load
42
36
  window.parent?.postMessage(
43
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(() => {
@@ -505,34 +512,6 @@ export function setupVisualEditAgent() {
505
512
  }
506
513
  break;
507
514
 
508
- case "navigate-to-route": {
509
- // Parent-driven CLIENT-SIDE navigation (no document reload). The canvas
510
- // keeps a single pre-booted iframe and switches which page it shows by
511
- // posting this instead of swapping `src`. We pushState to the new path
512
- // and dispatch popstate so the app's router (React Router et al.)
513
- // re-renders the matched route. Handled HERE (in the visual-edit agent)
514
- // rather than navigation-notifier so we can also clean up edit state:
515
- // the previous route's selection/overlays point at now-detached nodes.
516
- // Accept both flat (`message.path`) and nested (`message.data.path`).
517
- const navPath = (message.data && message.data.path) || message.path;
518
- if (typeof navPath === "string" && navPath.startsWith("/")) {
519
- const replace = (message.data && message.data.replace) || message.replace;
520
- if (replace) {
521
- history.replaceState(history.state, "", navPath);
522
- } else {
523
- history.pushState(history.state, "", navPath);
524
- }
525
- window.dispatchEvent(new PopStateEvent("popstate"));
526
- // Drop stale selection/hover overlays from the previous page. The
527
- // agent's listeners are document-level (persist across client-side
528
- // nav) and elements carry build-injected data-source-location, so
529
- // selection keeps working on the new route without re-instrumenting.
530
- clearSelection();
531
- clearHoverOverlays();
532
- }
533
- break;
534
- }
535
-
536
515
  case "update-classes":
537
516
  if (message.data && message.data.classes !== undefined) {
538
517
  updateElementClassesAndReposition(
@@ -557,7 +536,8 @@ export function setupVisualEditAgent() {
557
536
  updateElementAttributeAndReposition(
558
537
  message.data.visualSelectorId,
559
538
  message.data.attribute,
560
- message.data.value
539
+ message.data.value,
540
+ message.data.arrIndex
561
541
  );
562
542
  } else {
563
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;