mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
Merge branch 'fix/drag-handles' into chore/page-transactions
This commit is contained in:
commit
c5814acb09
@ -1,9 +1,13 @@
|
|||||||
import { Extension } from "@tiptap/core";
|
import { Extension } from "@tiptap/core";
|
||||||
|
|
||||||
import { PluginKey, NodeSelection, Plugin } from "@tiptap/pm/state";
|
import { NodeSelection, Plugin, PluginKey } from "@tiptap/pm/state";
|
||||||
// @ts-ignore
|
// @ts-expect-error __serializeForClipboard's is not exported
|
||||||
import { __serializeForClipboard, EditorView } from "@tiptap/pm/view";
|
import { __serializeForClipboard, EditorView } from "@tiptap/pm/view";
|
||||||
import React from "react";
|
|
||||||
|
export interface DragHandleOptions {
|
||||||
|
dragHandleWidth: number;
|
||||||
|
setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void;
|
||||||
|
}
|
||||||
|
|
||||||
function createDragHandleElement(): HTMLElement {
|
function createDragHandleElement(): HTMLElement {
|
||||||
const dragHandleElement = document.createElement("div");
|
const dragHandleElement = document.createElement("div");
|
||||||
@ -29,13 +33,8 @@ function createDragHandleElement(): HTMLElement {
|
|||||||
return dragHandleElement;
|
return dragHandleElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DragHandleOptions {
|
|
||||||
dragHandleWidth: number;
|
|
||||||
setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function absoluteRect(node: Element) {
|
function absoluteRect(node: Element) {
|
||||||
const data = node?.getBoundingClientRect();
|
const data = node.getBoundingClientRect();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
top: data.top,
|
top: data.top,
|
||||||
@ -51,40 +50,18 @@ function nodeDOMAtCoords(coords: { x: number; y: number }) {
|
|||||||
(elem: Element) =>
|
(elem: Element) =>
|
||||||
elem.parentElement?.matches?.(".ProseMirror") ||
|
elem.parentElement?.matches?.(".ProseMirror") ||
|
||||||
elem.matches(
|
elem.matches(
|
||||||
[
|
["li", "p:not(:first-child)", "pre", "blockquote", "h1, h2, h3", "table", "[data-type=horizontalRule]"].join(
|
||||||
"li",
|
", "
|
||||||
"p:not(:first-child)",
|
)
|
||||||
"pre",
|
|
||||||
"blockquote",
|
|
||||||
"h1, h2, h3",
|
|
||||||
"[data-type=horizontalRule]",
|
|
||||||
".tableWrapper",
|
|
||||||
].join(", ")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function nodePosAtDOM(node: Element, view: EditorView) {
|
function nodePosAtDOM(node: Element, view: EditorView, options: DragHandleOptions) {
|
||||||
const boundingRect = node?.getBoundingClientRect();
|
const boundingRect = node.getBoundingClientRect();
|
||||||
|
|
||||||
if (node.nodeName === "IMG") {
|
|
||||||
return view.posAtCoords({
|
|
||||||
left: boundingRect.left + 1,
|
|
||||||
top: boundingRect.top + 1,
|
|
||||||
})?.pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.nodeName === "PRE") {
|
|
||||||
return (
|
|
||||||
view.posAtCoords({
|
|
||||||
left: boundingRect.left + 1,
|
|
||||||
top: boundingRect.top + 1,
|
|
||||||
})?.pos! - 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return view.posAtCoords({
|
return view.posAtCoords({
|
||||||
left: boundingRect.left + 1,
|
left: boundingRect.left + 50 + options.dragHandleWidth,
|
||||||
top: boundingRect.top + 1,
|
top: boundingRect.top + 1,
|
||||||
})?.inside;
|
})?.inside;
|
||||||
}
|
}
|
||||||
@ -96,14 +73,14 @@ function DragHandle(options: DragHandleOptions) {
|
|||||||
if (!event.dataTransfer) return;
|
if (!event.dataTransfer) return;
|
||||||
|
|
||||||
const node = nodeDOMAtCoords({
|
const node = nodeDOMAtCoords({
|
||||||
x: event.clientX + options.dragHandleWidth + 50,
|
x: event.clientX + 50 + options.dragHandleWidth,
|
||||||
y: event.clientY,
|
y: event.clientY,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(node instanceof Element)) return;
|
if (!(node instanceof Element)) return;
|
||||||
|
|
||||||
const nodePos = nodePosAtDOM(node, view);
|
const nodePos = nodePosAtDOM(node, view, options);
|
||||||
if (nodePos === null || nodePos === undefined || nodePos < 0) return;
|
if (nodePos == null || nodePos < 0) return;
|
||||||
|
|
||||||
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)));
|
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)));
|
||||||
|
|
||||||
@ -132,9 +109,8 @@ function DragHandle(options: DragHandleOptions) {
|
|||||||
|
|
||||||
if (!(node instanceof Element)) return;
|
if (!(node instanceof Element)) return;
|
||||||
|
|
||||||
const nodePos = nodePosAtDOM(node, view);
|
const nodePos = nodePosAtDOM(node, view, options);
|
||||||
|
if (!nodePos) return;
|
||||||
if (nodePos === null || nodePos === undefined || nodePos < 0) return;
|
|
||||||
|
|
||||||
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)));
|
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)));
|
||||||
}
|
}
|
||||||
@ -192,11 +168,11 @@ function DragHandle(options: DragHandleOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const node = nodeDOMAtCoords({
|
const node = nodeDOMAtCoords({
|
||||||
x: event.clientX + options.dragHandleWidth,
|
x: event.clientX + 50 + options.dragHandleWidth,
|
||||||
y: event.clientY,
|
y: event.clientY,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(node instanceof Element)) {
|
if (!(node instanceof Element) || node.matches("ul, ol")) {
|
||||||
hideDragHandle();
|
hideDragHandle();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -207,7 +183,7 @@ function DragHandle(options: DragHandleOptions) {
|
|||||||
|
|
||||||
const rect = absoluteRect(node);
|
const rect = absoluteRect(node);
|
||||||
|
|
||||||
rect.top += (lineHeight - 24) / 2;
|
rect.top += (lineHeight - 20) / 2;
|
||||||
rect.top += paddingTop;
|
rect.top += paddingTop;
|
||||||
// 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")) {
|
||||||
@ -218,21 +194,22 @@ function DragHandle(options: DragHandleOptions) {
|
|||||||
if (!dragHandleElement) return;
|
if (!dragHandleElement) return;
|
||||||
|
|
||||||
dragHandleElement.style.left = `${rect.left - rect.width}px`;
|
dragHandleElement.style.left = `${rect.left - rect.width}px`;
|
||||||
dragHandleElement.style.top = `${rect.top + 3}px`;
|
dragHandleElement.style.top = `${rect.top}px`;
|
||||||
showDragHandle();
|
showDragHandle();
|
||||||
},
|
},
|
||||||
keydown: () => {
|
keydown: () => {
|
||||||
hideDragHandle();
|
hideDragHandle();
|
||||||
},
|
},
|
||||||
wheel: () => {
|
mousewheel: () => {
|
||||||
hideDragHandle();
|
hideDragHandle();
|
||||||
},
|
},
|
||||||
// dragging className is used for CSS
|
dragenter: (view) => {
|
||||||
dragstart: (view) => {
|
|
||||||
view.dom.classList.add("dragging");
|
view.dom.classList.add("dragging");
|
||||||
|
hideDragHandle();
|
||||||
},
|
},
|
||||||
drop: (view) => {
|
drop: (view) => {
|
||||||
view.dom.classList.remove("dragging");
|
view.dom.classList.remove("dragging");
|
||||||
|
hideDragHandle();
|
||||||
},
|
},
|
||||||
dragend: (view) => {
|
dragend: (view) => {
|
||||||
view.dom.classList.remove("dragging");
|
view.dom.classList.remove("dragging");
|
||||||
|
@ -54,7 +54,20 @@ const Command = Extension.create<SlashCommandOptions>({
|
|||||||
props.command({ editor, range });
|
props.command({ editor, range });
|
||||||
},
|
},
|
||||||
allow({ editor }: { editor: Editor }) {
|
allow({ editor }: { editor: Editor }) {
|
||||||
return !editor.isActive("table");
|
const { selection } = editor.state;
|
||||||
|
|
||||||
|
const parentNode = selection.$from.node(selection.$from.depth);
|
||||||
|
const blockType = parentNode.type.name;
|
||||||
|
|
||||||
|
if (blockType === "codeBlock") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editor.isActive("table")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
allowSpaces: true,
|
allowSpaces: true,
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity ease-in 0.2s;
|
transition: opacity ease-in 0.2s;
|
||||||
height: 18px;
|
height: 20px;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
@ -12,9 +12,24 @@
|
|||||||
background-color: rgb(var(--color-background-90));
|
background-color: rgb(var(--color-background-90));
|
||||||
}
|
}
|
||||||
|
|
||||||
.drag-handle:hover {
|
.ProseMirror:not(.dragging) .ProseMirror-selectednode {
|
||||||
background-color: rgb(var(--color-background-80));
|
outline: none !important;
|
||||||
|
cursor: grab;
|
||||||
|
background-color: #1f2937;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle:hover {
|
||||||
|
background-color: #4d4d4d;
|
||||||
|
cursor: grab;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle:active {
|
||||||
|
background-color: #4d4d4d;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
cursor: grabbing;
|
||||||
}
|
}
|
||||||
|
|
||||||
.drag-handle.hidden {
|
.drag-handle.hidden {
|
||||||
|
@ -2733,7 +2733,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^18.2.42":
|
"@types/react@*", "@types/react@18.2.42", "@types/react@^18.2.42":
|
||||||
version "18.2.42"
|
version "18.2.42"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.42.tgz#6f6b11a904f6d96dda3c2920328a97011a00aba7"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.42.tgz#6f6b11a904f6d96dda3c2920328a97011a00aba7"
|
||||||
integrity sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==
|
integrity sha512-c1zEr96MjakLYus/wPnuWDo1/zErfdU9rNsIGmE+NV71nx88FG9Ttgo5dqorXTu/LImX2f63WBP986gJkMPNbA==
|
||||||
|
Loading…
Reference in New Issue
Block a user