mirror of https://github.com/fantasticit/think.git
tiptap: improve drag
This commit is contained in:
parent
9560066cfa
commit
5f773ec988
|
@ -28,6 +28,7 @@ export const Dragable = Extension.create({
|
||||||
name: 'dragable',
|
name: 'dragable',
|
||||||
|
|
||||||
addProseMirrorPlugins() {
|
addProseMirrorPlugins() {
|
||||||
|
let scrollContainer;
|
||||||
let dropElement;
|
let dropElement;
|
||||||
let currentNode;
|
let currentNode;
|
||||||
let editorView;
|
let editorView;
|
||||||
|
@ -54,6 +55,11 @@ export const Dragable = Extension.create({
|
||||||
editorView.dragging = { slice, move: true };
|
editorView.dragging = { slice, move: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onScroll() {
|
||||||
|
if (!dropElement) return;
|
||||||
|
dropElement.style.opacity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new Plugin({
|
new Plugin({
|
||||||
view(view) {
|
view(view) {
|
||||||
|
@ -64,6 +70,12 @@ export const Dragable = Extension.create({
|
||||||
dropElement.className = 'drag-handler';
|
dropElement.className = 'drag-handler';
|
||||||
dropElement.addEventListener('dragstart', drag);
|
dropElement.addEventListener('dragstart', drag);
|
||||||
view.dom.parentElement.appendChild(dropElement);
|
view.dom.parentElement.appendChild(dropElement);
|
||||||
|
|
||||||
|
scrollContainer = view.dom.parentElement.parentElement?.parentElement?.parentElement;
|
||||||
|
|
||||||
|
if (scrollContainer) {
|
||||||
|
scrollContainer.addEventListener('scroll', onScroll);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -75,6 +87,10 @@ export const Dragable = Extension.create({
|
||||||
dropElement.removeEventListener('dragstart', drag);
|
dropElement.removeEventListener('dragstart', drag);
|
||||||
dropElement.parentNode.removeChild(dropElement);
|
dropElement.parentNode.removeChild(dropElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scrollContainer) {
|
||||||
|
scrollContainer.removeEventListener('scroll', onScroll);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -91,7 +107,7 @@ export const Dragable = Extension.create({
|
||||||
}
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
},
|
},
|
||||||
mousemove(view, event) {
|
mousedown(view, event) {
|
||||||
if (!dropElement) return;
|
if (!dropElement) return;
|
||||||
|
|
||||||
const coords = { left: event.clientX, top: event.clientY };
|
const coords = { left: event.clientX, top: event.clientY };
|
||||||
|
@ -134,10 +150,6 @@ export const Dragable = Extension.create({
|
||||||
dropElement.style.top = rect.top + 6 + 'px';
|
dropElement.style.top = rect.top + 6 + 'px';
|
||||||
dropElement.style.opacity = 1;
|
dropElement.style.opacity = 1;
|
||||||
},
|
},
|
||||||
mouseleave() {
|
|
||||||
if (!dropElement || currentNode) return;
|
|
||||||
dropElement.style.opacity = 0;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { Tooltip } from 'components/tooltip';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { uploadFile } from 'services/file';
|
import { uploadFile } from 'services/file';
|
||||||
|
import { Attachment } from 'tiptap/core/extensions/attachment';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
import { download, extractFileExtension, extractFilename, normalizeFileSize } from 'tiptap/prose-utils';
|
import { download, extractFileExtension, extractFilename, normalizeFileSize } from 'tiptap/prose-utils';
|
||||||
|
|
||||||
|
@ -154,5 +155,9 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return <DragableWrapper editor={editor}>{content}</DragableWrapper>;
|
return (
|
||||||
|
<DragableWrapper editor={editor} extensionName={Attachment.name}>
|
||||||
|
{content}
|
||||||
|
</DragableWrapper>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { EmojiPicker } from 'components/emoji-picker';
|
||||||
import { convertColorToRGBA } from 'helpers/color';
|
import { convertColorToRGBA } from 'helpers/color';
|
||||||
import { Theme, ThemeEnum } from 'hooks/use-theme';
|
import { Theme, ThemeEnum } from 'hooks/use-theme';
|
||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { Callout } from 'tiptap/core/extensions/callout';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -26,7 +27,12 @@ export const CalloutWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor} id="js-callout-container" className={cls(styles.wrap)}>
|
<DragableWrapper
|
||||||
|
editor={editor}
|
||||||
|
extensionName={Callout.name}
|
||||||
|
id="js-callout-container"
|
||||||
|
className={cls(styles.wrap)}
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
className={cls(styles.innerWrap, 'render-wrapper')}
|
className={cls(styles.innerWrap, 'render-wrapper')}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { NodeViewContent } from '@tiptap/react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { copy } from 'helpers/copy';
|
import { copy } from 'helpers/copy';
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
|
import { CodeBlock } from 'tiptap/core/extensions/code-block';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -14,7 +15,7 @@ export const CodeBlockWrapper = ({ editor, node: { attrs }, updateAttributes, ex
|
||||||
const $container = useRef<HTMLPreElement>();
|
const $container = useRef<HTMLPreElement>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor} className={cls(styles.wrap, 'render-wrapper')}>
|
<DragableWrapper editor={editor} extensionName={CodeBlock.name} className={cls(styles.wrap, 'render-wrapper')}>
|
||||||
<div className={styles.handleWrap}>
|
<div className={styles.handleWrap}>
|
||||||
<Select
|
<Select
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Space, Typography } from '@douyinfe/semi-ui';
|
import { Space, Typography } from '@douyinfe/semi-ui';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import Countdown from 'react-countdown';
|
import ReactCountdown from 'react-countdown';
|
||||||
|
import { Countdown } from 'tiptap/core/extensions/countdown';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -32,10 +33,10 @@ export const CountdownWrapper = ({ editor, node }) => {
|
||||||
const { title, date } = node.attrs;
|
const { title, date } = node.attrs;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor}>
|
<DragableWrapper editor={editor} extensionName={Countdown.name}>
|
||||||
<div className={cls(styles.wrap, 'render-wrapper')}>
|
<div className={cls(styles.wrap, 'render-wrapper')}>
|
||||||
<Text>{title}</Text>
|
<Text>{title}</Text>
|
||||||
<Countdown date={date} renderer={renderer}></Countdown>
|
<ReactCountdown date={date} renderer={renderer}></ReactCountdown>
|
||||||
</div>
|
</div>
|
||||||
</DragableWrapper>
|
</DragableWrapper>
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { useChildrenDocument } from 'data/document';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { DocumentChildren } from 'tiptap/core/extensions/document-children';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -37,6 +38,7 @@ export const DocumentChildrenWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
return (
|
return (
|
||||||
<DragableWrapper
|
<DragableWrapper
|
||||||
editor={editor}
|
editor={editor}
|
||||||
|
extensionName={DocumentChildren.name}
|
||||||
as="div"
|
as="div"
|
||||||
className={cls('render-wrapper', styles.wrap, isEditable && styles.isEditable, 'documentChildren')}
|
className={cls('render-wrapper', styles.wrap, isEditable && styles.isEditable, 'documentChildren')}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { IconDocument } from 'components/icons';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { DocumentReference } from 'tiptap/core/extensions/document-reference';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -50,7 +51,12 @@ export const DocumentReferenceWrapper = ({ editor, node, updateAttributes }) =>
|
||||||
}, [organizationId, wikiId, documentId, isEditable, isShare, title]);
|
}, [organizationId, wikiId, documentId, isEditable, isShare, title]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor} as="div" className={cls(styles.wrap, isEditable && 'render-wrapper')}>
|
<DragableWrapper
|
||||||
|
editor={editor}
|
||||||
|
extensionName={DocumentReference.name}
|
||||||
|
as="div"
|
||||||
|
className={cls(styles.wrap, isEditable && 'render-wrapper')}
|
||||||
|
>
|
||||||
{content}
|
{content}
|
||||||
</DragableWrapper>
|
</DragableWrapper>
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.isEditable {
|
&.isEditable {
|
||||||
&:hover {
|
&.isActive {
|
||||||
.dragHandle {
|
.dragHandle {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,23 +2,26 @@ import { Editor } from '@tiptap/core';
|
||||||
import { NodeViewWrapper } from '@tiptap/react';
|
import { NodeViewWrapper } from '@tiptap/react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import React, { ElementType } from 'react';
|
import React, { ElementType } from 'react';
|
||||||
|
import { useActive } from 'tiptap/core/hooks/use-active';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
export const DragableWrapper: React.FC<{
|
export const DragableWrapper: React.FC<{
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
|
extensionName: string;
|
||||||
as?: ElementType;
|
as?: ElementType;
|
||||||
id?: string;
|
id?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
}> = ({ editor, as = 'div', id, className, style = {}, children }) => {
|
}> = ({ editor, extensionName, as = 'div', id, className, style = {}, children }) => {
|
||||||
const isEditable = editor.isEditable;
|
const isEditable = editor.isEditable;
|
||||||
|
const isActive = useActive(editor, extensionName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper
|
<NodeViewWrapper
|
||||||
as={as}
|
as={as}
|
||||||
id={id}
|
id={id}
|
||||||
className={cls(styles.draggableItem, isEditable && styles.isEditable, className)}
|
className={cls(styles.draggableItem, isEditable && styles.isEditable, isActive && styles.isActive, className)}
|
||||||
style={style}
|
style={style}
|
||||||
>
|
>
|
||||||
<div className={styles.dragHandle} contentEditable="false" draggable="true" data-drag-handle />
|
<div className={styles.dragHandle} contentEditable="false" draggable="true" data-drag-handle />
|
||||||
|
|
|
@ -95,7 +95,11 @@ export const FlowWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
}, [toggleLoading, data]);
|
}, [toggleLoading, data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor} className={cls(styles.wrap, isActive && styles.isActive)}>
|
<DragableWrapper
|
||||||
|
editor={editor}
|
||||||
|
className={cls(styles.wrap, isActive && styles.isActive)}
|
||||||
|
extensionName={Flow.name}
|
||||||
|
>
|
||||||
<VisibilitySensor onChange={onViewportChange}>
|
<VisibilitySensor onChange={onViewportChange}>
|
||||||
<Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}>
|
<Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Typography } from '@douyinfe/semi-ui';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { Resizeable } from 'components/resizeable';
|
import { Resizeable } from 'components/resizeable';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
import { Iframe } from 'tiptap/core/extensions/iframe';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
import { getEditorContainerDOMSize } from 'tiptap/prose-utils';
|
import { getEditorContainerDOMSize } from 'tiptap/prose-utils';
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ export const IframeWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor}>
|
<DragableWrapper editor={editor} extensionName={Iframe.name}>
|
||||||
<Resizeable width={width} maxWidth={maxWidth} height={height} isEditable={isEditable} onChangeEnd={onResize}>
|
<Resizeable width={width} maxWidth={maxWidth} height={height} isEditable={isEditable} onChangeEnd={onResize}>
|
||||||
<div className={cls(styles.wrap, 'render-wrapper')}>
|
<div className={cls(styles.wrap, 'render-wrapper')}>
|
||||||
{url ? (
|
{url ? (
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useToggle } from 'hooks/use-toggle';
|
||||||
import { useCallback, useEffect, useRef } from 'react';
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
import { LazyLoadImage } from 'react-lazy-load-image-component';
|
import { LazyLoadImage } from 'react-lazy-load-image-component';
|
||||||
import { uploadFile } from 'services/file';
|
import { uploadFile } from 'services/file';
|
||||||
|
import { Image } from 'tiptap/core/extensions/image';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
import {
|
import {
|
||||||
extractFileExtension,
|
extractFileExtension,
|
||||||
|
@ -69,7 +70,7 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
}, [src, hasTrigger, selectFile, updateAttributes]);
|
}, [src, hasTrigger, selectFile, updateAttributes]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor} style={{ textAlign, fontSize: 0, maxWidth: '100%' }}>
|
<DragableWrapper editor={editor} extensionName={Image.name} style={{ textAlign, fontSize: 0, maxWidth: '100%' }}>
|
||||||
<Resizeable
|
<Resizeable
|
||||||
className={'render-wrapper'}
|
className={'render-wrapper'}
|
||||||
width={width || maxWidth}
|
width={width || maxWidth}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { convertColorToRGBA } from 'helpers/color';
|
||||||
import { Theme, ThemeEnum } from 'hooks/use-theme';
|
import { Theme, ThemeEnum } from 'hooks/use-theme';
|
||||||
import katex from 'katex';
|
import katex from 'katex';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import { Katex } from 'tiptap/core/extensions/katex';
|
||||||
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
import { DragableWrapper } from 'tiptap/core/wrappers/dragable';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -36,6 +37,7 @@ export const KatexWrapper = ({ node, editor }) => {
|
||||||
return (
|
return (
|
||||||
<DragableWrapper
|
<DragableWrapper
|
||||||
editor={editor}
|
editor={editor}
|
||||||
|
extensionName={Katex.name}
|
||||||
className={'render-wrapper'}
|
className={'render-wrapper'}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
|
|
|
@ -108,7 +108,11 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
}, [width, height, setCenter]);
|
}, [width, height, setCenter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragableWrapper editor={editor} className={cls(styles.wrap, isActive && styles.isActive)}>
|
<DragableWrapper
|
||||||
|
editor={editor}
|
||||||
|
extensionName={Mind.name}
|
||||||
|
className={cls(styles.wrap, isActive && styles.isActive)}
|
||||||
|
>
|
||||||
<VisibilitySensor onChange={onViewportChange}>
|
<VisibilitySensor onChange={onViewportChange}>
|
||||||
<Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}>
|
<Resizeable isEditable={isEditable} width={width} height={height} maxWidth={maxWidth} onChangeEnd={onResize}>
|
||||||
<div
|
<div
|
||||||
|
|
Loading…
Reference in New Issue