@base44-preview/vite-plugin 1.0.20-pr.83.ee1eb29 → 1.0.20-pr.85.5e3dff7

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.83.ee1eb29",
3
+ "version": "1.0.20-pr.85.5e3dff7",
4
4
  "description": "The Vite plugin for base44 based applications",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,6 +32,12 @@ 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
+
35
41
  // Notify initial URL on load
36
42
  window.parent?.postMessage(
37
43
  {
@@ -82,21 +82,12 @@ 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(
86
- elements: Element[],
87
- attribute: string,
88
- value: string,
89
- arrIndex?: number | string
90
- ): void {
85
+ export function updateElementAttribute(elements: Element[], attribute: string, value: string): void {
91
86
  if (!ALLOWED_ATTRIBUTES.includes(attribute)) {
92
87
  return;
93
88
  }
94
89
 
95
- const targetElements = arrIndex != null
96
- ? elements.filter((element) => (element as HTMLElement).dataset.arrIndex === String(arrIndex))
97
- : elements;
98
-
99
- targetElements.forEach((element) => {
90
+ elements.forEach((element) => {
100
91
  element.setAttribute(attribute, value);
101
92
  });
102
93
  }
@@ -368,13 +368,12 @@ export function setupVisualEditAgent() {
368
368
  const updateElementAttributeAndReposition = (
369
369
  visualSelectorId: string,
370
370
  attribute: string,
371
- value: string,
372
- arrIndex?: number | string
371
+ value: string
373
372
  ) => {
374
373
  const elements = findElementsById(visualSelectorId);
375
374
  if (elements.length === 0) return;
376
375
 
377
- updateElementAttribute(elements, attribute, value, arrIndex);
376
+ updateElementAttribute(elements, attribute, value);
378
377
 
379
378
  // Reposition overlays after attribute change (e.g. image src swap can affect layout)
380
379
  setTimeout(() => {
@@ -506,6 +505,34 @@ export function setupVisualEditAgent() {
506
505
  }
507
506
  break;
508
507
 
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
+
509
536
  case "update-classes":
510
537
  if (message.data && message.data.classes !== undefined) {
511
538
  updateElementClassesAndReposition(
@@ -530,8 +557,7 @@ export function setupVisualEditAgent() {
530
557
  updateElementAttributeAndReposition(
531
558
  message.data.visualSelectorId,
532
559
  message.data.attribute,
533
- message.data.value,
534
- message.data.arrIndex
560
+ message.data.value
535
561
  );
536
562
  } else {
537
563
  console.warn(
@@ -69,9 +69,6 @@ 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
-
75
72
  const parentElement = path.parentPath;
76
73
  if (!parentElement?.isJSXElement()) return null;
77
74
 
@@ -83,36 +80,6 @@ export class StaticArrayProcessor {
83
80
  return null;
84
81
  }
85
82
 
86
- private findImageSrcFieldPath(
87
- path: NodePath<t.JSXOpeningElement>,
88
- callbackParam: string
89
- ): string | null {
90
- const elementName = this.getElementName(path);
91
- if (elementName !== "img" && elementName !== "Image") return null;
92
-
93
- for (const attr of path.node.attributes) {
94
- if (
95
- !this.types.isJSXAttribute(attr) ||
96
- !this.types.isJSXIdentifier(attr.name) ||
97
- attr.name.name !== "src" ||
98
- !attr.value ||
99
- !this.types.isJSXExpressionContainer(attr.value)
100
- ) {
101
- continue;
102
- }
103
-
104
- const expression = attr.value.expression;
105
- if (
106
- this.types.isMemberExpression(expression) ||
107
- this.types.isOptionalMemberExpression(expression)
108
- ) {
109
- return this.extractFieldPathFromExpression(expression, callbackParam);
110
- }
111
- }
112
-
113
- return null;
114
- }
115
-
116
83
  private extractFieldPathFromChild(
117
84
  child: NodePath<t.JSXElement["children"][number]>,
118
85
  callbackParam: string
@@ -125,17 +92,6 @@ export class StaticArrayProcessor {
125
92
  return this.extractFieldPath(expression, callbackParam);
126
93
  }
127
94
 
128
- private extractFieldPathFromExpression(
129
- expr: t.MemberExpression | t.OptionalMemberExpression,
130
- callbackParam: string
131
- ): string | null {
132
- const parts = this.collectMemberExpressionPartsFromNode(expr);
133
- if (!parts) return null;
134
-
135
- const { rootName, propertyNames } = parts;
136
- return rootName === callbackParam ? propertyNames.join(".") : null;
137
- }
138
-
139
95
  private extractFieldPath(
140
96
  expr: NodePath<t.MemberExpression>,
141
97
  callbackParam: string
@@ -166,35 +122,6 @@ export class StaticArrayProcessor {
166
122
  return { rootName: current.node.name, propertyNames };
167
123
  }
168
124
 
169
- private collectMemberExpressionPartsFromNode(
170
- expr: t.MemberExpression | t.OptionalMemberExpression
171
- ): { rootName: string; propertyNames: string[] } | null {
172
- const propertyNames: string[] = [];
173
- let current: t.Expression = expr;
174
-
175
- while (
176
- this.types.isMemberExpression(current) ||
177
- this.types.isOptionalMemberExpression(current)
178
- ) {
179
- const property = current.property;
180
- if (!this.types.isIdentifier(property)) return null;
181
-
182
- propertyNames.unshift(property.name);
183
- current = current.object as t.Expression;
184
- }
185
-
186
- if (!this.types.isIdentifier(current)) return null;
187
-
188
- return { rootName: current.name, propertyNames };
189
- }
190
-
191
- private getElementName(path: NodePath<t.JSXOpeningElement>): string | null {
192
- const name = path.node.name;
193
- if (this.types.isJSXIdentifier(name)) return name.name;
194
- if (this.types.isJSXMemberExpression(name)) return name.property.name;
195
- return null;
196
- }
197
-
198
125
  private ensureIndexParam(arrayInfo: ArrayMapInfo): string {
199
126
  if (arrayInfo.indexParam) {
200
127
  return arrayInfo.indexParam;