@base44-preview/vite-plugin 1.0.20-pr.82.75ad211 → 1.0.20-pr.83.15dfedc

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.82.75ad211",
3
+ "version": "1.0.20-pr.83.15dfedc",
4
4
  "description": "The Vite plugin for base44 based applications",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -82,16 +82,45 @@ 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(
86
+ elements: Element[],
87
+ attribute: string,
88
+ value: string,
89
+ arrIndex?: number | string
90
+ ): void {
86
91
  if (!ALLOWED_ATTRIBUTES.includes(attribute)) {
87
92
  return;
88
93
  }
89
94
 
90
- elements.forEach((element) => {
95
+ const targetElements = arrIndex != null
96
+ ? elements.filter((element) => (element as HTMLElement).dataset.arrIndex === String(arrIndex))
97
+ : elements;
98
+
99
+ targetElements.forEach((element) => {
91
100
  element.setAttribute(attribute, value);
92
101
  });
93
102
  }
94
103
 
104
+ export function resolveAttributeUpdateArrIndex(
105
+ explicitArrIndex: number | string | null | undefined,
106
+ selectedElement: Element | null,
107
+ selectedElementId: string | null,
108
+ visualSelectorId: string
109
+ ): number | string | undefined {
110
+ if (explicitArrIndex != null) {
111
+ return explicitArrIndex;
112
+ }
113
+
114
+ if (!selectedElement || selectedElementId !== visualSelectorId) {
115
+ return undefined;
116
+ }
117
+
118
+ const staticArrayElement = selectedElement.closest(
119
+ "[data-arr-index]"
120
+ ) as HTMLElement | null;
121
+ return staticArrayElement?.dataset.arrIndex;
122
+ }
123
+
95
124
  /** Collect attribute values from an element for a given allowlist. */
96
125
  export function collectAllowedAttributes(element: Element, allowedAttributes: string[]): Record<string, string> {
97
126
  const attributes: Record<string, string> = {};
@@ -1,4 +1,17 @@
1
- import { findElementsById, updateElementClasses, updateElementAttribute, collectAllowedAttributes, ALLOWED_ATTRIBUTES, getElementSelectorId, stopAnimations, resumeAnimations, findInstrumentedElement, resolveHoverTarget, positionLabel } from "./utils.js";
1
+ import {
2
+ findElementsById,
3
+ updateElementClasses,
4
+ updateElementAttribute,
5
+ resolveAttributeUpdateArrIndex,
6
+ collectAllowedAttributes,
7
+ ALLOWED_ATTRIBUTES,
8
+ getElementSelectorId,
9
+ stopAnimations,
10
+ resumeAnimations,
11
+ findInstrumentedElement,
12
+ resolveHoverTarget,
13
+ positionLabel,
14
+ } from "./utils.js";
2
15
  import { createLayerController } from "./layer-dropdown/controller.js";
3
16
  import { LAYER_DROPDOWN_ATTR } from "./layer-dropdown/consts.js";
4
17
  import { createInlineEditController } from "../capabilities/inline-edit/index.js";
@@ -368,12 +381,20 @@ export function setupVisualEditAgent() {
368
381
  const updateElementAttributeAndReposition = (
369
382
  visualSelectorId: string,
370
383
  attribute: string,
371
- value: string
384
+ value: string,
385
+ arrIndex?: number | string
372
386
  ) => {
373
387
  const elements = findElementsById(visualSelectorId);
374
388
  if (elements.length === 0) return;
375
389
 
376
- updateElementAttribute(elements, attribute, value);
390
+ const targetArrIndex = resolveAttributeUpdateArrIndex(
391
+ arrIndex,
392
+ selectedElement,
393
+ selectedElementId,
394
+ visualSelectorId
395
+ );
396
+
397
+ updateElementAttribute(elements, attribute, value, targetArrIndex);
377
398
 
378
399
  // Reposition overlays after attribute change (e.g. image src swap can affect layout)
379
400
  setTimeout(() => {
@@ -529,7 +550,8 @@ export function setupVisualEditAgent() {
529
550
  updateElementAttributeAndReposition(
530
551
  message.data.visualSelectorId,
531
552
  message.data.attribute,
532
- message.data.value
553
+ message.data.value,
554
+ message.data.arrIndex
533
555
  );
534
556
  } else {
535
557
  console.warn(
@@ -652,20 +674,17 @@ export function setupVisualEditAgent() {
652
674
  ? message.referenceVhBase
653
675
  : undefined
654
676
  );
655
- postAckIfRequested(event, message);
656
677
  break;
657
678
 
658
679
  case "measure-page-height":
659
680
  pageHeightBridge.measurePageHeight(
660
- safeAckOrigin(event),
681
+ event.origin && event.origin !== "null" ? event.origin : "*",
661
682
  typeof message.settleMs === "number" ? message.settleMs : undefined
662
683
  );
663
- postAckIfRequested(event, message);
664
684
  break;
665
685
 
666
686
  case "suppress-auto-popups":
667
687
  autoPopupSuppressor.suppress();
668
- postAckIfRequested(event, message);
669
688
  break;
670
689
 
671
690
  case "toggle-canvas-wheel-zoom-bridge":
@@ -758,22 +777,3 @@ export function setupVisualEditAgent() {
758
777
  // Send ready message to parent
759
778
  window.parent.postMessage({ type: "visual-edit-agent-ready" }, "*");
760
779
  }
761
-
762
- // "*" fallback covers jsdom (empty origin) and sandboxed iframes (literal "null").
763
- export function safeAckOrigin(event: MessageEvent): string {
764
- return event.origin && event.origin !== "null" ? event.origin : "*";
765
- }
766
-
767
- // Echoes `<type>:ack` to the parent when the incoming message includes a
768
- // reqId. No-op without reqId — keeps senders that don't expect acks working.
769
- export function postAckIfRequested(
770
- event: MessageEvent,
771
- message: { type?: unknown; reqId?: unknown },
772
- ): void {
773
- if (typeof message.reqId !== "string") return;
774
- if (typeof message.type !== "string") return;
775
- window.parent.postMessage(
776
- { type: `${message.type}:ack`, reqId: message.reqId },
777
- safeAckOrigin(event),
778
- );
779
- }
@@ -4,6 +4,7 @@ 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
 
@@ -69,6 +70,9 @@ export class StaticArrayProcessor {
69
70
  path: NodePath<t.JSXOpeningElement>,
70
71
  callbackParam: string
71
72
  ): string | null {
73
+ const imageSrcFieldPath = this.findImageSrcFieldPath(path, callbackParam);
74
+ if (imageSrcFieldPath) return imageSrcFieldPath;
75
+
72
76
  const parentElement = path.parentPath;
73
77
  if (!parentElement?.isJSXElement()) return null;
74
78
 
@@ -80,6 +84,36 @@ export class StaticArrayProcessor {
80
84
  return null;
81
85
  }
82
86
 
87
+ private findImageSrcFieldPath(
88
+ path: NodePath<t.JSXOpeningElement>,
89
+ callbackParam: string
90
+ ): string | null {
91
+ const elementName = this.getElementName(path);
92
+ if (elementName !== "img" && elementName !== "Image") return null;
93
+
94
+ for (const attr of path.node.attributes) {
95
+ if (
96
+ !this.types.isJSXAttribute(attr) ||
97
+ !this.types.isJSXIdentifier(attr.name) ||
98
+ attr.name.name !== "src" ||
99
+ !attr.value ||
100
+ !this.types.isJSXExpressionContainer(attr.value)
101
+ ) {
102
+ continue;
103
+ }
104
+
105
+ const expression = attr.value.expression;
106
+ if (
107
+ this.types.isMemberExpression(expression) ||
108
+ this.types.isOptionalMemberExpression(expression)
109
+ ) {
110
+ return this.extractFieldPathFromExpression(expression, callbackParam);
111
+ }
112
+ }
113
+
114
+ return null;
115
+ }
116
+
83
117
  private extractFieldPathFromChild(
84
118
  child: NodePath<t.JSXElement["children"][number]>,
85
119
  callbackParam: string
@@ -92,6 +126,52 @@ export class StaticArrayProcessor {
92
126
  return this.extractFieldPath(expression, callbackParam);
93
127
  }
94
128
 
129
+ private extractFieldPathFromExpression(
130
+ expr: t.MemberExpression | t.OptionalMemberExpression,
131
+ callbackParam: string
132
+ ): string | null {
133
+ const lookupName = this.extractStaticLookupName(expr, callbackParam);
134
+ if (lookupName) return lookupName;
135
+
136
+ const parts = this.collectMemberExpressionPartsFromNode(expr);
137
+ if (!parts) return null;
138
+
139
+ const { rootName, propertyNames } = parts;
140
+ return rootName === callbackParam ? propertyNames.join(".") : null;
141
+ }
142
+
143
+ private extractStaticLookupName(
144
+ expr: t.MemberExpression | t.OptionalMemberExpression,
145
+ callbackParam: string
146
+ ): string | null {
147
+ if (!expr.computed) return null;
148
+ if (
149
+ !this.types.isIdentifier(expr.object)
150
+ ) {
151
+ return null;
152
+ }
153
+
154
+ if (
155
+ this.types.isIdentifier(expr.property) &&
156
+ expr.property.name === callbackParam
157
+ ) {
158
+ return expr.object.name;
159
+ }
160
+
161
+ if (
162
+ this.types.isMemberExpression(expr.property) ||
163
+ this.types.isOptionalMemberExpression(expr.property)
164
+ ) {
165
+ const keyFieldPath = this.extractFieldPathFromExpression(
166
+ expr.property,
167
+ callbackParam
168
+ );
169
+ return keyFieldPath ? `${expr.object.name}[${keyFieldPath}]` : null;
170
+ }
171
+
172
+ return null;
173
+ }
174
+
95
175
  private extractFieldPath(
96
176
  expr: NodePath<t.MemberExpression>,
97
177
  callbackParam: string
@@ -122,6 +202,35 @@ export class StaticArrayProcessor {
122
202
  return { rootName: current.node.name, propertyNames };
123
203
  }
124
204
 
205
+ private collectMemberExpressionPartsFromNode(
206
+ expr: t.MemberExpression | t.OptionalMemberExpression
207
+ ): { rootName: string; propertyNames: string[] } | null {
208
+ const propertyNames: string[] = [];
209
+ let current: t.Expression = expr;
210
+
211
+ while (
212
+ this.types.isMemberExpression(current) ||
213
+ this.types.isOptionalMemberExpression(current)
214
+ ) {
215
+ const property = current.property;
216
+ if (!this.types.isIdentifier(property)) return null;
217
+
218
+ propertyNames.unshift(property.name);
219
+ current = current.object as t.Expression;
220
+ }
221
+
222
+ if (!this.types.isIdentifier(current)) return null;
223
+
224
+ return { rootName: current.name, propertyNames };
225
+ }
226
+
227
+ private getElementName(path: NodePath<t.JSXOpeningElement>): string | null {
228
+ const name = path.node.name;
229
+ if (this.types.isJSXIdentifier(name)) return name.name;
230
+ if (this.types.isJSXMemberExpression(name)) return name.property.name;
231
+ return null;
232
+ }
233
+
125
234
  private ensureIndexParam(arrayInfo: ArrayMapInfo): string {
126
235
  if (arrayInfo.indexParam) {
127
236
  return arrayInfo.indexParam;
@@ -156,7 +265,7 @@ export class StaticArrayProcessor {
156
265
 
157
266
  private findParentArrayMap(
158
267
  path: NodePath<t.JSXOpeningElement>,
159
- maxDepth: number = 5
268
+ maxDepth: number = MAX_JSX_DEPTH
160
269
  ): ArrayMapInfo | null {
161
270
  let currentPath: NodePath = path;
162
271
  let depth = 0;