editor: improve move node logic

Signed-off-by: 01zulfi <85733202+01zulfi@users.noreply.github.com>
This commit is contained in:
01zulfi
2025-12-01 11:17:26 +05:00
parent 2955c7c65c
commit fc8ea74d39

View File

@@ -22,7 +22,6 @@ import OrderedList from "@tiptap/extension-ordered-list";
import { Fragment, Node, Slice } from "@tiptap/pm/model"; import { Fragment, Node, Slice } from "@tiptap/pm/model";
import { Selection } from "@tiptap/pm/state"; import { Selection } from "@tiptap/pm/state";
import { ReplaceStep } from "@tiptap/pm/transform"; import { ReplaceStep } from "@tiptap/pm/transform";
import { isListActive } from "../../utils/list.js";
import { import {
findParentNodeClosestToPos, findParentNodeClosestToPos,
findParentNodeOfType findParentNodeOfType
@@ -34,9 +33,12 @@ import { CheckList } from "../check-list/check-list.js";
import { OutlineList } from "../outline-list/outline-list.js"; import { OutlineList } from "../outline-list/outline-list.js";
import { Table } from "../table/table.js"; import { Table } from "../table/table.js";
import { TaskListNode } from "../task-list/task-list.js"; import { TaskListNode } from "../task-list/task-list.js";
import { ListItem } from "../list-item/list-item.js";
import { CheckListItem } from "../check-list-item/check-list-item.js";
import { TaskItemNode } from "../task-item/task-item.js";
import { OutlineListItem } from "../outline-list-item/outline-list-item.js";
type ResolvedNode = { type ResolvedNode = {
pos: number;
start: number; start: number;
depth: number; depth: number;
node: Node; node: Node;
@@ -55,77 +57,77 @@ function mapChildren<T>(
return array; return array;
} }
function resolveNode(editor: Editor) { const listItems = [
ListItem.name,
CheckListItem.name,
TaskItemNode.name,
OutlineListItem.name
];
function resolveNode(editor: Editor): ResolvedNode | undefined {
const { state } = editor; const { state } = editor;
const { $from } = state.selection; const { $from } = state.selection;
let targetType = $from.node().type; const currentNode = $from.node();
let currentResolved = findParentNodeOfType(targetType)(state.selection); const parentNode = $from.node($from.depth - 1);
let targetType = currentNode.type;
let currentResolved: ResolvedNode | undefined = {
start: $from.start(),
depth: $from.depth,
node: currentNode
};
if (isListActive(editor)) { if (listItems.includes(parentNode.type.name)) {
const currentNode = $from.node();
const parentNode = $from.node($from.depth - 1);
const isFirstParagraph = const isFirstParagraph =
currentNode.type.name === "paragraph" && currentNode.type.name === "paragraph" &&
parentNode.firstChild === currentNode; parentNode.firstChild === currentNode;
// move the entire list item
if (isFirstParagraph) { if (isFirstParagraph) {
targetType = $from.node($from.depth - 1).type; targetType = parentNode.type;
if ( currentResolved = findParentNodeOfType(targetType)(state.selection);
targetType.name === Callout.name ||
targetType.name === Blockquote.name
) {
targetType = $from.node($from.depth - 2).type;
}
} }
currentResolved = findParentNodeOfType(targetType)(state.selection);
} }
if ( if (parentNode.type.name === Callout.name) {
findParentNodeClosestToPos($from, (node) => node.type.name === Callout.name)
) {
const currentNode = $from.node();
const parentNode = $from.node($from.depth - 1);
const isFirstHeading = const isFirstHeading =
currentNode.type.name === "heading" && currentNode.type.name === "heading" &&
parentNode.firstChild === currentNode; parentNode.firstChild === currentNode;
// move the entire callout
if (isFirstHeading) { if (isFirstHeading) {
targetType = $from.node($from.depth - 1).type; targetType = parentNode.type;
currentResolved = findParentNodeOfType(targetType)(state.selection);
} }
currentResolved = findParentNodeOfType(targetType)(state.selection);
} }
return currentResolved; return currentResolved;
} }
function resolveParentNode(editor: Editor) { const validParents = [
Callout.name,
Table.name,
BulletList.name,
OrderedList.name,
TaskListNode.name,
CheckList.name,
OutlineList.name,
Blockquote.name
];
function resolveParentNode(editor: Editor): ResolvedNode | undefined {
const { state } = editor; const { state } = editor;
const { $from } = state.selection; const { $from } = state.selection;
const validParents = [
Callout.name,
Table.name,
BulletList.name,
OrderedList.name,
TaskListNode.name,
CheckList.name,
OutlineList.name,
Blockquote.name
];
const parent = findParentNodeClosestToPos($from, (node) => const parent = findParentNodeClosestToPos($from, (node) =>
validParents.includes(node.type.name) validParents.includes(node.type.name)
); );
if (!parent) return undefined; if (!parent) return undefined;
const targetType = parent.node.type; return {
return findParentNodeOfType(targetType)(state.selection); start: parent.start,
depth: parent.depth,
node: parent.node
};
} }
function swapNodeWithSibling( function swapNodeWithSibling(