[WEB-1118] fix: table selections using drag handle fixed (#4429)

* fix: table selections in using drag handle fixed

* fix: not show drag handles for empty p tags
This commit is contained in:
M. Palanikannan 2024-05-10 17:32:23 +05:30 committed by GitHub
parent 88ebda42ff
commit 0ad8bf7664
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 82 additions and 47 deletions

View File

@ -97,6 +97,9 @@ const replaceCodeBlockWithContent = (editor: Editor) => {
const startPos = pos; const startPos = pos;
const endPos = pos + node.nodeSize; const endPos = pos + node.nodeSize;
const textContent = node.textContent; const textContent = node.textContent;
if (textContent.length === 0) {
editor.chain().focus().toggleCodeBlock().run();
}
replaceCodeBlock(startPos, endPos, textContent); replaceCodeBlock(startPos, endPos, textContent);
return false; return false;
} }

View File

@ -218,6 +218,10 @@ export const Table = Node.create({
addKeyboardShortcuts() { addKeyboardShortcuts() {
return { return {
Tab: () => { Tab: () => {
if (this.editor.isActive("table")) {
if (this.editor.isActive("listItem") || this.editor.isActive("taskItem")) {
return false;
}
if (this.editor.commands.goToNextCell()) { if (this.editor.commands.goToNextCell()) {
return true; return true;
} }
@ -227,6 +231,8 @@ export const Table = Node.create({
} }
return this.editor.chain().addRowAfter().goToNextCell().run(); return this.editor.chain().addRowAfter().goToNextCell().run();
}
return false;
}, },
"Shift-Tab": () => this.editor.commands.goToPreviousCell(), "Shift-Tab": () => this.editor.commands.goToPreviousCell(),
Backspace: deleteTableWhenAllCellsSelected, Backspace: deleteTableWhenAllCellsSelected,

View File

@ -15,7 +15,6 @@ export function CoreEditorProps(editorClassName: string): EditorProps {
if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) { if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) {
const slashCommand = document.querySelector("#slash-command"); const slashCommand = document.querySelector("#slash-command");
if (slashCommand) { if (slashCommand) {
console.log("registered");
return true; return true;
} }
} }

View File

@ -14,6 +14,21 @@ export interface DragHandleOptions {
}; };
} }
export const DragAndDrop = (setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void) =>
Extension.create({
name: "dragAndDrop",
addProseMirrorPlugins() {
return [
DragHandle({
dragHandleWidth: 24,
scrollThreshold: { up: 300, down: 100 },
setHideDragHandle,
}),
];
},
});
function createDragHandleElement(): HTMLElement { function createDragHandleElement(): HTMLElement {
const dragHandleElement = document.createElement("div"); const dragHandleElement = document.createElement("div");
dragHandleElement.draggable = true; dragHandleElement.draggable = true;
@ -49,23 +64,31 @@ function absoluteRect(node: Element) {
} }
function nodeDOMAtCoords(coords: { x: number; y: number }) { function nodeDOMAtCoords(coords: { x: number; y: number }) {
return document const elements = document.elementsFromPoint(coords.x, coords.y);
.elementsFromPoint(coords.x, coords.y) const generalSelectors = [
.find(
(elem: Element) =>
elem.parentElement?.matches?.(".ProseMirror") ||
elem.matches(
[
"li", "li",
"p:not(:first-child)", "p:not(:first-child)",
".code-block", ".code-block",
"blockquote", "blockquote",
"h1, h2, h3", "h1, h2, h3",
"table", ".table-wrapper",
"[data-type=horizontalRule]", "[data-type=horizontalRule]",
].join(", ") ].join(", ");
)
); for (const elem of elements) {
// if the element is a <p> tag that is the first child of a td or th
if (
(elem.matches("td > p:first-child") || elem.matches("th > p:first-child")) &&
elem?.textContent?.trim() !== ""
) {
return elem; // Return only if p tag is not empty
}
// apply general selector
if (elem.matches(generalSelectors)) {
return elem;
}
}
return null;
} }
function nodePosAtDOM(node: Element, view: EditorView, options: DragHandleOptions) { function nodePosAtDOM(node: Element, view: EditorView, options: DragHandleOptions) {
@ -86,15 +109,19 @@ function nodePosAtDOMForBlockquotes(node: Element, view: EditorView) {
})?.inside; })?.inside;
} }
function calcNodePos(pos: number, view: EditorView) { function calcNodePos(pos: number, view: EditorView, node: Element) {
const maxPos = view.state.doc.content.size; const maxPos = view.state.doc.content.size;
const safePos = Math.max(0, Math.min(pos, maxPos)); const safePos = Math.max(0, Math.min(pos, maxPos));
const $pos = view.state.doc.resolve(safePos); const $pos = view.state.doc.resolve(safePos);
if ($pos.depth > 1) { if ($pos.depth > 1) {
if (node.matches("ul:not([data-type=taskList]) li, ol li")) {
// only for nested lists
const newPos = $pos.before($pos.depth); const newPos = $pos.before($pos.depth);
return Math.max(0, Math.min(newPos, maxPos)); return Math.max(0, Math.min(newPos, maxPos));
} }
}
return safePos; return safePos;
} }
@ -114,12 +141,12 @@ function DragHandle(options: DragHandleOptions) {
let draggedNodePos = nodePosAtDOM(node, view, options); let draggedNodePos = nodePosAtDOM(node, view, options);
if (draggedNodePos == null || draggedNodePos < 0) return; if (draggedNodePos == null || draggedNodePos < 0) return;
draggedNodePos = calcNodePos(draggedNodePos, view); draggedNodePos = calcNodePos(draggedNodePos, view, node);
const { from, to } = view.state.selection; const { from, to } = view.state.selection;
const diff = from - to; const diff = from - to;
const fromSelectionPos = calcNodePos(from, view); const fromSelectionPos = calcNodePos(from, view, node);
let differentNodeSelected = false; let differentNodeSelected = false;
const nodePos = view.state.doc.resolve(fromSelectionPos); const nodePos = view.state.doc.resolve(fromSelectionPos);
@ -148,6 +175,19 @@ function DragHandle(options: DragHandleOptions) {
listType = node.parentElement!.tagName; listType = node.parentElement!.tagName;
} }
if (node.matches("blockquote")) {
let nodePosForBlockquotes = nodePosAtDOMForBlockquotes(node, view);
if (nodePosForBlockquotes === null || nodePosForBlockquotes === undefined) return;
const docSize = view.state.doc.content.size;
nodePosForBlockquotes = Math.max(0, Math.min(nodePosForBlockquotes, docSize));
if (nodePosForBlockquotes >= 0 && nodePosForBlockquotes <= docSize) {
const nodeSelection = NodeSelection.create(view.state.doc, nodePosForBlockquotes);
view.dispatch(view.state.tr.setSelection(nodeSelection));
}
}
const slice = view.state.selection.content(); const slice = view.state.selection.content();
const { dom, text } = __serializeForClipboard(view, slice); const { dom, text } = __serializeForClipboard(view, slice);
@ -190,7 +230,7 @@ function DragHandle(options: DragHandleOptions) {
if (nodePos === null || nodePos === undefined) return; if (nodePos === null || nodePos === undefined) return;
// Adjust the nodePos to point to the start of the node, ensuring NodeSelection can be applied // Adjust the nodePos to point to the start of the node, ensuring NodeSelection can be applied
nodePos = calcNodePos(nodePos, view); nodePos = calcNodePos(nodePos, view, node);
// Use NodeSelection to select the node at the calculated position // Use NodeSelection to select the node at the calculated position
const nodeSelection = NodeSelection.create(view.state.doc, nodePos); const nodeSelection = NodeSelection.create(view.state.doc, nodePos);
@ -279,9 +319,11 @@ function DragHandle(options: DragHandleOptions) {
// Li markers // Li markers
if (node.matches("ul:not([data-type=taskList]) li, ol li")) { if (node.matches("ul:not([data-type=taskList]) li, ol li")) {
rect.top += 4;
rect.left -= 18; rect.left -= 18;
} }
if (node.matches(".table-wrapper")) {
rect.top += 8;
}
rect.width = options.dragHandleWidth; rect.width = options.dragHandleWidth;
@ -352,18 +394,3 @@ function DragHandle(options: DragHandleOptions) {
}, },
}); });
} }
export const DragAndDrop = (setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void) =>
Extension.create({
name: "dragAndDrop",
addProseMirrorPlugins() {
return [
DragHandle({
dragHandleWidth: 24,
scrollThreshold: { up: 300, down: 100 },
setHideDragHandle,
}),
];
},
});