@archie/devtools 0.0.44 → 0.0.45
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.
- package/dist/client/client.js +291 -189
- package/dist/client/client.mjs +291 -189
- package/package.json +1 -1
package/dist/client/client.js
CHANGED
|
@@ -616,44 +616,6 @@ function getFirstCollision(collisions, property) {
|
|
|
616
616
|
const [firstCollision] = collisions;
|
|
617
617
|
return property ? firstCollision[property] : firstCollision;
|
|
618
618
|
}
|
|
619
|
-
function centerOfRectangle(rect, left, top) {
|
|
620
|
-
if (left === void 0) {
|
|
621
|
-
left = rect.left;
|
|
622
|
-
}
|
|
623
|
-
if (top === void 0) {
|
|
624
|
-
top = rect.top;
|
|
625
|
-
}
|
|
626
|
-
return {
|
|
627
|
-
x: left + rect.width * 0.5,
|
|
628
|
-
y: top + rect.height * 0.5
|
|
629
|
-
};
|
|
630
|
-
}
|
|
631
|
-
var closestCenter = (_ref) => {
|
|
632
|
-
let {
|
|
633
|
-
collisionRect,
|
|
634
|
-
droppableRects,
|
|
635
|
-
droppableContainers
|
|
636
|
-
} = _ref;
|
|
637
|
-
const centerRect = centerOfRectangle(collisionRect, collisionRect.left, collisionRect.top);
|
|
638
|
-
const collisions = [];
|
|
639
|
-
for (const droppableContainer of droppableContainers) {
|
|
640
|
-
const {
|
|
641
|
-
id
|
|
642
|
-
} = droppableContainer;
|
|
643
|
-
const rect = droppableRects.get(id);
|
|
644
|
-
if (rect) {
|
|
645
|
-
const distBetween = distanceBetween(centerOfRectangle(rect), centerRect);
|
|
646
|
-
collisions.push({
|
|
647
|
-
id,
|
|
648
|
-
data: {
|
|
649
|
-
droppableContainer,
|
|
650
|
-
value: distBetween
|
|
651
|
-
}
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return collisions.sort(sortCollisionsAsc);
|
|
656
|
-
};
|
|
657
619
|
var closestCorners = (_ref) => {
|
|
658
620
|
let {
|
|
659
621
|
collisionRect,
|
|
@@ -5582,6 +5544,7 @@ var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
|
5582
5544
|
var HANDLES = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
|
|
5583
5545
|
var HANDLE_HIT_SIZE = 24;
|
|
5584
5546
|
var HANDLE_KNOB_SIZE = 8;
|
|
5547
|
+
var EMPTY_SCROLL_DELTA = { x: NaN, y: NaN };
|
|
5585
5548
|
var OVERLAY_ROOT_STYLE = {
|
|
5586
5549
|
position: "fixed",
|
|
5587
5550
|
inset: 0,
|
|
@@ -5655,17 +5618,39 @@ function handlePosition(dir) {
|
|
|
5655
5618
|
};
|
|
5656
5619
|
return positions[dir];
|
|
5657
5620
|
}
|
|
5658
|
-
function
|
|
5621
|
+
function getSelectedOutlineStyle(rect, inspectorTheme) {
|
|
5659
5622
|
return {
|
|
5660
5623
|
...OUTLINE_BASE_STYLE,
|
|
5661
5624
|
left: rect.left,
|
|
5662
5625
|
top: rect.top,
|
|
5663
5626
|
width: rect.width,
|
|
5664
5627
|
height: rect.height,
|
|
5665
|
-
border:
|
|
5666
|
-
backgroundColor:
|
|
5628
|
+
border: `2px solid ${inspectorTheme.accent}`,
|
|
5629
|
+
backgroundColor: inspectorTheme.accentSoft
|
|
5667
5630
|
};
|
|
5668
5631
|
}
|
|
5632
|
+
function getGuideOutlineStyle(rect, tier, inspectorTheme) {
|
|
5633
|
+
const base = {
|
|
5634
|
+
...OUTLINE_BASE_STYLE,
|
|
5635
|
+
left: rect.left,
|
|
5636
|
+
top: rect.top,
|
|
5637
|
+
width: rect.width,
|
|
5638
|
+
height: rect.height
|
|
5639
|
+
};
|
|
5640
|
+
switch (tier) {
|
|
5641
|
+
case "candidate":
|
|
5642
|
+
return { ...base, border: `1px solid ${inspectorTheme.accent}`, opacity: 0.2 };
|
|
5643
|
+
case "lane-child":
|
|
5644
|
+
return { ...base, border: `1px dashed ${inspectorTheme.accent}`, opacity: 0.45 };
|
|
5645
|
+
case "lane":
|
|
5646
|
+
return {
|
|
5647
|
+
...base,
|
|
5648
|
+
border: `1.5px solid ${inspectorTheme.accent}`,
|
|
5649
|
+
backgroundColor: inspectorTheme.accentSoft,
|
|
5650
|
+
opacity: 0.75
|
|
5651
|
+
};
|
|
5652
|
+
}
|
|
5653
|
+
}
|
|
5669
5654
|
function getResizeHandleStyle(position) {
|
|
5670
5655
|
return {
|
|
5671
5656
|
...RESIZE_HANDLE_BASE_STYLE,
|
|
@@ -5688,40 +5673,58 @@ function getLabelStyle(labelLeft, labelTop, labelColor) {
|
|
|
5688
5673
|
backgroundColor: labelColor
|
|
5689
5674
|
};
|
|
5690
5675
|
}
|
|
5676
|
+
function projectDragRect(dragGuide, nodeId, sdx, sdy) {
|
|
5677
|
+
const r = dragGuide.rects.get(nodeId);
|
|
5678
|
+
if (!r) return null;
|
|
5679
|
+
return { left: r.left - sdx, top: r.top - sdy, width: r.width, height: r.height };
|
|
5680
|
+
}
|
|
5691
5681
|
function ElementHighlight({
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
activeEl,
|
|
5695
|
-
arrangeSelectedNodeId,
|
|
5682
|
+
selected,
|
|
5683
|
+
dragGuide,
|
|
5696
5684
|
externalDragActive,
|
|
5697
5685
|
onResizeHandlePointerDown
|
|
5698
5686
|
}) {
|
|
5699
5687
|
const inspectorTheme = useDesignModeStore((s) => s.inspectorTheme);
|
|
5700
|
-
const internalDragInProgress = draggingNodeId !== null;
|
|
5701
|
-
const overlayVisible = arrangeSelectedNodeId !== null || internalDragInProgress;
|
|
5702
5688
|
const containerRef = (0, import_react7.useRef)(null);
|
|
5703
5689
|
const rafRef = (0, import_react7.useRef)(0);
|
|
5690
|
+
const lastScrollDeltaRef = (0, import_react7.useRef)(EMPTY_SCROLL_DELTA);
|
|
5704
5691
|
const syncPositions = (0, import_react7.useCallback)(() => {
|
|
5705
5692
|
const container = containerRef.current;
|
|
5706
5693
|
if (!container) return;
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
const
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
const
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
label.style.left = `${rect.left}px`;
|
|
5720
|
-
label.style.top = `${rect.top}px`;
|
|
5694
|
+
if (dragGuide) {
|
|
5695
|
+
const sdx = window.scrollX - dragGuide.startScroll.x;
|
|
5696
|
+
const sdy = window.scrollY - dragGuide.startScroll.y;
|
|
5697
|
+
if (sdx === lastScrollDeltaRef.current.x && sdy === lastScrollDeltaRef.current.y) return;
|
|
5698
|
+
lastScrollDeltaRef.current = { x: sdx, y: sdy };
|
|
5699
|
+
const outlines = container.querySelectorAll("[data-guide-for]");
|
|
5700
|
+
for (const outline2 of outlines) {
|
|
5701
|
+
const nodeId = outline2.getAttribute("data-guide-for");
|
|
5702
|
+
const r = dragGuide.rects.get(nodeId);
|
|
5703
|
+
if (!r) continue;
|
|
5704
|
+
outline2.style.left = `${r.left - sdx}px`;
|
|
5705
|
+
outline2.style.top = `${r.top - sdy}px`;
|
|
5721
5706
|
}
|
|
5707
|
+
return;
|
|
5722
5708
|
}
|
|
5723
|
-
|
|
5709
|
+
if (!selected) return;
|
|
5710
|
+
const rect2 = selected.element.getBoundingClientRect();
|
|
5711
|
+
const outline = container.querySelector("[data-outline-for]");
|
|
5712
|
+
if (outline) {
|
|
5713
|
+
outline.style.left = `${rect2.left}px`;
|
|
5714
|
+
outline.style.top = `${rect2.top}px`;
|
|
5715
|
+
outline.style.width = `${rect2.width}px`;
|
|
5716
|
+
outline.style.height = `${rect2.height}px`;
|
|
5717
|
+
}
|
|
5718
|
+
const label = container.querySelector("[data-drag-handle]");
|
|
5719
|
+
if (label) {
|
|
5720
|
+
label.style.left = `${rect2.left + 12}px`;
|
|
5721
|
+
label.style.top = `${Math.max(0, rect2.top - 20)}px`;
|
|
5722
|
+
}
|
|
5723
|
+
}, [dragGuide, selected]);
|
|
5724
|
+
const loopActive = !externalDragActive && (dragGuide !== null || selected !== null);
|
|
5724
5725
|
(0, import_react7.useEffect)(() => {
|
|
5726
|
+
if (!loopActive) return;
|
|
5727
|
+
lastScrollDeltaRef.current = EMPTY_SCROLL_DELTA;
|
|
5725
5728
|
let running = true;
|
|
5726
5729
|
const loop = () => {
|
|
5727
5730
|
if (!running) return;
|
|
@@ -5733,81 +5736,113 @@ function ElementHighlight({
|
|
|
5733
5736
|
running = false;
|
|
5734
5737
|
cancelAnimationFrame(rafRef.current);
|
|
5735
5738
|
};
|
|
5736
|
-
}, [syncPositions]);
|
|
5737
|
-
if (!
|
|
5738
|
-
if (
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
{
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
if (
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5739
|
+
}, [loopActive, syncPositions]);
|
|
5740
|
+
if (!loopActive) return null;
|
|
5741
|
+
if (dragGuide) {
|
|
5742
|
+
const sdx = window.scrollX - dragGuide.startScroll.x;
|
|
5743
|
+
const sdy = window.scrollY - dragGuide.startScroll.y;
|
|
5744
|
+
const { candidateContainerIds, activeContainerId, activeChildIds, draggingNodeId } = dragGuide;
|
|
5745
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref: containerRef, "data-design-mode-ui": true, style: OVERLAY_ROOT_STYLE, children: [
|
|
5746
|
+
[...candidateContainerIds].map((id) => {
|
|
5747
|
+
if (id === activeContainerId || id === draggingNodeId) return null;
|
|
5748
|
+
const rect2 = projectDragRect(dragGuide, id, sdx, sdy);
|
|
5749
|
+
if (!rect2) return null;
|
|
5750
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
5751
|
+
"div",
|
|
5752
|
+
{
|
|
5753
|
+
"data-guide-for": id,
|
|
5754
|
+
"data-guide-tier": "candidate",
|
|
5755
|
+
"data-design-mode-ui": true,
|
|
5756
|
+
style: getGuideOutlineStyle(rect2, "candidate", inspectorTheme)
|
|
5757
|
+
},
|
|
5758
|
+
`candidate:${id}`
|
|
5759
|
+
);
|
|
5760
|
+
}),
|
|
5761
|
+
activeContainerId !== null && activeChildIds.map((id) => {
|
|
5762
|
+
if (id === draggingNodeId) return null;
|
|
5763
|
+
const rect2 = projectDragRect(dragGuide, id, sdx, sdy);
|
|
5764
|
+
if (!rect2) return null;
|
|
5765
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
5766
|
+
"div",
|
|
5767
|
+
{
|
|
5768
|
+
"data-guide-for": id,
|
|
5769
|
+
"data-guide-tier": "lane-child",
|
|
5770
|
+
"data-design-mode-ui": true,
|
|
5771
|
+
style: getGuideOutlineStyle(rect2, "lane-child", inspectorTheme)
|
|
5772
|
+
},
|
|
5773
|
+
`lane-child:${id}`
|
|
5774
|
+
);
|
|
5775
|
+
}),
|
|
5776
|
+
activeContainerId !== null && activeContainerId !== draggingNodeId && (() => {
|
|
5777
|
+
const rect2 = projectDragRect(dragGuide, activeContainerId, sdx, sdy);
|
|
5778
|
+
if (!rect2) return null;
|
|
5779
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
5780
|
+
"div",
|
|
5781
|
+
{
|
|
5782
|
+
"data-guide-for": activeContainerId,
|
|
5783
|
+
"data-guide-tier": "lane",
|
|
5784
|
+
"data-design-mode-ui": true,
|
|
5785
|
+
style: getGuideOutlineStyle(rect2, "lane", inspectorTheme)
|
|
5786
|
+
},
|
|
5787
|
+
`lane:${activeContainerId}`
|
|
5788
|
+
);
|
|
5789
|
+
})()
|
|
5790
|
+
] });
|
|
5791
|
+
}
|
|
5792
|
+
if (!selected) return null;
|
|
5793
|
+
const rect = selected.element.getBoundingClientRect();
|
|
5794
|
+
const labelTop = Math.max(0, rect.top - 20);
|
|
5795
|
+
const labelLeft = rect.left + 12;
|
|
5796
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { ref: containerRef, "data-design-mode-ui": true, style: OVERLAY_ROOT_STYLE, children: [
|
|
5797
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
5798
|
+
"div",
|
|
5799
|
+
{
|
|
5800
|
+
"data-outline-for": selected.nodeId,
|
|
5801
|
+
"data-design-mode-ui": true,
|
|
5802
|
+
style: getSelectedOutlineStyle(rect, inspectorTheme),
|
|
5803
|
+
children: selected.draggable && HANDLES.map((dir) => {
|
|
5804
|
+
const pos = handlePosition(dir);
|
|
5805
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
5787
5806
|
"div",
|
|
5788
5807
|
{
|
|
5789
5808
|
"data-design-mode-ui": true,
|
|
5790
|
-
"data-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
),
|
|
5796
|
-
children:
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5809
|
+
"data-resize-handle": dir,
|
|
5810
|
+
onPointerDown: (e) => {
|
|
5811
|
+
e.stopPropagation();
|
|
5812
|
+
onResizeHandlePointerDown?.(e, selected.nodeId, dir);
|
|
5813
|
+
},
|
|
5814
|
+
style: getResizeHandleStyle(pos),
|
|
5815
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
5816
|
+
"span",
|
|
5817
|
+
{
|
|
5818
|
+
"data-design-mode-ui": true,
|
|
5819
|
+
style: getResizeKnobStyle(inspectorTheme.accent)
|
|
5820
|
+
}
|
|
5821
|
+
)
|
|
5822
|
+
},
|
|
5823
|
+
dir
|
|
5824
|
+
);
|
|
5825
|
+
})
|
|
5826
|
+
}
|
|
5827
|
+
),
|
|
5828
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
5829
|
+
"div",
|
|
5830
|
+
{
|
|
5831
|
+
"data-design-mode-ui": true,
|
|
5832
|
+
"data-drag-handle": selected.nodeId,
|
|
5833
|
+
style: getLabelStyle(labelLeft, labelTop, inspectorTheme.accent),
|
|
5834
|
+
children: [
|
|
5835
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: LABEL_ICON_STYLE, children: "\u283F" }),
|
|
5836
|
+
selected.label,
|
|
5837
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: LABEL_DIMENSIONS_STYLE, children: [
|
|
5838
|
+
Math.round(rect.width),
|
|
5839
|
+
"\xD7",
|
|
5840
|
+
Math.round(rect.height)
|
|
5841
|
+
] })
|
|
5842
|
+
]
|
|
5843
|
+
}
|
|
5844
|
+
)
|
|
5845
|
+
] });
|
|
5811
5846
|
}
|
|
5812
5847
|
|
|
5813
5848
|
// src/client/dnd/design-mode/projection.ts
|
|
@@ -6601,30 +6636,6 @@ function applyDndCommandPlacement(command, direction, resolveNodeElement) {
|
|
|
6601
6636
|
return true;
|
|
6602
6637
|
}
|
|
6603
6638
|
|
|
6604
|
-
// src/client/dnd/design-mode/design-mode-collision.ts
|
|
6605
|
-
function filterDroppables(droppableContainers, blockedContainerIds) {
|
|
6606
|
-
if (!blockedContainerIds || blockedContainerIds.size === 0) return droppableContainers;
|
|
6607
|
-
return droppableContainers.filter((container) => !blockedContainerIds.has(String(container.id)));
|
|
6608
|
-
}
|
|
6609
|
-
function getCollisions(detector, args) {
|
|
6610
|
-
return detector(args);
|
|
6611
|
-
}
|
|
6612
|
-
function createDesignModeCollisionDetection(blockedContainerIds) {
|
|
6613
|
-
return (args) => {
|
|
6614
|
-
const droppableContainers = filterDroppables(args.droppableContainers, blockedContainerIds);
|
|
6615
|
-
if (droppableContainers.length === 0) return [];
|
|
6616
|
-
const scopedArgs = {
|
|
6617
|
-
...args,
|
|
6618
|
-
droppableContainers
|
|
6619
|
-
};
|
|
6620
|
-
const pointerHits = getCollisions(pointerWithin, scopedArgs);
|
|
6621
|
-
if (pointerHits.length > 0) return pointerHits;
|
|
6622
|
-
const cornerHits = getCollisions(closestCorners, scopedArgs);
|
|
6623
|
-
if (cornerHits.length > 0) return cornerHits;
|
|
6624
|
-
return getCollisions(closestCenter, scopedArgs);
|
|
6625
|
-
};
|
|
6626
|
-
}
|
|
6627
|
-
|
|
6628
6639
|
// src/client/dnd/design-mode/arrange-session.ts
|
|
6629
6640
|
function serializeArrangeChange(event, index) {
|
|
6630
6641
|
return {
|
|
@@ -6903,9 +6914,9 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6903
6914
|
const lastIntentRef = (0, import_react11.useRef)(null);
|
|
6904
6915
|
const visualIntentRef = (0, import_react11.useRef)(null);
|
|
6905
6916
|
const sourceContainerIdRef = (0, import_react11.useRef)(null);
|
|
6917
|
+
const activeLaneContainerIdRef = (0, import_react11.useRef)(null);
|
|
6906
6918
|
const rowLockedRef = (0, import_react11.useRef)(false);
|
|
6907
6919
|
const dragSessionAnchorRef = (0, import_react11.useRef)(null);
|
|
6908
|
-
const lockRef = (0, import_react11.useRef)({ containerId: null, isCrossUnlocked: false, exitSince: null, unlockUntilTs: null });
|
|
6909
6920
|
const targetPlaneRef = (0, import_react11.useRef)("lane");
|
|
6910
6921
|
const nestCandidateRef = (0, import_react11.useRef)(null);
|
|
6911
6922
|
const nestTargetRef = (0, import_react11.useRef)(null);
|
|
@@ -6915,7 +6926,6 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6915
6926
|
const sourceCommitLaneRef = (0, import_react11.useRef)(null);
|
|
6916
6927
|
const commitLaneCacheRef = (0, import_react11.useRef)(/* @__PURE__ */ new Map());
|
|
6917
6928
|
const safeZoneRef = (0, import_react11.useRef)(null);
|
|
6918
|
-
const blockedContainerIdsRef = (0, import_react11.useRef)(/* @__PURE__ */ new Set());
|
|
6919
6929
|
const historyRef = (0, import_react11.useRef)(new DndCommandHistory());
|
|
6920
6930
|
const processedUndoIdRef = (0, import_react11.useRef)(undoRequestId);
|
|
6921
6931
|
const processedRedoIdRef = (0, import_react11.useRef)(redoRequestId);
|
|
@@ -6935,9 +6945,9 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6935
6945
|
lastIntentRef,
|
|
6936
6946
|
visualIntentRef,
|
|
6937
6947
|
sourceContainerIdRef,
|
|
6948
|
+
activeLaneContainerIdRef,
|
|
6938
6949
|
rowLockedRef,
|
|
6939
6950
|
dragSessionAnchorRef,
|
|
6940
|
-
lockRef,
|
|
6941
6951
|
targetPlaneRef,
|
|
6942
6952
|
nestCandidateRef,
|
|
6943
6953
|
nestTargetRef,
|
|
@@ -6947,7 +6957,6 @@ function useOverlayRefs(undoRequestId, redoRequestId) {
|
|
|
6947
6957
|
sourceCommitLaneRef,
|
|
6948
6958
|
commitLaneCacheRef,
|
|
6949
6959
|
safeZoneRef,
|
|
6950
|
-
blockedContainerIdsRef,
|
|
6951
6960
|
historyRef,
|
|
6952
6961
|
processedUndoIdRef,
|
|
6953
6962
|
processedRedoIdRef,
|
|
@@ -7215,6 +7224,11 @@ function pointInRect(px, py, r) {
|
|
|
7215
7224
|
function pointInExpandedRect(px, py, r, inset) {
|
|
7216
7225
|
return px >= r.left - inset && px <= r.right + inset && py >= r.top - inset && py <= r.bottom + inset;
|
|
7217
7226
|
}
|
|
7227
|
+
function isInNestZone(px, py, rect) {
|
|
7228
|
+
const relX = (px - rect.left) / rect.width;
|
|
7229
|
+
const relY = (py - rect.top) / rect.height;
|
|
7230
|
+
return relX > NEST_EDGE_FRACTION && relX < 1 - NEST_EDGE_FRACTION && relY > NEST_EDGE_FRACTION && relY < 1 - NEST_EDGE_FRACTION;
|
|
7231
|
+
}
|
|
7218
7232
|
function buildSlotQuadtree(slotIndex) {
|
|
7219
7233
|
const rects = /* @__PURE__ */ new Map();
|
|
7220
7234
|
for (const [id, slot] of slotIndex) {
|
|
@@ -7257,6 +7271,11 @@ var DragIntentEngine = class {
|
|
|
7257
7271
|
__publicField(this, "laneAllowedContainers");
|
|
7258
7272
|
__publicField(this, "blockedContainerIds");
|
|
7259
7273
|
__publicField(this, "targetPlane", "lane");
|
|
7274
|
+
// Memoized result of getValidDropContainerIds(). Safe to cache because every
|
|
7275
|
+
// input it reads (containerIndex, slotIndex, activeId, laneAllowedContainers,
|
|
7276
|
+
// blockedContainerIds) is fixed in the constructor and never mutated during
|
|
7277
|
+
// a drag.
|
|
7278
|
+
__publicField(this, "validDropContainerIds", null);
|
|
7260
7279
|
this.projectionTree = projection.projectionTree;
|
|
7261
7280
|
this.containerIndex = projection.containerIndex;
|
|
7262
7281
|
this.slotIndex = projection.slotIndex;
|
|
@@ -7293,6 +7312,44 @@ var DragIntentEngine = class {
|
|
|
7293
7312
|
getContainerChildren(containerId) {
|
|
7294
7313
|
return this.containerIndex.get(containerId)?.children ?? [];
|
|
7295
7314
|
}
|
|
7315
|
+
/**
|
|
7316
|
+
* Every container id this engine would accept as a drop target for the
|
|
7317
|
+
* active node, at the current pointer position or any other — i.e. the
|
|
7318
|
+
* full set `resolvePointerContainer` draws from, not a snapshot of one
|
|
7319
|
+
* resolve() call. Intended for the visual layer to draw a guide that
|
|
7320
|
+
* matches exactly what the engine can land on, without re-deriving the
|
|
7321
|
+
* eligibility rule itself.
|
|
7322
|
+
*
|
|
7323
|
+
* Always queries with `laneLock: true`. That is not an approximation of
|
|
7324
|
+
* the "real" default — it IS the real answer for every reachable caller:
|
|
7325
|
+
*
|
|
7326
|
+
* - With a row lock active (`laneAllowedContainers` set), `isLaneContainer`
|
|
7327
|
+
* restricts eligibility to that set, so this returns exactly
|
|
7328
|
+
* `{srcContainerId}` — the ARCH-1071 lock, reproduced faithfully.
|
|
7329
|
+
* - Without a row lock, `laneAllowedContainers` is null and
|
|
7330
|
+
* `isLaneContainer` returns true unconditionally, so `laneLock`'s value
|
|
7331
|
+
* makes no difference — passing `true` costs nothing here.
|
|
7332
|
+
* - The engine's own 'nest' plane does call `isEligibleDropContainer` with
|
|
7333
|
+
* `laneLock: false` (see `peekNestIntent` → `resolvePointerContainer`),
|
|
7334
|
+
* but that plane is unreachable for a locked drag: `computeAllowNest`
|
|
7335
|
+
* (useDragVisualLoop.ts) short-circuits `rowLocked` drags before
|
|
7336
|
+
* `setTargetPlane('nest')` is ever called, so `targetPlane` stays
|
|
7337
|
+
* 'lane' for the drag's whole lifetime. If that guard is ever removed,
|
|
7338
|
+
* this method will under-report nest-only targets for locked drags —
|
|
7339
|
+
* keep the two in sync.
|
|
7340
|
+
*
|
|
7341
|
+
* Cached after the first call: every input (containerIndex, slotIndex,
|
|
7342
|
+
* activeId, laneAllowedContainers, blockedContainerIds) is fixed at
|
|
7343
|
+
* construction and never changes for the life of a drag.
|
|
7344
|
+
*/
|
|
7345
|
+
getValidDropContainerIds() {
|
|
7346
|
+
if (this.validDropContainerIds) return this.validDropContainerIds;
|
|
7347
|
+
const ids2 = /* @__PURE__ */ new Set();
|
|
7348
|
+
for (const id of this.containerIndex.keys()) {
|
|
7349
|
+
if (this.isEligibleDropContainer(id, true)) ids2.add(id);
|
|
7350
|
+
}
|
|
7351
|
+
return this.validDropContainerIds = ids2;
|
|
7352
|
+
}
|
|
7296
7353
|
setTargetPlane(plane) {
|
|
7297
7354
|
this.targetPlane = plane;
|
|
7298
7355
|
}
|
|
@@ -7311,6 +7368,17 @@ var DragIntentEngine = class {
|
|
|
7311
7368
|
isInvalidDropContainer(containerId) {
|
|
7312
7369
|
return containerId === this.activeId || this.isContainerDescendantOf(containerId, this.activeId);
|
|
7313
7370
|
}
|
|
7371
|
+
/**
|
|
7372
|
+
* The full "can this container accept the active node this drag" predicate.
|
|
7373
|
+
* SINGLE definition — every caller routes through it so no two parts of the
|
|
7374
|
+
* system can disagree about which containers are droppable.
|
|
7375
|
+
*/
|
|
7376
|
+
isEligibleDropContainer(containerId, laneLock) {
|
|
7377
|
+
if (this.isInvalidDropContainer(containerId)) return false;
|
|
7378
|
+
if (this.isBlockedContainer(containerId)) return false;
|
|
7379
|
+
if (laneLock && !this.isLaneContainer(containerId)) return false;
|
|
7380
|
+
return this.hasUsableSlots(containerId);
|
|
7381
|
+
}
|
|
7314
7382
|
/**
|
|
7315
7383
|
* Resolve the drag intent from the current pointer position.
|
|
7316
7384
|
*
|
|
@@ -7398,9 +7466,7 @@ var DragIntentEngine = class {
|
|
|
7398
7466
|
const childNode = this.getNodeRect(childId);
|
|
7399
7467
|
if (!childNode) continue;
|
|
7400
7468
|
if (!pointInRect(px, py, childNode)) continue;
|
|
7401
|
-
|
|
7402
|
-
const relY = (py - childNode.top) / childNode.height;
|
|
7403
|
-
if (relX > NEST_EDGE_FRACTION && relX < 1 - NEST_EDGE_FRACTION && relY > NEST_EDGE_FRACTION && relY < 1 - NEST_EDGE_FRACTION) {
|
|
7469
|
+
if (isInNestZone(px, py, childNode)) {
|
|
7404
7470
|
return {
|
|
7405
7471
|
containerId: pointerContainerId,
|
|
7406
7472
|
index: container.children.indexOf(childId),
|
|
@@ -7414,11 +7480,8 @@ var DragIntentEngine = class {
|
|
|
7414
7480
|
resolvePointerContainer(px, py, laneLock) {
|
|
7415
7481
|
const pointerContainers = [];
|
|
7416
7482
|
for (const [id, node] of this.containerIndex) {
|
|
7417
|
-
if (this.isInvalidDropContainer(id)) continue;
|
|
7418
|
-
if (this.isBlockedContainer(id)) continue;
|
|
7419
|
-
if (laneLock && !this.isLaneContainer(id)) continue;
|
|
7420
7483
|
if (!pointInRect(px, py, node.rect)) continue;
|
|
7421
|
-
if (this.
|
|
7484
|
+
if (!this.isEligibleDropContainer(id, laneLock)) continue;
|
|
7422
7485
|
const r = node.rect;
|
|
7423
7486
|
const edgeDistX = Math.min(px - r.left, r.right - px);
|
|
7424
7487
|
const edgeDistY = Math.min(py - r.top, r.bottom - py);
|
|
@@ -7435,11 +7498,11 @@ var DragIntentEngine = class {
|
|
|
7435
7498
|
let pointerContainerId = pointerContainers[0]?.id ?? null;
|
|
7436
7499
|
if (!pointerContainerId && this.lastIntent?.mode === "reorder") {
|
|
7437
7500
|
const lastContainer = this.containerIndex.get(this.lastIntent.containerId);
|
|
7438
|
-
if (lastContainer &&
|
|
7501
|
+
if (lastContainer && this.isEligibleDropContainer(lastContainer.id, laneLock) && pointInExpandedRect(px, py, lastContainer.rect, LAST_CONTAINER_REENTRY_SLOP_PX)) {
|
|
7439
7502
|
pointerContainerId = lastContainer.id;
|
|
7440
7503
|
}
|
|
7441
7504
|
}
|
|
7442
|
-
if (this.originContainerId && this.originContainerId !== pointerContainerId &&
|
|
7505
|
+
if (this.originContainerId && this.originContainerId !== pointerContainerId && this.isEligibleDropContainer(this.originContainerId, laneLock)) {
|
|
7443
7506
|
const originNode = this.containerIndex.get(this.originContainerId);
|
|
7444
7507
|
const currentNode = pointerContainerId ? this.containerIndex.get(pointerContainerId) : null;
|
|
7445
7508
|
const originIsDeeper = originNode && (!currentNode || originNode.depth >= currentNode.depth);
|
|
@@ -7852,7 +7915,8 @@ function useDragVisualLoop({
|
|
|
7852
7915
|
refs,
|
|
7853
7916
|
getCommitLaneSnapshot,
|
|
7854
7917
|
setInsideRect,
|
|
7855
|
-
setDropLine
|
|
7918
|
+
setDropLine,
|
|
7919
|
+
setActiveLaneContainerId
|
|
7856
7920
|
}) {
|
|
7857
7921
|
(0, import_react12.useEffect)(() => {
|
|
7858
7922
|
const engine = refs.engineRef.current;
|
|
@@ -7860,6 +7924,11 @@ function useDragVisualLoop({
|
|
|
7860
7924
|
if (!activeDrag || !engine || !snapshot) return;
|
|
7861
7925
|
let rafId;
|
|
7862
7926
|
const animator = refs.animatorRef.current;
|
|
7927
|
+
const publishActiveLane = (containerId) => {
|
|
7928
|
+
if (refs.activeLaneContainerIdRef.current === containerId) return;
|
|
7929
|
+
refs.activeLaneContainerIdRef.current = containerId;
|
|
7930
|
+
setActiveLaneContainerId(containerId);
|
|
7931
|
+
};
|
|
7863
7932
|
const setTargetPlane = (nextPlane) => {
|
|
7864
7933
|
const prevPlane = refs.targetPlaneRef.current;
|
|
7865
7934
|
if (prevPlane === nextPlane) return;
|
|
@@ -7878,6 +7947,7 @@ function useDragVisualLoop({
|
|
|
7878
7947
|
const safeZone = refs.safeZoneRef.current;
|
|
7879
7948
|
if (isPointerBlocked(px, py, safeZone)) {
|
|
7880
7949
|
setTargetPlane("lane");
|
|
7950
|
+
publishActiveLane(null);
|
|
7881
7951
|
refs.lastIntentRef.current = null;
|
|
7882
7952
|
refs.visualIntentRef.current = null;
|
|
7883
7953
|
refs.nestCandidateRef.current = null;
|
|
@@ -7919,6 +7989,7 @@ function useDragVisualLoop({
|
|
|
7919
7989
|
let intent = engine.resolve(px, py, window.scrollX, window.scrollY, snapshot.scroll.x, snapshot.scroll.y);
|
|
7920
7990
|
if (!intent) {
|
|
7921
7991
|
setTargetPlane("lane");
|
|
7992
|
+
publishActiveLane(null);
|
|
7922
7993
|
refs.lastIntentRef.current = null;
|
|
7923
7994
|
refs.visualIntentRef.current = null;
|
|
7924
7995
|
refs.nestCandidateRef.current = null;
|
|
@@ -7944,6 +8015,7 @@ function useDragVisualLoop({
|
|
|
7944
8015
|
const targetId = intent.slotId.split("::nest::")[1] ?? "";
|
|
7945
8016
|
if (!targetId) {
|
|
7946
8017
|
setTargetPlane("lane");
|
|
8018
|
+
publishActiveLane(null);
|
|
7947
8019
|
rafId = requestAnimationFrame(tick);
|
|
7948
8020
|
return;
|
|
7949
8021
|
}
|
|
@@ -7965,12 +8037,14 @@ function useDragVisualLoop({
|
|
|
7965
8037
|
};
|
|
7966
8038
|
refs.visualIntentRef.current = intent;
|
|
7967
8039
|
refs.lastIntentRef.current = intent;
|
|
8040
|
+
publishActiveLane(intent.containerId);
|
|
7968
8041
|
} else {
|
|
7969
8042
|
setTargetPlane("lane");
|
|
7970
8043
|
refs.nestCandidateRef.current = null;
|
|
7971
8044
|
refs.nestTargetRef.current = null;
|
|
7972
8045
|
refs.lastIntentRef.current = intent;
|
|
7973
8046
|
refs.visualIntentRef.current = intent;
|
|
8047
|
+
publishActiveLane(intent.containerId);
|
|
7974
8048
|
setInsideRect(null);
|
|
7975
8049
|
const proj = refs.projectionRef.current;
|
|
7976
8050
|
const slot = proj.slotIndex.get(intent.slotId);
|
|
@@ -8277,7 +8351,8 @@ function useDragLifecycle({
|
|
|
8277
8351
|
syncHistoryAvailability,
|
|
8278
8352
|
resolveNodeElement,
|
|
8279
8353
|
setInsideRect,
|
|
8280
|
-
setDropLine
|
|
8354
|
+
setDropLine,
|
|
8355
|
+
setActiveLaneContainerId
|
|
8281
8356
|
}) {
|
|
8282
8357
|
const [activeDrag, setActiveDrag] = (0, import_react13.useState)(null);
|
|
8283
8358
|
const clearDragState = (0, import_react13.useCallback)(() => {
|
|
@@ -8288,13 +8363,12 @@ function useDragLifecycle({
|
|
|
8288
8363
|
refs.snapshotRef.current = null;
|
|
8289
8364
|
refs.projectionRef.current = EMPTY_PROJECTION;
|
|
8290
8365
|
refs.engineRef.current = null;
|
|
8291
|
-
refs.blockedContainerIdsRef.current = /* @__PURE__ */ new Set();
|
|
8292
8366
|
refs.lastIntentRef.current = null;
|
|
8293
8367
|
refs.visualIntentRef.current = null;
|
|
8294
8368
|
refs.sourceContainerIdRef.current = null;
|
|
8369
|
+
refs.activeLaneContainerIdRef.current = null;
|
|
8295
8370
|
refs.rowLockedRef.current = false;
|
|
8296
8371
|
refs.dragSessionAnchorRef.current = null;
|
|
8297
|
-
refs.lockRef.current = { containerId: null, isCrossUnlocked: false, exitSince: null, unlockUntilTs: null };
|
|
8298
8372
|
refs.targetPlaneRef.current = "lane";
|
|
8299
8373
|
refs.nestCandidateRef.current = null;
|
|
8300
8374
|
refs.nestTargetRef.current = null;
|
|
@@ -8305,6 +8379,7 @@ function useDragLifecycle({
|
|
|
8305
8379
|
refs.safeZoneRef.current = null;
|
|
8306
8380
|
setInsideRect(null);
|
|
8307
8381
|
setDropLine(null);
|
|
8382
|
+
setActiveLaneContainerId(null);
|
|
8308
8383
|
setActiveDrag(null);
|
|
8309
8384
|
resume();
|
|
8310
8385
|
}, [clearCommitLaneCache, resume]);
|
|
@@ -8362,7 +8437,6 @@ function useDragLifecycle({
|
|
|
8362
8437
|
const sourceCommitLane = getCommitLaneSnapshot(srcContainerId);
|
|
8363
8438
|
const startPosition = getCurrentCommitPlacement(anchorNodeId, srcContainerId);
|
|
8364
8439
|
const blockedContainerIds = buildBlockedStructuralContainerIds(proj, refs.nodeMapRef.current, srcContainerId);
|
|
8365
|
-
refs.blockedContainerIdsRef.current = blockedContainerIds;
|
|
8366
8440
|
const engineOptions = buildDragIntentEngineOptions(anchorScanned.element, srcContainerId, blockedContainerIds);
|
|
8367
8441
|
refs.rowLockedRef.current = !!engineOptions.laneAllowedContainers;
|
|
8368
8442
|
refs.engineRef.current = createDragIntentEngine(proj, anchorNodeId, engineOptions);
|
|
@@ -8371,7 +8445,6 @@ function useDragLifecycle({
|
|
|
8371
8445
|
refs.sourceContainerIdRef.current = srcContainerId;
|
|
8372
8446
|
refs.sourceCommitLaneRef.current = sourceCommitLane;
|
|
8373
8447
|
refs.dragSessionAnchorRef.current = anchor;
|
|
8374
|
-
refs.lockRef.current = { containerId: srcContainerId, isCrossUnlocked: true, exitSince: null, unlockUntilTs: null };
|
|
8375
8448
|
refs.dragStartPositionRef.current = startPosition;
|
|
8376
8449
|
refs.safeZoneRef.current = resolveSafeZoneRect();
|
|
8377
8450
|
pause();
|
|
@@ -8930,6 +9003,7 @@ function commitExternalDrop(x, y, engine, component, refs, resolveNodeElement, s
|
|
|
8930
9003
|
// src/client/dnd/design-mode/DesignModeOverlay.tsx
|
|
8931
9004
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
8932
9005
|
var DROP_ANIMATION = { duration: DURATION_MS, easing: EASING };
|
|
9006
|
+
var EMPTY_CONTAINER_ID_SET = /* @__PURE__ */ new Set();
|
|
8933
9007
|
function resizeCursorFromHandle(handle) {
|
|
8934
9008
|
switch (handle) {
|
|
8935
9009
|
case "n":
|
|
@@ -9217,13 +9291,9 @@ function DesignModeOverlay() {
|
|
|
9217
9291
|
const sensors = useSensors(
|
|
9218
9292
|
useSensor(PointerSensor, { activationConstraint: { distance: 8 } })
|
|
9219
9293
|
);
|
|
9220
|
-
const collisionDetection = (0, import_react16.useCallback)(
|
|
9221
|
-
(args) => createDesignModeCollisionDetection(refs.blockedContainerIdsRef.current)(args),
|
|
9222
|
-
[]
|
|
9223
|
-
// eslint-disable-line react-hooks/exhaustive-deps -- refs are stable
|
|
9224
|
-
);
|
|
9225
9294
|
const [insideRect, setInsideRect] = (0, import_react16.useState)(null);
|
|
9226
9295
|
const [dropLine, setDropLine] = (0, import_react16.useState)(null);
|
|
9296
|
+
const [activeLaneContainerId, setActiveLaneContainerId] = (0, import_react16.useState)(null);
|
|
9227
9297
|
(0, import_react16.useEffect)(() => {
|
|
9228
9298
|
if (!enabled) return;
|
|
9229
9299
|
const fn = (e) => {
|
|
@@ -9259,8 +9329,43 @@ function DesignModeOverlay() {
|
|
|
9259
9329
|
syncHistoryAvailability,
|
|
9260
9330
|
resolveNodeElement,
|
|
9261
9331
|
setInsideRect,
|
|
9262
|
-
setDropLine
|
|
9332
|
+
setDropLine,
|
|
9333
|
+
setActiveLaneContainerId
|
|
9263
9334
|
});
|
|
9335
|
+
const dropCandidateContainerIds = (0, import_react16.useMemo)(
|
|
9336
|
+
() => activeDrag ? refs.engineRef.current?.getValidDropContainerIds() ?? null : null,
|
|
9337
|
+
[activeDrag]
|
|
9338
|
+
// eslint-disable-line react-hooks/exhaustive-deps -- refs are stable
|
|
9339
|
+
);
|
|
9340
|
+
const visibleCandidateContainerIds = (0, import_react16.useMemo)(() => {
|
|
9341
|
+
if (!dropCandidateContainerIds) return null;
|
|
9342
|
+
const rects = refs.snapshotRef.current?.rects;
|
|
9343
|
+
if (!rects) return dropCandidateContainerIds;
|
|
9344
|
+
const vw = window.innerWidth;
|
|
9345
|
+
const vh = window.innerHeight;
|
|
9346
|
+
const visible = /* @__PURE__ */ new Set();
|
|
9347
|
+
for (const id of dropCandidateContainerIds) {
|
|
9348
|
+
const r = rects.get(id);
|
|
9349
|
+
if (!r) continue;
|
|
9350
|
+
if (r.right < 0 || r.bottom < 0 || r.left > vw || r.top > vh) continue;
|
|
9351
|
+
visible.add(id);
|
|
9352
|
+
}
|
|
9353
|
+
return visible;
|
|
9354
|
+
}, [dropCandidateContainerIds]);
|
|
9355
|
+
const dragGuide = (0, import_react16.useMemo)(() => {
|
|
9356
|
+
if (!activeDrag) return null;
|
|
9357
|
+
const snapshot = refs.snapshotRef.current;
|
|
9358
|
+
if (!snapshot) return null;
|
|
9359
|
+
const activeChildIds = activeLaneContainerId ? refs.engineRef.current?.getContainerChildren(activeLaneContainerId) ?? [] : [];
|
|
9360
|
+
return {
|
|
9361
|
+
rects: snapshot.rects,
|
|
9362
|
+
startScroll: snapshot.scroll,
|
|
9363
|
+
candidateContainerIds: visibleCandidateContainerIds ?? EMPTY_CONTAINER_ID_SET,
|
|
9364
|
+
activeContainerId: activeLaneContainerId,
|
|
9365
|
+
activeChildIds,
|
|
9366
|
+
draggingNodeId: activeDrag.nodeId
|
|
9367
|
+
};
|
|
9368
|
+
}, [activeDrag, activeLaneContainerId, visibleCandidateContainerIds]);
|
|
9264
9369
|
(0, import_react16.useEffect)(() => {
|
|
9265
9370
|
if (!enabled || activeDrag) return;
|
|
9266
9371
|
if (undoRequestId === refs.processedUndoIdRef.current) return;
|
|
@@ -9323,7 +9428,7 @@ function DesignModeOverlay() {
|
|
|
9323
9428
|
safeZoneRef: refs.safeZoneRef,
|
|
9324
9429
|
autoScrollStateRef: refs.autoScrollStateRef
|
|
9325
9430
|
});
|
|
9326
|
-
useDragVisualLoop({ activeDrag, refs, getCommitLaneSnapshot, setInsideRect, setDropLine });
|
|
9431
|
+
useDragVisualLoop({ activeDrag, refs, getCommitLaneSnapshot, setInsideRect, setDropLine, setActiveLaneContainerId });
|
|
9327
9432
|
useExternalDragLoop({
|
|
9328
9433
|
externalDrag,
|
|
9329
9434
|
refs,
|
|
@@ -9343,7 +9448,6 @@ function DesignModeOverlay() {
|
|
|
9343
9448
|
DndContext,
|
|
9344
9449
|
{
|
|
9345
9450
|
sensors,
|
|
9346
|
-
collisionDetection,
|
|
9347
9451
|
autoScroll: false,
|
|
9348
9452
|
onDragStart: handleDragStart,
|
|
9349
9453
|
onDragEnd: handleDragEnd,
|
|
@@ -9352,10 +9456,8 @@ function DesignModeOverlay() {
|
|
|
9352
9456
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
9353
9457
|
ElementHighlight,
|
|
9354
9458
|
{
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
activeEl: refs.activeElRef.current,
|
|
9358
|
-
arrangeSelectedNodeId,
|
|
9459
|
+
selected: arrangeSelectedNodeId ? nodeMap.get(arrangeSelectedNodeId) ?? null : null,
|
|
9460
|
+
dragGuide,
|
|
9359
9461
|
externalDragActive: externalDrag !== null,
|
|
9360
9462
|
onResizeHandlePointerDown: handleResizeHandlePointerDown
|
|
9361
9463
|
}
|