@base44/vite-plugin 1.0.13 → 1.0.15

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.
@@ -3,12 +3,13 @@
3
3
  // fire on their own.
4
4
  //
5
5
  // parent → child { type: "freeze-vh-units", referenceVhBase?: number }
6
- // Rewrites every `vh` in <style> + CSSOM to fixed `px` (kills the
7
- // vh ↔ auto-resize feedback loop). Idempotent; covers HMR-added
8
- // styles too. Fire-and-forget.
6
+ // Rewrites every `vh` in <style> + CSSOM to a CSS variable-backed
7
+ // expression (kills the vh ↔ auto-resize feedback loop). Repeated calls
8
+ // update the variable, so callers can rebase without recovering raw CSS.
9
+ // Idempotent; covers HMR-added styles too. Fire-and-forget.
9
10
  //
10
11
  // parent → child { type: "measure-page-height", settleMs?: number }
11
- // After `settleMs` (default 2000) posts the page's scrollHeight back
12
+ // After `settleMs` (default 2000) posts the page's measured content height
12
13
  // as `{ type: "page-height-measured", height }` to the requester.
13
14
 
14
15
  type IncomingMessage = {
@@ -34,6 +35,7 @@ const FALLBACK_VHBASE: number = 900;
34
35
  const MIN_VHBASE: number = 400;
35
36
  const DEFAULT_SETTLE_MS: number = 2000;
36
37
  const NEUTRALIZE_DEBOUNCE_MS: number = 16;
38
+ const REFERENCE_VH_BASE_VAR: string = "--base44-reference-vh-base";
37
39
 
38
40
  const noop: () => void = (): void => {};
39
41
 
@@ -94,13 +96,14 @@ export function createPageHeightBridgeController(): PageHeightBridgeController {
94
96
 
95
97
  return {
96
98
  freezeVhUnits: (override: number | undefined): void => {
99
+ const referenceVhBase: number = resolveReferenceVhBase(override);
100
+ setReferenceVhBase(referenceVhBase);
97
101
  if (vhCleanups) {
98
102
  vhForceRun?.();
99
103
  return;
100
104
  }
101
- const referenceVhBase: number = resolveReferenceVhBase(override);
102
105
  vhCleanups = [];
103
- vhForceRun = startVhNeutralizer(referenceVhBase, vhCleanups);
106
+ vhForceRun = startVhNeutralizer(vhCleanups);
104
107
  },
105
108
 
106
109
  // Target the requester's origin so the height isn't broadcast to anyone
@@ -134,15 +137,16 @@ function resolveReferenceVhBase(override: number | undefined): number {
134
137
  return detected >= MIN_VHBASE ? detected : FALLBACK_VHBASE;
135
138
  }
136
139
 
140
+ function setReferenceVhBase(referenceVhBase: number): void {
141
+ document.documentElement.style.setProperty(REFERENCE_VH_BASE_VAR, `${referenceVhBase}px`);
142
+ }
143
+
137
144
  // Caches keep work proportional to *new* CSS, not total CSS. <head> observer
138
145
  // catches `<style>`/`<link>` adds; per-element observers catch HMR text edits.
139
146
  // Returns a `forceRun` so the caller can re-trigger neutralization on later
140
147
  // parent requests (idempotent — already-rewritten text is skipped via the
141
148
  // processed sets).
142
- function startVhNeutralizer(
143
- referenceVhBase: number,
144
- cleanups: Array<() => void>,
145
- ): () => void {
149
+ function startVhNeutralizer(cleanups: Array<() => void>): () => void {
146
150
  const VH_RE: RegExp = /(\d+(?:\.\d+)?)vh\b/g;
147
151
  const processedStyles: WeakSet<HTMLStyleElement> = new WeakSet();
148
152
  const processedSheets: WeakMap<CSSStyleSheet, number> = new WeakMap();
@@ -152,7 +156,7 @@ function startVhNeutralizer(
152
156
  const neutralize = (): void => {
153
157
  const rewrite = (input: string): string =>
154
158
  input.replace(VH_RE, (_match: string, n: string): string =>
155
- `${((parseFloat(n) / 100) * referenceVhBase).toFixed(2)}px`,
159
+ `calc(var(${REFERENCE_VH_BASE_VAR}) * ${formatVhFactor(n)})`,
156
160
  );
157
161
 
158
162
  document.querySelectorAll<HTMLStyleElement>("style").forEach((el: HTMLStyleElement): void => {
@@ -230,6 +234,10 @@ function startVhNeutralizer(
230
234
  return debouncedNeutralize;
231
235
  }
232
236
 
237
+ function formatVhFactor(value: string): string {
238
+ return String(Number((parseFloat(value) / 100).toFixed(6)));
239
+ }
240
+
233
241
  function rewriteVhInRules(rules: CSSRuleList, rewrite: (value: string) => string): void {
234
242
  for (let i: number = 0; i < rules.length; i++) {
235
243
  const rule: IndexableCssRule | undefined = rules[i] as IndexableCssRule | undefined;
@@ -257,10 +265,88 @@ function containsStylesheetNode(nodes: NodeList): boolean {
257
265
  }
258
266
 
259
267
  function measureContentHeight(): number {
260
- return Math.max(
268
+ const scrollHeight: number = Math.max(
261
269
  document.documentElement.scrollHeight,
262
270
  document.body?.scrollHeight ?? 0,
263
271
  );
272
+ const viewportHeight: number = Math.max(
273
+ window.innerHeight || 0,
274
+ document.documentElement.clientHeight,
275
+ document.body?.clientHeight ?? 0,
276
+ );
277
+ const contentBottom: number = measureElementContentBottom(viewportHeight);
278
+ const referenceVhBase: number = readReferenceVhBase();
279
+ if (contentBottom > 0) return Math.ceil(Math.max(contentBottom, referenceVhBase));
280
+ return Math.ceil(Math.max(scrollHeight, referenceVhBase));
281
+ }
282
+
283
+ function readReferenceVhBase(): number {
284
+ const value: string = document.documentElement.style.getPropertyValue(REFERENCE_VH_BASE_VAR);
285
+ const parsed: number = parseFloat(value);
286
+ return Number.isFinite(parsed) ? parsed : 0;
287
+ }
288
+
289
+ function measureElementContentBottom(viewportHeight: number): number {
290
+ if (!document.body) return 0;
291
+ const elements: Element[] = [document.body, ...Array.from(document.body.querySelectorAll("*"))];
292
+ const contentBottoms: WeakMap<Element, number> = new WeakMap();
293
+ const viewportBottom: number = window.scrollY + viewportHeight;
294
+
295
+ for (let i: number = elements.length - 1; i >= 0; i--) {
296
+ const el: Element | undefined = elements[i];
297
+ if (!el) continue;
298
+ const childContentBottom: number = readChildrenContentBottom(el, contentBottoms);
299
+ const rawBottom: number = readElementBottom(el);
300
+ const selfBottom: number = isViewportStretchedContainer(rawBottom, childContentBottom, viewportBottom)
301
+ ? 0
302
+ : rawBottom;
303
+ contentBottoms.set(el, Math.max(childContentBottom, selfBottom));
304
+ }
305
+
306
+ return contentBottoms.get(document.body) ?? 0;
307
+ }
308
+
309
+ function readChildrenContentBottom(
310
+ el: Element,
311
+ contentBottoms: WeakMap<Element, number>,
312
+ ): number {
313
+ let childContentBottom: number = 0;
314
+ for (let i: number = 0; i < el.children.length; i++) {
315
+ const child: Element | undefined = el.children[i];
316
+ if (!child) continue;
317
+ childContentBottom = Math.max(childContentBottom, contentBottoms.get(child) ?? 0);
318
+ }
319
+ return childContentBottom;
320
+ }
321
+
322
+ function readElementBottom(el: Element): number {
323
+ const computedStyle: CSSStyleDeclaration = window.getComputedStyle(el);
324
+ if (isOutOfFlowDecoration(computedStyle)) return 0;
325
+ const rect: DOMRect = el.getBoundingClientRect();
326
+ if (rect.width === 0 && rect.height === 0) return 0;
327
+ return rect.bottom + window.scrollY + readMarginBottom(computedStyle);
328
+ }
329
+
330
+ function readMarginBottom(computedStyle: CSSStyleDeclaration): number {
331
+ const marginBottom: number = parseFloat(computedStyle.marginBottom);
332
+ return Number.isFinite(marginBottom) ? marginBottom : 0;
333
+ }
334
+
335
+ function isOutOfFlowDecoration(computedStyle: CSSStyleDeclaration): boolean {
336
+ if (computedStyle.position === "fixed") return true;
337
+ return computedStyle.position === "absolute" && computedStyle.pointerEvents === "none";
338
+ }
339
+
340
+ function isViewportStretchedContainer(
341
+ elementBottom: number,
342
+ childBottom: number,
343
+ viewportBottom: number,
344
+ ): boolean {
345
+ return (
346
+ childBottom > 0 &&
347
+ Math.abs(elementBottom - viewportBottom) <= 1 &&
348
+ elementBottom - childBottom > 8
349
+ );
264
350
  }
265
351
 
266
352
  function createDebouncer(fn: () => void, delayMs: number): Debouncer {
@@ -3,11 +3,13 @@ import { createLayerController } from "./layer-dropdown/controller.js";
3
3
  import { LAYER_DROPDOWN_ATTR } from "./layer-dropdown/consts.js";
4
4
  import { createInlineEditController } from "../capabilities/inline-edit/index.js";
5
5
  import { THEME_FONT_PREVIEW_ID } from "../consts.js";
6
+ import { createCanvasWheelZoomBridgeController } from "./canvas-wheel-zoom-bridge.js";
6
7
  import { createPageHeightBridgeController } from "./page-height-bridge.js";
7
8
 
8
9
  const REPOSITION_DELAY_MS = 50;
9
10
 
10
11
  export function setupVisualEditAgent() {
12
+ const canvasWheelZoomBridge = createCanvasWheelZoomBridgeController();
11
13
  const pageHeightBridge = createPageHeightBridgeController();
12
14
 
13
15
  // State variables (replacing React useState/useRef)
@@ -656,6 +658,10 @@ export function setupVisualEditAgent() {
656
658
  );
657
659
  break;
658
660
 
661
+ case "toggle-canvas-wheel-zoom-bridge":
662
+ canvasWheelZoomBridge.enable();
663
+ break;
664
+
659
665
  default:
660
666
  break;
661
667
  }