@vectoriox/iox-builder 3.3.1 → 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) {
|
|
@@ -1418,6 +1446,9 @@ class DragEngineService {
|
|
|
1418
1446
|
this._sourceEl = el;
|
|
1419
1447
|
this._isDragging = true;
|
|
1420
1448
|
this._rootEscapeActiveFor = null;
|
|
1449
|
+
// Suppress native text selection for the duration of the drag — without this,
|
|
1450
|
+
// dragging the pointer across any text (canvas or sidebar) selects/highlights it.
|
|
1451
|
+
document.body.classList.add('iox-dragging');
|
|
1421
1452
|
this._lastPointerX = event.client.x;
|
|
1422
1453
|
this._lastPointerY = event.client.y;
|
|
1423
1454
|
this.isDragging$.next(true);
|
|
@@ -1479,6 +1510,7 @@ class DragEngineService {
|
|
|
1479
1510
|
clone.classList.add('iox-drag-moving');
|
|
1480
1511
|
document.body.appendChild(clone);
|
|
1481
1512
|
this._overlay = clone;
|
|
1513
|
+
this._startGhostFollow(rect.left, rect.top);
|
|
1482
1514
|
// Hide original wrapper in-place (keeps layout space so container size is stable).
|
|
1483
1515
|
el.classList.add('iox-drag-active-source');
|
|
1484
1516
|
}
|
|
@@ -1492,15 +1524,17 @@ class DragEngineService {
|
|
|
1492
1524
|
_onDragMove(event) {
|
|
1493
1525
|
this._lastPointerX = event.client.x;
|
|
1494
1526
|
this._lastPointerY = event.client.y;
|
|
1495
|
-
//
|
|
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.
|
|
1496
1529
|
if (this._overlay) {
|
|
1497
|
-
this.
|
|
1498
|
-
this.
|
|
1530
|
+
this._ghostTargetX = event.client.x - this._grabOffsetX;
|
|
1531
|
+
this._ghostTargetY = event.client.y - this._grabOffsetY;
|
|
1499
1532
|
}
|
|
1500
1533
|
this._updateDeepTarget();
|
|
1501
1534
|
this._updateIndicator();
|
|
1502
1535
|
}
|
|
1503
1536
|
_onDragEnd(event) {
|
|
1537
|
+
document.body.classList.remove('iox-dragging');
|
|
1504
1538
|
// Restore original element visibility BEFORE Angular re-renders on drop.
|
|
1505
1539
|
if (this._sourceEl) {
|
|
1506
1540
|
this._sourceEl.classList.remove('iox-drag-active-source');
|
|
@@ -1559,14 +1593,30 @@ class DragEngineService {
|
|
|
1559
1593
|
chip.style.top = (pointerY + 14) + 'px';
|
|
1560
1594
|
document.body.appendChild(chip);
|
|
1561
1595
|
this._overlay = chip;
|
|
1596
|
+
this._startGhostFollow(pointerX + 14, pointerY + 14);
|
|
1562
1597
|
}
|
|
1563
1598
|
_removeOverlay() {
|
|
1599
|
+
this._stopGhostFollow();
|
|
1564
1600
|
this._overlay?.remove();
|
|
1565
1601
|
this._overlay = null;
|
|
1566
1602
|
this._grabOffsetX = 0;
|
|
1567
1603
|
this._grabOffsetY = 0;
|
|
1568
1604
|
}
|
|
1569
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
|
+
// ─────────────────────────────────────────────────────────
|
|
1570
1620
|
// Deep-target detection (smallest bounding-rect area)
|
|
1571
1621
|
// ─────────────────────────────────────────────────────────
|
|
1572
1622
|
_updateDeepTarget() {
|
|
@@ -1763,13 +1813,13 @@ class DragEngineService {
|
|
|
1763
1813
|
this._indicator.style.cssText =
|
|
1764
1814
|
'flex-shrink:0;width:0;align-self:stretch;' +
|
|
1765
1815
|
'background:#6366f1;border-radius:2px;pointer-events:none;margin:0;' +
|
|
1766
|
-
|
|
1816
|
+
`transition:width 140ms ${MOTION_EASE},margin 140ms ${MOTION_EASE};overflow:hidden;`;
|
|
1767
1817
|
}
|
|
1768
1818
|
else {
|
|
1769
1819
|
this._indicator.style.cssText =
|
|
1770
1820
|
'height:0;width:100%;background:#6366f1;border-radius:2px;' +
|
|
1771
1821
|
'pointer-events:none;margin:0;display:block;' +
|
|
1772
|
-
|
|
1822
|
+
`transition:height 140ms ${MOTION_EASE},margin 140ms ${MOTION_EASE};overflow:hidden;`;
|
|
1773
1823
|
}
|
|
1774
1824
|
}
|
|
1775
1825
|
this._indicatorContainerId = containerId;
|
|
@@ -1815,7 +1865,7 @@ class DragEngineService {
|
|
|
1815
1865
|
el.style.transition = 'none';
|
|
1816
1866
|
el.style.transform = `translate(${dx}px,${dy}px)`;
|
|
1817
1867
|
requestAnimationFrame(() => {
|
|
1818
|
-
el.style.transition =
|
|
1868
|
+
el.style.transition = `transform 140ms ${MOTION_EASE}`;
|
|
1819
1869
|
el.style.transform = '';
|
|
1820
1870
|
});
|
|
1821
1871
|
});
|