@vectoriox/iox-builder 1.7.10 → 1.7.12
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.
|
@@ -2588,11 +2588,16 @@ class MoveableCanvasService {
|
|
|
2588
2588
|
this.onReorder = null;
|
|
2589
2589
|
/** Called after a geometry commit (resize) so the host can emit LAYOUT_CHANGED (undo/save). */
|
|
2590
2590
|
this.onLayoutChanged = null;
|
|
2591
|
+
/** Preview device viewport size (CSS px) — reference for vw/vh unit conversion on resize. */
|
|
2592
|
+
this.viewportGetter = () => ({ width: 0, height: 0 });
|
|
2591
2593
|
}
|
|
2592
|
-
/** Wire the Moveable control box into `container`; `scaleGetter` returns the live canvas zoom
|
|
2593
|
-
|
|
2594
|
+
/** Wire the Moveable control box into `container`; `scaleGetter` returns the live canvas zoom;
|
|
2595
|
+
* `viewportGetter` returns the previewed device viewport size (for vw/vh resize conversion). */
|
|
2596
|
+
init(container, scaleGetter, viewportGetter) {
|
|
2594
2597
|
this.container = container;
|
|
2595
2598
|
this.scaleGetter = scaleGetter;
|
|
2599
|
+
if (viewportGetter)
|
|
2600
|
+
this.viewportGetter = viewportGetter;
|
|
2596
2601
|
}
|
|
2597
2602
|
/** Point Moveable at the selected element (skips inline-edit + preview-clone targets). */
|
|
2598
2603
|
select(element, node) {
|
|
@@ -2722,16 +2727,70 @@ class MoveableCanvasService {
|
|
|
2722
2727
|
return;
|
|
2723
2728
|
}
|
|
2724
2729
|
const last = e.lastEvent ?? e;
|
|
2725
|
-
const
|
|
2726
|
-
const
|
|
2727
|
-
// C2: geometry goes to styleProps (width/height) — never a transform:scale.
|
|
2728
|
-
|
|
2730
|
+
const wPx = last.width ?? el.getBoundingClientRect().width;
|
|
2731
|
+
const hPx = last.height ?? el.getBoundingClientRect().height;
|
|
2732
|
+
// C2: geometry goes to styleProps (width/height) — never a transform:scale. Keep the unit the
|
|
2733
|
+
// user CONFIGURED (%, vw, em, …) instead of always forcing px.
|
|
2734
|
+
this.applyStyle(this.node, {
|
|
2735
|
+
width: this.toConfiguredUnit(wPx, this.currentStyleValue('width'), el, 'width'),
|
|
2736
|
+
height: this.toConfiguredUnit(hPx, this.currentStyleValue('height'), el, 'height'),
|
|
2737
|
+
});
|
|
2729
2738
|
// Clear the transient inline size so the styleProps `.iox-node` rule drives it (single source).
|
|
2730
2739
|
el.style.width = '';
|
|
2731
2740
|
el.style.height = '';
|
|
2732
2741
|
this.onLayoutChanged?.();
|
|
2733
2742
|
setTimeout(() => this.moveable?.updateRect(), 0);
|
|
2734
2743
|
}
|
|
2744
|
+
/** The node's currently-configured value for a style trait (e.g. '100%', '120px'). */
|
|
2745
|
+
currentStyleValue(name) {
|
|
2746
|
+
for (const group of (this.node?.styleTraits ?? [])) {
|
|
2747
|
+
for (const trait of (group.traits ?? [])) {
|
|
2748
|
+
if (trait.name === name)
|
|
2749
|
+
return trait.default;
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
return undefined;
|
|
2753
|
+
}
|
|
2754
|
+
/** Convert a pixel measurement into the unit the user configured, so resizing from the canvas
|
|
2755
|
+
* preserves %, vw/vh, em/rem etc. instead of always writing px. */
|
|
2756
|
+
toConfiguredUnit(px, current, el, axis) {
|
|
2757
|
+
const round = (n) => Math.round(n * 100) / 100;
|
|
2758
|
+
const m = String(current ?? '').trim().match(/(px|%|vw|vh|vmin|vmax|rem|em)\s*$/);
|
|
2759
|
+
const unit = m ? m[1] : 'px';
|
|
2760
|
+
switch (unit) {
|
|
2761
|
+
case '%': {
|
|
2762
|
+
const ref = axis === 'width' ? (el.parentElement?.clientWidth ?? 0) : (el.parentElement?.clientHeight ?? 0);
|
|
2763
|
+
return ref > 0 ? `${round(px / ref * 100)}%` : `${Math.round(px)}px`;
|
|
2764
|
+
}
|
|
2765
|
+
case 'vw': {
|
|
2766
|
+
const vw = this.viewportGetter().width;
|
|
2767
|
+
return vw > 0 ? `${round(px / vw * 100)}vw` : `${Math.round(px)}px`;
|
|
2768
|
+
}
|
|
2769
|
+
case 'vh': {
|
|
2770
|
+
const vh = this.viewportGetter().height;
|
|
2771
|
+
return vh > 0 ? `${round(px / vh * 100)}vh` : `${Math.round(px)}px`;
|
|
2772
|
+
}
|
|
2773
|
+
case 'vmin': {
|
|
2774
|
+
const { width, height } = this.viewportGetter();
|
|
2775
|
+
const base = Math.min(width, height);
|
|
2776
|
+
return base > 0 ? `${round(px / base * 100)}vmin` : `${Math.round(px)}px`;
|
|
2777
|
+
}
|
|
2778
|
+
case 'vmax': {
|
|
2779
|
+
const { width, height } = this.viewportGetter();
|
|
2780
|
+
const base = Math.max(width, height);
|
|
2781
|
+
return base > 0 ? `${round(px / base * 100)}vmax` : `${Math.round(px)}px`;
|
|
2782
|
+
}
|
|
2783
|
+
case 'rem': {
|
|
2784
|
+
const fs = parseFloat(getComputedStyle(el.ownerDocument.documentElement).fontSize) || 16;
|
|
2785
|
+
return `${round(px / fs)}rem`;
|
|
2786
|
+
}
|
|
2787
|
+
case 'em': {
|
|
2788
|
+
const fs = parseFloat(getComputedStyle(el).fontSize) || 16;
|
|
2789
|
+
return `${round(px / fs)}em`;
|
|
2790
|
+
}
|
|
2791
|
+
default: return `${Math.round(px)}px`;
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2735
2794
|
/** Write geometry changes into the node's styleTraits (the serialized source of truth) and the
|
|
2736
2795
|
* central stylesheet, so the style panel, save (self-describing), and SSR engine all agree. */
|
|
2737
2796
|
applyStyle(node, changes) {
|
|
@@ -4363,7 +4422,7 @@ class BuilderComponent {
|
|
|
4363
4422
|
// element via Moveable, reusing DragEngineService.handleDrop for the reorder. See
|
|
4364
4423
|
// iox-ai-guidance/architecture/builder/moveable-migration.md.
|
|
4365
4424
|
if (this.moveableMode && this.previewCanvas?.nativeElement) {
|
|
4366
|
-
this.moveableCanvas.init(this.previewCanvas.nativeElement, () => this.viewportService.getScale());
|
|
4425
|
+
this.moveableCanvas.init(this.previewCanvas.nativeElement, () => this.viewportService.getScale(), () => ({ width: this.viewportWidth, height: this.viewportHeight }));
|
|
4367
4426
|
// Resize commits geometry to styleProps → emit LAYOUT_CHANGED so undo/save pick it up.
|
|
4368
4427
|
this.moveableCanvas.onLayoutChanged = () => this.panelEventService.emit(PanelEventTypes.LAYOUT_CHANGED, this.layout);
|
|
4369
4428
|
this.sub?.add(this.overlayService.select$.subscribe(entry => {
|
|
@@ -4444,6 +4503,10 @@ class BuilderComponent {
|
|
|
4444
4503
|
// Keep the fixed-position drop-target overlay aligned when canvas scrolls
|
|
4445
4504
|
// during an active drag (pointer doesn't move, so _onDragMove never fires).
|
|
4446
4505
|
this.dragEngine.refreshDragOverlays();
|
|
4506
|
+
// Reposition the Moveable control box (resize handles) on each scroll tick — otherwise
|
|
4507
|
+
// the handles drift away from the element as the canvas scrolls (the overlay outline
|
|
4508
|
+
// already repositions via the synthetic 'scroll' above).
|
|
4509
|
+
this.moveableCanvas.refresh();
|
|
4447
4510
|
});
|
|
4448
4511
|
const raf = (time) => {
|
|
4449
4512
|
this.lenis?.raf(time);
|