fix(outliner): move entire subtree with all children during drag and drop
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m4s

This commit is contained in:
sandrodach committed 2026-10-27 16:00:03 +01:00
1 parent 266026da4c
commit 1bdd7d245d
2 files changed
+96 -14

No files matched your search

@@ -1072,22 +1072,60 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
);
const handleMoveBlock = useCallback(
(blockId: string, newIndex: number, level?: number) => {
(blockId: string, targetIndex: number, newLevel?: number) => {
if (!effectiveCanEdit) return;
setBlocks((prev) => {
const fromIdx = prev.findIndex((b) => b.id === blockId);
if (fromIdx === -1) return prev;
const parentBlock = prev[fromIdx];
const parentLevel = Math.max(0, parentBlock.level || 0);
// Calculate full subtree count (dragged block + all contiguous descendants)
let count = 1;
for (let i = fromIdx + 1; i < prev.length; i++) {
if (Math.max(0, prev[i].level || 0) > parentLevel) {
count++;
} else {
break;
}
}
// Prevent dropping inside its own subtree
if (targetIndex >= fromIdx && targetIndex < fromIdx + count) {
return prev;
}
const copy = [...prev];
const [moving] = copy.splice(fromIdx, 1);
const updatedMoving: DocumentBlock = {
...moving,
level: level !== undefined ? level : moving.level,
};
const boundedIdx = Math.max(0, Math.min(newIndex, copy.length));
copy.splice(boundedIdx, 0, updatedMoving);
const subtree = copy.splice(fromIdx, count);
// Adjust insertion index because removing elements from before shifts target index
let insertIndex = targetIndex;
if (fromIdx < targetIndex) {
insertIndex = targetIndex - count;
}
insertIndex = Math.max(0, Math.min(insertIndex, copy.length));
// Calculate level adjustments if moving to a constrained position
const prevBlockInPosition = insertIndex > 0 ? copy[insertIndex - 1] : null;
const maxAllowed = prevBlockInPosition
? Math.max(0, prevBlockInPosition.level || 0) + 1
: 0;
const targetLevel = newLevel !== undefined ? newLevel : parentLevel;
const clampedLevel = Math.min(targetLevel, maxAllowed);
const levelDelta = clampedLevel - parentLevel;
const updatedSubtree = subtree.map((b) => ({
...b,
level: Math.max(0, (b.level || 0) + levelDelta),
}));
copy.splice(insertIndex, 0, ...updatedSubtree);
const normalized = ensureNonEmptyBlocks(docId, copy);
if (isLiveEnabled) {
sendBlockMoved(blockId, boundedIdx, updatedMoving.level, normalized);
sendBlockMoved(blockId, insertIndex, updatedSubtree[0].level, normalized);
}
return normalized;
});