@vectoriox/iox-builder 1.4.35 → 1.4.36

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.
@@ -348,6 +348,8 @@ class DragEngineService {
348
348
  this._flipEls = new Set();
349
349
  // ── Viewport scale ────────────────────────────────────────
350
350
  this._scale = 1;
351
+ // ── Dropzone rect cache — snapshotted at drag start and on scroll ─────────
352
+ this._dropzoneRectCache = new Map();
351
353
  // ── Root-escape ───────────────────────────────────────────
352
354
  this.ROOT_ESCAPE_PX = 14;
353
355
  this._rootEscapeActiveFor = null;
@@ -403,6 +405,14 @@ class DragEngineService {
403
405
  }
404
406
  /** Called by BuilderComponent whenever the viewport scale changes. */
405
407
  setScale(scale) { this._scale = scale; }
408
+ _snapshotRects() {
409
+ this._dropzoneRectCache.clear();
410
+ for (const id of this.ids) {
411
+ const el = this._getEl(id);
412
+ if (el)
413
+ this._dropzoneRectCache.set(id, el.getBoundingClientRect());
414
+ }
415
+ }
406
416
  // ─────────────────────────────────────────────────────────
407
417
  // Element lookup — elMap first, DOM id fallback
408
418
  // ─────────────────────────────────────────────────────────
@@ -558,6 +568,7 @@ class DragEngineService {
558
568
  this._createExternalChip(this._payload, event.client.x, event.client.y);
559
569
  el.classList.add('iox-drag-source');
560
570
  }
571
+ this._snapshotRects();
561
572
  }
562
573
  _onDragMove(event) {
563
574
  this._lastPointerX = event.client.x;
@@ -652,7 +663,7 @@ class DragEngineService {
652
663
  // whose DOM element lives inside the dragged source wrapper.
653
664
  if (this._sourceEl?.contains(el))
654
665
  continue;
655
- const rect = el.getBoundingClientRect();
666
+ const rect = this._dropzoneRectCache.get(id) ?? el.getBoundingClientRect();
656
667
  if (px >= rect.left && px <= rect.right && py >= rect.top && py <= rect.bottom) {
657
668
  const area = rect.width * rect.height;
658
669
  if (area < bestArea) {
@@ -674,7 +685,7 @@ class DragEngineService {
674
685
  if (this._rootEscapeActiveFor) {
675
686
  const escEl = this._getEl(this._rootEscapeActiveFor);
676
687
  if (escEl) {
677
- const r = escEl.getBoundingClientRect();
688
+ const r = this._dropzoneRectCache.get(this._rootEscapeActiveFor) ?? escEl.getBoundingClientRect();
678
689
  const inside = px >= r.left && px <= r.right && py >= r.top && py <= r.bottom;
679
690
  if (inside) {
680
691
  bestId = 'canvas-preview';
@@ -691,7 +702,7 @@ class DragEngineService {
691
702
  bestId && bestId !== 'canvas-preview' && this._isRootContainer(bestId)) {
692
703
  const el = this._getEl(bestId);
693
704
  if (el) {
694
- const rect = el.getBoundingClientRect();
705
+ const rect = this._dropzoneRectCache.get(bestId) ?? el.getBoundingClientRect();
695
706
  const nearEdge = py <= rect.top + this.ROOT_ESCAPE_PX ||
696
707
  py >= rect.bottom - this.ROOT_ESCAPE_PX;
697
708
  // Only escape if we were already targeting this section or
@@ -731,6 +742,7 @@ class DragEngineService {
731
742
  refreshDragOverlays() {
732
743
  if (!this._isDragging)
733
744
  return;
745
+ this._snapshotRects();
734
746
  this._moveTargetOverlay(this._deepTargetId);
735
747
  }
736
748
  _moveTargetOverlay(targetId) {
@@ -2613,6 +2625,11 @@ class OverlayComponent {
2613
2625
  this.moreMenuStyle = {};
2614
2626
  this.subs = [];
2615
2627
  this.boundUpdate = () => this.updateAll();
2628
+ this._scrollRaf = 0;
2629
+ this.boundScrollUpdate = () => {
2630
+ cancelAnimationFrame(this._scrollRaf);
2631
+ this._scrollRaf = requestAnimationFrame(() => this.updateAll());
2632
+ };
2616
2633
  this.activeScrollContainer = null;
2617
2634
  }
2618
2635
  ngOnInit() {
@@ -2647,9 +2664,9 @@ class OverlayComponent {
2647
2664
  // its wrapper element after each raf tick — listen to that to reposition
2648
2665
  // overlay boxes as the canvas scrolls.
2649
2666
  this.subs.push(this.overlayService.scrollContainer$.subscribe(el => {
2650
- this.activeScrollContainer?.removeEventListener('scroll', this.boundUpdate);
2667
+ this.activeScrollContainer?.removeEventListener('scroll', this.boundScrollUpdate);
2651
2668
  this.activeScrollContainer = el;
2652
- el.addEventListener('scroll', this.boundUpdate, { passive: true });
2669
+ el.addEventListener('scroll', this.boundScrollUpdate, { passive: true });
2653
2670
  }));
2654
2671
  // Open the more menu when a canvas element is right-clicked.
2655
2672
  this.subs.push(this.overlayService.contextMenu$.subscribe(({ x, y }) => {
@@ -2663,8 +2680,9 @@ class OverlayComponent {
2663
2680
  this.resizeObserver?.disconnect();
2664
2681
  this.containerResizeObserver?.disconnect();
2665
2682
  this.mutationObserver?.disconnect();
2683
+ cancelAnimationFrame(this._scrollRaf);
2666
2684
  window.removeEventListener('resize', this.boundUpdate);
2667
- this.activeScrollContainer?.removeEventListener('scroll', this.boundUpdate);
2685
+ this.activeScrollContainer?.removeEventListener('scroll', this.boundScrollUpdate);
2668
2686
  this.activeScrollContainer = null;
2669
2687
  }
2670
2688
  // ── Toolbar actions ──────────────────────────────────────