diff --git a/packages/client/src/tiptap/core/extensions/dragable.ts b/packages/client/src/tiptap/core/extensions/dragable.ts
new file mode 100644
index 00000000..d5b1c3b1
--- /dev/null
+++ b/packages/client/src/tiptap/core/extensions/dragable.ts
@@ -0,0 +1,130 @@
+import { Extension } from '@tiptap/core';
+import { Plugin } from 'prosemirror-state';
+import { NodeSelection } from 'prosemirror-state';
+import { __serializeForClipboard } from 'prosemirror-view';
+
+function createRect(rect) {
+ if (rect == null) {
+ return null;
+ }
+ const newRect = {
+ left: rect.left + document.body.scrollLeft,
+ top: rect.top + document.body.scrollTop,
+ width: rect.width,
+ height: rect.height,
+ bottom: 0,
+ right: 0,
+ };
+ newRect.bottom = newRect.top + newRect.height;
+ newRect.right = newRect.left + newRect.width;
+ return newRect;
+}
+
+function absoluteRect(element) {
+ return createRect(element.getBoundingClientRect());
+}
+
+export const Dragable = Extension.create({
+ name: 'dragable',
+
+ addProseMirrorPlugins() {
+ let dropElement;
+ let currentNode;
+ let editorView;
+ const WIDTH = 24;
+
+ function drag(e) {
+ if (!currentNode || currentNode.nodeType !== 1) return;
+ let pos = null;
+ const desc = editorView.docView.nearestDesc(currentNode, true);
+
+ if (!(!desc || desc === editorView.docView)) {
+ pos = desc.posBefore;
+ }
+
+ if (!pos) return;
+
+ editorView.dispatch(editorView.state.tr.setSelection(NodeSelection.create(editorView.state.doc, pos)));
+ const slice = editorView.state.selection.content();
+ const { dom, text } = __serializeForClipboard(editorView, slice);
+ e.dataTransfer.clearData();
+ e.dataTransfer.setData('text/html', dom.innerHTML);
+ e.dataTransfer.setData('text/plain', text);
+ editorView.dragging = { slice, move: true };
+ }
+
+ return [
+ new Plugin({
+ view(view) {
+ editorView = view;
+ dropElement = document.createElement('div');
+ dropElement.setAttribute('draggable', 'true');
+ dropElement.className = 'drag-handler';
+ dropElement.addEventListener('dragstart', drag);
+ view.dom.parentElement.appendChild(dropElement);
+
+ return {
+ update(view) {
+ editorView = view;
+ },
+ destroy() {
+ if (dropElement && dropElement.parentNode) {
+ dropElement.removeEventListener('dragstart', drag);
+ dropElement.parentNode.removeChild(dropElement);
+ }
+ },
+ };
+ },
+ props: {
+ handleDOMEvents: {
+ drop() {
+ dropElement.style.opacity = 0;
+ setTimeout(() => {
+ const node = document.querySelector('.ProseMirror-hideselection');
+ if (node) {
+ node.classList.remove('ProseMirror-hideselection');
+ }
+ }, 50);
+ },
+ mousemove(view, event) {
+ const coords = { left: event.clientX, top: event.clientY };
+ const pos = view.posAtCoords(coords);
+
+ if (!pos) return;
+
+ let node = view.domAtPos(pos.pos);
+
+ node = node.node;
+
+ while (node && node.parentNode) {
+ if (node.parentNode?.classList?.contains?.('ProseMirror')) {
+ break;
+ }
+ node = node.parentNode;
+ }
+
+ if (!node || !node.getBoundingClientRect) {
+ return;
+ }
+
+ if (node?.classList?.contains('node-title') || node?.classList?.contains('node-table')) {
+ return;
+ }
+
+ currentNode = node;
+
+ const rect = absoluteRect(node);
+ const win = node.ownerDocument.defaultView;
+ rect.top += win.pageYOffset;
+ rect.left += win.pageXOffset;
+ rect.width = WIDTH + 'px';
+ dropElement.style.left = rect.left - WIDTH + 'px';
+ dropElement.style.top = rect.top + 6 + 'px';
+ dropElement.style.opacity = 1;
+ },
+ },
+ },
+ }),
+ ];
+ },
+});
diff --git a/packages/client/src/tiptap/core/extensions/paragraph.ts b/packages/client/src/tiptap/core/extensions/paragraph.ts
index c13cae25..7e25a7f4 100644
--- a/packages/client/src/tiptap/core/extensions/paragraph.ts
+++ b/packages/client/src/tiptap/core/extensions/paragraph.ts
@@ -1,12 +1,3 @@
import TitapParagraph from '@tiptap/extension-paragraph';
-import { ReactNodeViewRenderer } from '@tiptap/react';
-import { ParagraphWrapper } from '../wrappers/paragraph';
-
-export const Paragraph = TitapParagraph.extend({
- draggable: true,
-
- addNodeView() {
- return ReactNodeViewRenderer(ParagraphWrapper);
- },
-});
+export const Paragraph = TitapParagraph.extend({});
diff --git a/packages/client/src/tiptap/core/styles/base.scss b/packages/client/src/tiptap/core/styles/base.scss
index 91bd3c96..8a51a3e0 100644
--- a/packages/client/src/tiptap/core/styles/base.scss
+++ b/packages/client/src/tiptap/core/styles/base.scss
@@ -70,6 +70,7 @@
}
p {
+ margin-top: 0.75rem;
margin-bottom: 0;
font-size: 1em;
font-weight: normal;
diff --git a/packages/client/src/tiptap/core/styles/drag.scss b/packages/client/src/tiptap/core/styles/drag.scss
new file mode 100644
index 00000000..2841b243
--- /dev/null
+++ b/packages/client/src/tiptap/core/styles/drag.scss
@@ -0,0 +1,11 @@
+.drag-handler {
+ position: fixed;
+ width: 16px;
+ height: 16px;
+ cursor: grab;
+ opacity: 1;
+ background-image: url('data:image/svg+xml;charset=UTF-8,');
+ background-repeat: no-repeat;
+ background-size: contain;
+ background-position: center;
+}
diff --git a/packages/client/src/tiptap/core/styles/index.scss b/packages/client/src/tiptap/core/styles/index.scss
index 72c9d469..db29c736 100644
--- a/packages/client/src/tiptap/core/styles/index.scss
+++ b/packages/client/src/tiptap/core/styles/index.scss
@@ -17,3 +17,4 @@
@import './table.scss';
@import './title.scss';
@import './kityminder.scss';
+@import './drag.scss';
diff --git a/packages/client/src/tiptap/core/wrappers/dragable/index.module.scss b/packages/client/src/tiptap/core/wrappers/dragable/index.module.scss
index 798e77de..8487d957 100644
--- a/packages/client/src/tiptap/core/wrappers/dragable/index.module.scss
+++ b/packages/client/src/tiptap/core/wrappers/dragable/index.module.scss
@@ -5,9 +5,9 @@
.dragHandle {
position: absolute;
top: 0.3rem;
- left: -1.5rem;
- width: 1rem;
- height: 1rem;
+ left: -24px;
+ width: 16px;
+ height: 16px;
cursor: grab;
opacity: 0;
background-image: url('data:image/svg+xml;charset=UTF-8,');
diff --git a/packages/client/src/tiptap/core/wrappers/paragraph/index.module.scss b/packages/client/src/tiptap/core/wrappers/paragraph/index.module.scss
deleted file mode 100644
index 98cee0ac..00000000
--- a/packages/client/src/tiptap/core/wrappers/paragraph/index.module.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.paragraph {
- margin-top: 0.75em;
-}
diff --git a/packages/client/src/tiptap/core/wrappers/paragraph/index.tsx b/packages/client/src/tiptap/core/wrappers/paragraph/index.tsx
deleted file mode 100644
index cc706e85..00000000
--- a/packages/client/src/tiptap/core/wrappers/paragraph/index.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { NodeViewContent } from '@tiptap/react';
-import { useCallback } from 'react';
-import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
-
-import styles from './index.module.scss';
-
-export const ParagraphWrapper = ({ editor }) => {
- const prevent = useCallback((e) => {
- e.prevntDefault();
- return false;
- }, []);
-
- return (
-
-
-
- );
-};
diff --git a/packages/client/src/tiptap/editor/collaboration/kit.ts b/packages/client/src/tiptap/editor/collaboration/kit.ts
index 50d23f17..deba6268 100644
--- a/packages/client/src/tiptap/editor/collaboration/kit.ts
+++ b/packages/client/src/tiptap/editor/collaboration/kit.ts
@@ -16,6 +16,7 @@ import { Countdown } from 'tiptap/core/extensions/countdown';
import { Document } from 'tiptap/core/extensions/document';
import { DocumentChildren } from 'tiptap/core/extensions/document-children';
import { DocumentReference } from 'tiptap/core/extensions/document-reference';
+import { Dragable } from 'tiptap/core/extensions/dragable';
import { Dropcursor } from 'tiptap/core/extensions/dropcursor';
import { Emoji } from 'tiptap/core/extensions/emoji';
import { EventEmitter } from 'tiptap/core/extensions/event-emitter';
@@ -98,6 +99,7 @@ export const CollaborationKit = [
CodeBlock,
Color,
ColorHighlighter,
+ Dragable,
Dropcursor,
EventEmitter,
Focus,