@vectoriox/iox-builder 3.3.2 → 3.3.3

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.
@@ -1189,6 +1189,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
1189
1189
  type: Injectable
1190
1190
  }] });
1191
1191
 
1192
+ // Ease-out-quint — fast start, precise stop, no overshoot. Used for FLIP sibling
1193
+ // reflow and the insertion indicator open/close. Deliberately NOT a spring/back
1194
+ // curve (e.g. cubic-bezier(0.34,1.56,0.64,1)): multiple siblings animating with
1195
+ // overshoot at once reads as jitter, not polish — reserve overshoot for single-
1196
+ // element motion (ghost drop-settle, a later phase).
1197
+ const MOTION_EASE = 'cubic-bezier(0.22, 1, 0.36, 1)';
1198
+ // Per-frame exponential smoothing factor for the drag ghost's cursor-follow.
1199
+ // Was: ghost position set 1:1 to the pointer every dragmove (rigid/teleporty).
1200
+ // Lower = more lag/weight, higher = snappier. 0.35 catches up to the pointer
1201
+ // within ~5-6 frames (~80-100ms) — reads as "responsive but weighted".
1202
+ const GHOST_FOLLOW_SMOOTHING = 0.35;
1192
1203
  function deepCloneNode(node) {
1193
1204
  const clone = JSON.parse(JSON.stringify(node));
1194
1205
  // Fresh ids + remap intra-subtree references (stateTriggers, interaction targets) so a cloned
@@ -1225,6 +1236,12 @@ class DragEngineService {
1225
1236
  /** Where on the element the user grabbed it (for accurate ghost positioning). */
1226
1237
  this._grabOffsetX = 0;
1227
1238
  this._grabOffsetY = 0;
1239
+ // ── Ghost cursor-follow (eased, not 1:1) ───────────────────
1240
+ this._ghostX = 0;
1241
+ this._ghostY = 0;
1242
+ this._ghostTargetX = 0;
1243
+ this._ghostTargetY = 0;
1244
+ this._ghostRaf = 0;
1228
1245
  // ── Pointer tracking ──────────────────────────────────────
1229
1246
  this._lastPointerX = 0;
1230
1247
  this._lastPointerY = 0;
@@ -1246,6 +1263,17 @@ class DragEngineService {
1246
1263
  // ── Root-escape ───────────────────────────────────────────
1247
1264
  this.ROOT_ESCAPE_PX = 14;
1248
1265
  this._rootEscapeActiveFor = null;
1266
+ this._ghostFollowStep = () => {
1267
+ if (!this._overlay) {
1268
+ this._ghostRaf = 0;
1269
+ return;
1270
+ }
1271
+ this._ghostX += (this._ghostTargetX - this._ghostX) * GHOST_FOLLOW_SMOOTHING;
1272
+ this._ghostY += (this._ghostTargetY - this._ghostY) * GHOST_FOLLOW_SMOOTHING;
1273
+ this._overlay.style.left = this._ghostX + 'px';
1274
+ this._overlay.style.top = this._ghostY + 'px';
1275
+ this._ghostRaf = requestAnimationFrame(this._ghostFollowStep);
1276
+ };
1249
1277
  }
1250
1278
  // ── Shared drop handler — used by all layout components ───────────────────
1251
1279
  handleDrop(children, event, dropListId, cdr, afterDrop) {
@@ -1482,6 +1510,7 @@ class DragEngineService {
1482
1510
  clone.classList.add('iox-drag-moving');
1483
1511
  document.body.appendChild(clone);
1484
1512
  this._overlay = clone;
1513
+ this._startGhostFollow(rect.left, rect.top);
1485
1514
  // Hide original wrapper in-place (keeps layout space so container size is stable).
1486
1515
  el.classList.add('iox-drag-active-source');
1487
1516
  }
@@ -1495,10 +1524,11 @@ class DragEngineService {
1495
1524
  _onDragMove(event) {
1496
1525
  this._lastPointerX = event.client.x;
1497
1526
  this._lastPointerY = event.client.y;
1498
- // Move the clone (or chip) under the cursor.
1527
+ // Update the ghost's follow target; the rAF loop (_ghostFollowStep) eases
1528
+ // the clone/chip toward it rather than snapping to it every dragmove.
1499
1529
  if (this._overlay) {
1500
- this._overlay.style.left = (event.client.x - this._grabOffsetX) + 'px';
1501
- this._overlay.style.top = (event.client.y - this._grabOffsetY) + 'px';
1530
+ this._ghostTargetX = event.client.x - this._grabOffsetX;
1531
+ this._ghostTargetY = event.client.y - this._grabOffsetY;
1502
1532
  }
1503
1533
  this._updateDeepTarget();
1504
1534
  this._updateIndicator();
@@ -1563,14 +1593,30 @@ class DragEngineService {
1563
1593
  chip.style.top = (pointerY + 14) + 'px';
1564
1594
  document.body.appendChild(chip);
1565
1595
  this._overlay = chip;
1596
+ this._startGhostFollow(pointerX + 14, pointerY + 14);
1566
1597
  }
1567
1598
  _removeOverlay() {
1599
+ this._stopGhostFollow();
1568
1600
  this._overlay?.remove();
1569
1601
  this._overlay = null;
1570
1602
  this._grabOffsetX = 0;
1571
1603
  this._grabOffsetY = 0;
1572
1604
  }
1573
1605
  // ─────────────────────────────────────────────────────────
1606
+ // Ghost cursor-follow — eased toward the pointer via rAF instead of
1607
+ // snapped to it every dragmove event.
1608
+ // ─────────────────────────────────────────────────────────
1609
+ _startGhostFollow(initialLeft, initialTop) {
1610
+ this._ghostX = this._ghostTargetX = initialLeft;
1611
+ this._ghostY = this._ghostTargetY = initialTop;
1612
+ cancelAnimationFrame(this._ghostRaf);
1613
+ this._ghostRaf = requestAnimationFrame(this._ghostFollowStep);
1614
+ }
1615
+ _stopGhostFollow() {
1616
+ cancelAnimationFrame(this._ghostRaf);
1617
+ this._ghostRaf = 0;
1618
+ }
1619
+ // ─────────────────────────────────────────────────────────
1574
1620
  // Deep-target detection (smallest bounding-rect area)
1575
1621
  // ─────────────────────────────────────────────────────────
1576
1622
  _updateDeepTarget() {
@@ -1767,13 +1813,13 @@ class DragEngineService {
1767
1813
  this._indicator.style.cssText =
1768
1814
  'flex-shrink:0;width:0;align-self:stretch;' +
1769
1815
  'background:#6366f1;border-radius:2px;pointer-events:none;margin:0;' +
1770
- 'transition:width 140ms ease,margin 140ms ease;overflow:hidden;';
1816
+ `transition:width 140ms ${MOTION_EASE},margin 140ms ${MOTION_EASE};overflow:hidden;`;
1771
1817
  }
1772
1818
  else {
1773
1819
  this._indicator.style.cssText =
1774
1820
  'height:0;width:100%;background:#6366f1;border-radius:2px;' +
1775
1821
  'pointer-events:none;margin:0;display:block;' +
1776
- 'transition:height 140ms ease,margin 140ms ease;overflow:hidden;';
1822
+ `transition:height 140ms ${MOTION_EASE},margin 140ms ${MOTION_EASE};overflow:hidden;`;
1777
1823
  }
1778
1824
  }
1779
1825
  this._indicatorContainerId = containerId;
@@ -1819,7 +1865,7 @@ class DragEngineService {
1819
1865
  el.style.transition = 'none';
1820
1866
  el.style.transform = `translate(${dx}px,${dy}px)`;
1821
1867
  requestAnimationFrame(() => {
1822
- el.style.transition = 'transform 140ms ease';
1868
+ el.style.transition = `transform 140ms ${MOTION_EASE}`;
1823
1869
  el.style.transform = '';
1824
1870
  });
1825
1871
  });