mirror of https://github.com/fantasticit/think.git
refactor
This commit is contained in:
parent
2dbdf3f3ee
commit
eb5aaad020
|
@ -7,5 +7,5 @@ git pull
|
||||||
pnpm install
|
pnpm install
|
||||||
pnpm run build
|
pnpm run build
|
||||||
|
|
||||||
pm2 restart @think/server
|
pm2 reload @think/server
|
||||||
pm2 restart @think/client
|
pm2 reload @think/client
|
||||||
|
|
11
package.json
11
package.json
|
@ -34,17 +34,6 @@
|
||||||
"node": ">=16.5.0"
|
"node": ">=16.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
||||||
"@typescript-eslint/parser": "^5.0.0",
|
|
||||||
"eslint": "^8.11.0",
|
|
||||||
"eslint-config-next": "12.0.10",
|
|
||||||
"eslint-config-prettier": "^8.3.0",
|
|
||||||
"eslint-import-resolver-typescript": "^2.5.0",
|
|
||||||
"eslint-plugin-import": "^2.25.4",
|
|
||||||
"eslint-plugin-jest": "^26.1.1",
|
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
|
||||||
"eslint-plugin-react": "^7.29.3",
|
|
||||||
"eslint-plugin-react-hooks": "^4.3.0",
|
|
||||||
"prettier": "^2.3.2",
|
"prettier": "^2.3.2",
|
||||||
"stylelint": "^14.6.1",
|
"stylelint": "^14.6.1",
|
||||||
"stylelint-config-css-modules": "^4.1.0",
|
"stylelint-config-css-modules": "^4.1.0",
|
||||||
|
|
|
@ -7,7 +7,7 @@ interface IProps extends BannerProps {
|
||||||
duration?: number;
|
duration?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Banner: React.FC<IProps> = ({ type, description, duration }) => {
|
export const Banner: React.FC<IProps> = ({ type, description, duration = 0 }) => {
|
||||||
const timer = useRef<ReturnType<typeof setTimeout>>();
|
const timer = useRef<ReturnType<typeof setTimeout>>();
|
||||||
const [visible, toggleVisible] = useToggle(true);
|
const [visible, toggleVisible] = useToggle(true);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useRef, useState } from 'react';
|
||||||
import { useEditor, EditorContent } from '@tiptap/react';
|
import { useEditor, EditorContent } from '@tiptap/react';
|
||||||
import { Avatar, Button, Space, Typography, Banner, Pagination } from '@douyinfe/semi-ui';
|
import { Avatar, Button, Space, Typography, Banner, Pagination } from '@douyinfe/semi-ui';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import { DEFAULT_EXTENSION, Document, History, CommentMenuBar } from 'components/tiptap';
|
import { DEFAULT_EXTENSION, Document, History, CommentMenuBar } from 'tiptap';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { useUser } from 'data/user';
|
import { useUser } from 'data/user';
|
||||||
import { useComments } from 'data/comment';
|
import { useComments } from 'data/comment';
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useEditor, EditorContent } from '@tiptap/react';
|
||||||
import { BackTop } from '@douyinfe/semi-ui';
|
import { BackTop } from '@douyinfe/semi-ui';
|
||||||
import { ILoginUser, IAuthority } from '@think/domains';
|
import { ILoginUser, IAuthority } from '@think/domains';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
|
import { useNetwork } from 'hooks/use-network';
|
||||||
import {
|
import {
|
||||||
MenuBar,
|
MenuBar,
|
||||||
DEFAULT_EXTENSION,
|
DEFAULT_EXTENSION,
|
||||||
|
@ -15,7 +16,7 @@ import {
|
||||||
ProviderStatus,
|
ProviderStatus,
|
||||||
getIndexdbProvider,
|
getIndexdbProvider,
|
||||||
destoryIndexdbProvider,
|
destoryIndexdbProvider,
|
||||||
} from 'components/tiptap';
|
} from 'tiptap';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { joinUser } from 'components/document/collaboration';
|
import { joinUser } from 'components/document/collaboration';
|
||||||
import { Banner } from 'components/banner';
|
import { Banner } from 'components/banner';
|
||||||
|
@ -34,6 +35,7 @@ interface IProps {
|
||||||
export const Editor: React.FC<IProps> = ({ user, documentId, authority, className, style }) => {
|
export const Editor: React.FC<IProps> = ({ user, documentId, authority, className, style }) => {
|
||||||
if (!user) return null;
|
if (!user) return null;
|
||||||
const [status, setStatus] = useState<ProviderStatus>('connecting');
|
const [status, setStatus] = useState<ProviderStatus>('connecting');
|
||||||
|
const { online } = useNetwork();
|
||||||
const provider = useMemo(() => {
|
const provider = useMemo(() => {
|
||||||
return getProvider({
|
return getProvider({
|
||||||
targetId: documentId,
|
targetId: documentId,
|
||||||
|
@ -94,11 +96,10 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
|
||||||
normalContent={() => {
|
normalContent={() => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.editorWrap}>
|
<div className={styles.editorWrap}>
|
||||||
{status === 'disconnected' && (
|
{(!online || status === 'disconnected') && (
|
||||||
<Banner
|
<Banner
|
||||||
type="warning"
|
type="warning"
|
||||||
description="我们已与您断开连接,您可以继续编辑文档。一旦重新连接,我们会自动重新提交数据。
|
description="我们已与您断开连接,您可以继续编辑文档。一旦重新连接,我们会自动重新提交数据。"
|
||||||
"
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<header className={className}>
|
<header className={className}>
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
getCollaborationCursorExtension,
|
getCollaborationCursorExtension,
|
||||||
getProvider,
|
getProvider,
|
||||||
destoryProvider,
|
destoryProvider,
|
||||||
} from 'components/tiptap';
|
} from 'tiptap';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { ImageViewer } from 'components/image-viewer';
|
import { ImageViewer } from 'components/image-viewer';
|
||||||
import { joinUser } from 'components/document/collaboration';
|
import { joinUser } from 'components/document/collaboration';
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { useDocumentStyle } from 'hooks/use-document-style';
|
||||||
import { useWindowSize } from 'hooks/use-window-size';
|
import { useWindowSize } from 'hooks/use-window-size';
|
||||||
import { useUser } from 'data/user';
|
import { useUser } from 'data/user';
|
||||||
import { useDocumentDetail } from 'data/document';
|
import { useDocumentDetail } from 'data/document';
|
||||||
import { DocumentSkeleton } from 'components/tiptap';
|
import { DocumentSkeleton } from 'tiptap';
|
||||||
import { Editor } from './editor';
|
import { Editor } from './editor';
|
||||||
import { CreateUser } from './user';
|
import { CreateUser } from './user';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useEditor, EditorContent } from '@tiptap/react';
|
import { useEditor, EditorContent } from '@tiptap/react';
|
||||||
import { IDocument } from '@think/domains';
|
import { IDocument } from '@think/domains';
|
||||||
import { DEFAULT_EXTENSION, DocumentWithTitle } from 'components/tiptap';
|
import { DEFAULT_EXTENSION, DocumentWithTitle } from 'tiptap';
|
||||||
import { safeJSONParse } from 'helpers/json';
|
import { safeJSONParse } from 'helpers/json';
|
||||||
import { CreateUser } from '../user';
|
import { CreateUser } from '../user';
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { ImageViewer } from 'components/image-viewer';
|
||||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||||
import { useWindowSize } from 'hooks/use-window-size';
|
import { useWindowSize } from 'hooks/use-window-size';
|
||||||
import { usePublicDocument } from 'data/document';
|
import { usePublicDocument } from 'data/document';
|
||||||
import { DocumentSkeleton } from 'components/tiptap';
|
import { DocumentSkeleton } from 'tiptap';
|
||||||
import { DocumentContent } from './content';
|
import { DocumentContent } from './content';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ export const IconSub: React.FC<{ style?: React.CSSProperties }> = ({ style = {}
|
||||||
svg={
|
svg={
|
||||||
<svg width="16" height="16" viewBox="0 0 256 256" role="presentation">
|
<svg width="16" height="16" viewBox="0 0 256 256" role="presentation">
|
||||||
<g stroke="currentColor" fill="none" fillRule="evenodd">
|
<g stroke="currentColor" fill="none" fillRule="evenodd">
|
||||||
<path stroke-width="20" stroke-linecap="round" d="m40 50 114 168M154 50 40 218"></path>
|
<path strokeWidth="20" strokeLinecap="round" d="m40 50 114 168M154 50 40 218"></path>
|
||||||
<path
|
<path
|
||||||
d="M231.92 225.48c2.72 0 4.08-1.48 4.08-4.44 0-2.88-1.36-4.32-4.08-4.32H198.8c6.48-5.52 12.28-11.24 17.4-17.16 2.16-2.48 4.28-5.16 6.36-8.04 2.08-2.88 3.94-5.82 5.58-8.82 1.64-3 2.96-6.04 3.96-9.12 1-3.08 1.5-6.14 1.5-9.18 0-3.36-.48-6.42-1.44-9.18s-2.38-5.12-4.26-7.08-4.2-3.48-6.96-4.56c-2.76-1.08-5.9-1.62-9.42-1.62-7.92 0-13.8 2.26-17.64 6.78-3.84 4.52-5.76 10.66-5.76 18.42 0 2.24.32 3.74.96 4.5.64.76 1.96 1.14 3.96 1.14 1.76 0 2.98-.44 3.66-1.32.68-.88 1.02-2.32 1.02-4.32 0-4.8 1.04-8.74 3.12-11.82s5.4-4.62 9.96-4.62c4 0 7.16 1.32 9.48 3.96 2.32 2.64 3.48 6.12 3.48 10.44 0 3.2-.64 6.42-1.92 9.66-1.28 3.24-2.94 6.4-4.98 9.48a84.099 84.099 0 0 1-6.84 8.94c-2.52 2.88-5.04 5.6-7.56 8.16-2.52 2.56-4.92 4.94-7.2 7.14-2.28 2.2-4.18 4.1-5.7 5.7-.64 1.04-.96 2.04-.96 3-.56 1.04-.86 2.06-.9 3.06-.04 1 .1 1.88.42 2.64.32.76.8 1.38 1.44 1.86.64.48 1.36.72 2.16.72h40.2Z"
|
d="M231.92 225.48c2.72 0 4.08-1.48 4.08-4.44 0-2.88-1.36-4.32-4.08-4.32H198.8c6.48-5.52 12.28-11.24 17.4-17.16 2.16-2.48 4.28-5.16 6.36-8.04 2.08-2.88 3.94-5.82 5.58-8.82 1.64-3 2.96-6.04 3.96-9.12 1-3.08 1.5-6.14 1.5-9.18 0-3.36-.48-6.42-1.44-9.18s-2.38-5.12-4.26-7.08-4.2-3.48-6.96-4.56c-2.76-1.08-5.9-1.62-9.42-1.62-7.92 0-13.8 2.26-17.64 6.78-3.84 4.52-5.76 10.66-5.76 18.42 0 2.24.32 3.74.96 4.5.64.76 1.96 1.14 3.96 1.14 1.76 0 2.98-.44 3.66-1.32.68-.88 1.02-2.32 1.02-4.32 0-4.8 1.04-8.74 3.12-11.82s5.4-4.62 9.96-4.62c4 0 7.16 1.32 9.48 3.96 2.32 2.64 3.48 6.12 3.48 10.44 0 3.2-.64 6.42-1.92 9.66-1.28 3.24-2.94 6.4-4.98 9.48a84.099 84.099 0 0 1-6.84 8.94c-2.52 2.88-5.04 5.6-7.56 8.16-2.52 2.56-4.92 4.94-7.2 7.14-2.28 2.2-4.18 4.1-5.7 5.7-.64 1.04-.96 2.04-.96 3-.56 1.04-.86 2.06-.9 3.06-.04 1 .1 1.88.42 2.64.32.76.8 1.38 1.44 1.86.64.48 1.36.72 2.16.72h40.2Z"
|
||||||
strokeWidth="5"
|
strokeWidth="5"
|
||||||
|
|
|
@ -7,7 +7,7 @@ export const IconSup: React.FC<{ style?: React.CSSProperties }> = ({ style = {}
|
||||||
svg={
|
svg={
|
||||||
<svg width="16" height="16" viewBox="0 0 256 256" role="presentation">
|
<svg width="16" height="16" viewBox="0 0 256 256" role="presentation">
|
||||||
<g stroke="currentColor" fill="none" fillRule="evenodd">
|
<g stroke="currentColor" fill="none" fillRule="evenodd">
|
||||||
<path stroke-width="20" stroke-linecap="round" d="m40 50 114 168M154 50 40 218"></path>
|
<path strokeWidth="20" strokeLinecap="round" d="m40 50 114 168M154 50 40 218"></path>
|
||||||
<path
|
<path
|
||||||
d="M231.92 103.48c2.72 0 4.08-1.48 4.08-4.44 0-2.88-1.36-4.32-4.08-4.32H198.8c6.48-5.52 12.28-11.24 17.4-17.16 2.16-2.48 4.28-5.16 6.36-8.04 2.08-2.88 3.94-5.82 5.58-8.82 1.64-3 2.96-6.04 3.96-9.12 1-3.08 1.5-6.14 1.5-9.18 0-3.36-.48-6.42-1.44-9.18s-2.38-5.12-4.26-7.08-4.2-3.48-6.96-4.56c-2.76-1.08-5.9-1.62-9.42-1.62-7.92 0-13.8 2.26-17.64 6.78-3.84 4.52-5.76 10.66-5.76 18.42 0 2.24.32 3.74.96 4.5.64.76 1.96 1.14 3.96 1.14 1.76 0 2.98-.44 3.66-1.32.68-.88 1.02-2.32 1.02-4.32 0-4.8 1.04-8.74 3.12-11.82s5.4-4.62 9.96-4.62c4 0 7.16 1.32 9.48 3.96 2.32 2.64 3.48 6.12 3.48 10.44 0 3.2-.64 6.42-1.92 9.66-1.28 3.24-2.94 6.4-4.98 9.48a84.099 84.099 0 0 1-6.84 8.94c-2.52 2.88-5.04 5.6-7.56 8.16-2.52 2.56-4.92 4.94-7.2 7.14-2.28 2.2-4.18 4.1-5.7 5.7-.64 1.04-.96 2.04-.96 3-.56 1.04-.86 2.06-.9 3.06-.04 1 .1 1.88.42 2.64.32.76.8 1.38 1.44 1.86.64.48 1.36.72 2.16.72h40.2Z"
|
d="M231.92 103.48c2.72 0 4.08-1.48 4.08-4.44 0-2.88-1.36-4.32-4.08-4.32H198.8c6.48-5.52 12.28-11.24 17.4-17.16 2.16-2.48 4.28-5.16 6.36-8.04 2.08-2.88 3.94-5.82 5.58-8.82 1.64-3 2.96-6.04 3.96-9.12 1-3.08 1.5-6.14 1.5-9.18 0-3.36-.48-6.42-1.44-9.18s-2.38-5.12-4.26-7.08-4.2-3.48-6.96-4.56c-2.76-1.08-5.9-1.62-9.42-1.62-7.92 0-13.8 2.26-17.64 6.78-3.84 4.52-5.76 10.66-5.76 18.42 0 2.24.32 3.74.96 4.5.64.76 1.96 1.14 3.96 1.14 1.76 0 2.98-.44 3.66-1.32.68-.88 1.02-2.32 1.02-4.32 0-4.8 1.04-8.74 3.12-11.82s5.4-4.62 9.96-4.62c4 0 7.16 1.32 9.48 3.96 2.32 2.64 3.48 6.12 3.48 10.44 0 3.2-.64 6.42-1.92 9.66-1.28 3.24-2.94 6.4-4.98 9.48a84.099 84.099 0 0 1-6.84 8.94c-2.52 2.88-5.04 5.6-7.56 8.16-2.52 2.56-4.92 4.94-7.2 7.14-2.28 2.2-4.18 4.1-5.7 5.7-.64 1.04-.96 2.04-.96 3-.56 1.04-.86 2.06-.9 3.06-.04 1 .1 1.88.42 2.64.32.76.8 1.38 1.44 1.86.64.48 1.36.72 2.16.72h40.2Z"
|
||||||
strokeWidth="5"
|
strokeWidth="5"
|
||||||
|
|
|
@ -18,13 +18,7 @@ import {
|
||||||
import { IconChevronLeft, IconArticle } from '@douyinfe/semi-icons';
|
import { IconChevronLeft, IconArticle } from '@douyinfe/semi-icons';
|
||||||
import { ILoginUser, ITemplate } from '@think/domains';
|
import { ILoginUser, ITemplate } from '@think/domains';
|
||||||
import { Theme } from 'components/theme';
|
import { Theme } from 'components/theme';
|
||||||
import {
|
import { DEFAULT_EXTENSION, DocumentWithTitle, getCollaborationExtension, getProvider, MenuBar } from 'tiptap';
|
||||||
DEFAULT_EXTENSION,
|
|
||||||
DocumentWithTitle,
|
|
||||||
getCollaborationExtension,
|
|
||||||
getProvider,
|
|
||||||
MenuBar,
|
|
||||||
} from 'components/tiptap';
|
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { User } from 'components/user';
|
import { User } from 'components/user';
|
||||||
import { DocumentStyle } from 'components/document/style';
|
import { DocumentStyle } from 'components/document/style';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import cls from 'classnames';
|
||||||
import { useEditor, EditorContent } from '@tiptap/react';
|
import { useEditor, EditorContent } from '@tiptap/react';
|
||||||
import { Layout, Spin, Typography } from '@douyinfe/semi-ui';
|
import { Layout, Spin, Typography } from '@douyinfe/semi-ui';
|
||||||
import { IUser, ITemplate } from '@think/domains';
|
import { IUser, ITemplate } from '@think/domains';
|
||||||
import { DEFAULT_EXTENSION, DocumentWithTitle } from 'components/tiptap';
|
import { DEFAULT_EXTENSION, DocumentWithTitle } from 'tiptap';
|
||||||
import { DataRender } from 'components/data-render';
|
import { DataRender } from 'components/data-render';
|
||||||
import { ImageViewer } from 'components/image-viewer';
|
import { ImageViewer } from 'components/image-viewer';
|
||||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
export * from './collaboration';
|
|
||||||
export * from './helpers/isChangeOrigin';
|
|
|
@ -1,187 +0,0 @@
|
||||||
import * as Y from 'yjs';
|
|
||||||
import { Decoration, DecorationSet } from 'prosemirror-view'; // eslint-disable-line
|
|
||||||
import { Plugin } from 'prosemirror-state'; // eslint-disable-line
|
|
||||||
import * as math from 'lib0/math';
|
|
||||||
import {
|
|
||||||
absolutePositionToRelativePosition,
|
|
||||||
relativePositionToAbsolutePosition,
|
|
||||||
setMeta,
|
|
||||||
yCursorPluginKey,
|
|
||||||
ySyncPluginKey,
|
|
||||||
} from 'y-prosemirror';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default generator for a cursor element
|
|
||||||
*
|
|
||||||
* @param {any} user user data
|
|
||||||
* @return HTMLElement
|
|
||||||
*/
|
|
||||||
export const defaultCursorBuilder = (user) => {
|
|
||||||
const cursor = document.createElement('span');
|
|
||||||
cursor.classList.add('ProseMirror-yjs-cursor');
|
|
||||||
cursor.setAttribute('style', `border-color: ${user.color}`);
|
|
||||||
const userDiv = document.createElement('div');
|
|
||||||
userDiv.setAttribute('style', `background-color: ${user.color}`);
|
|
||||||
userDiv.insertBefore(document.createTextNode(user.name), null);
|
|
||||||
cursor.insertBefore(userDiv, null);
|
|
||||||
return cursor;
|
|
||||||
};
|
|
||||||
|
|
||||||
const rxValidColor = /^#[0-9a-fA-F]{6}$/;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {any} state
|
|
||||||
* @param {Awareness} awareness
|
|
||||||
* @return {any} DecorationSet
|
|
||||||
*/
|
|
||||||
export const createDecorations = (state, awareness, createCursor) => {
|
|
||||||
const ystate = ySyncPluginKey.getState(state) || state['y-sync$'];
|
|
||||||
const y = ystate.doc;
|
|
||||||
const decorations = [];
|
|
||||||
if (ystate.snapshot != null || ystate.prevSnapshot != null || ystate.binding === null) {
|
|
||||||
// do not render cursors while snapshot is active
|
|
||||||
return DecorationSet.create(state.doc, []);
|
|
||||||
}
|
|
||||||
awareness.getStates().forEach((aw, clientId) => {
|
|
||||||
if (clientId === y.clientID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (aw.cursor != null) {
|
|
||||||
const user = aw.user || {};
|
|
||||||
if (user.color == null) {
|
|
||||||
user.color = '#ffa500';
|
|
||||||
} else if (!rxValidColor.test(user.color)) {
|
|
||||||
// We only support 6-digit RGB colors in y-prosemirror
|
|
||||||
console.warn('A user uses an unsupported color format', user);
|
|
||||||
}
|
|
||||||
if (user.name == null) {
|
|
||||||
user.name = `User: ${clientId}`;
|
|
||||||
}
|
|
||||||
let anchor = relativePositionToAbsolutePosition(
|
|
||||||
y,
|
|
||||||
ystate.type,
|
|
||||||
Y.createRelativePositionFromJSON(aw.cursor.anchor),
|
|
||||||
ystate.binding.mapping
|
|
||||||
);
|
|
||||||
let head = relativePositionToAbsolutePosition(
|
|
||||||
y,
|
|
||||||
ystate.type,
|
|
||||||
Y.createRelativePositionFromJSON(aw.cursor.head),
|
|
||||||
ystate.binding.mapping
|
|
||||||
);
|
|
||||||
if (anchor !== null && head !== null) {
|
|
||||||
const maxsize = math.max(state.doc.content.size - 1, 0);
|
|
||||||
anchor = math.min(anchor, maxsize);
|
|
||||||
head = math.min(head, maxsize);
|
|
||||||
decorations.push(Decoration.widget(head, () => createCursor(user), { key: clientId + '', side: 10 }));
|
|
||||||
const from = math.min(anchor, head);
|
|
||||||
const to = math.max(anchor, head);
|
|
||||||
decorations.push(
|
|
||||||
Decoration.inline(
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
{ style: `background-color: ${user.color}70` },
|
|
||||||
{ inclusiveEnd: true, inclusiveStart: false }
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return DecorationSet.create(state.doc, decorations);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A prosemirror plugin that listens to awareness information on Yjs.
|
|
||||||
* This requires that a `prosemirrorPlugin` is also bound to the prosemirror.
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
* @param {Awareness} awareness
|
|
||||||
* @param {object} [opts]
|
|
||||||
* @param {function(any):HTMLElement} [opts.cursorBuilder]
|
|
||||||
* @param {function(any):any} [opts.getSelection]
|
|
||||||
* @param {string} [opts.cursorStateField] By default all editor bindings use the awareness 'cursor' field to propagate cursor information.
|
|
||||||
* @return {any}
|
|
||||||
*/
|
|
||||||
export const yCursorPlugin = (
|
|
||||||
awareness,
|
|
||||||
{ cursorBuilder = defaultCursorBuilder, getSelection = (state) => state.selection } = {},
|
|
||||||
cursorStateField = 'cursor'
|
|
||||||
) =>
|
|
||||||
new Plugin({
|
|
||||||
key: yCursorPluginKey,
|
|
||||||
state: {
|
|
||||||
init(_, state) {
|
|
||||||
return createDecorations(state, awareness, cursorBuilder);
|
|
||||||
},
|
|
||||||
apply(tr, prevState, oldState, newState) {
|
|
||||||
const ystate = ySyncPluginKey.getState(newState);
|
|
||||||
const yCursorState = tr.getMeta(yCursorPluginKey);
|
|
||||||
if ((ystate && ystate.isChangeOrigin) || (yCursorState && yCursorState.awarenessUpdated)) {
|
|
||||||
return createDecorations(newState, awareness, cursorBuilder);
|
|
||||||
}
|
|
||||||
return prevState.map(tr.mapping, tr.doc);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
decorations: (state) => {
|
|
||||||
return yCursorPluginKey.getState(state);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
view: (view) => {
|
|
||||||
const awarenessListener = () => {
|
|
||||||
// @ts-ignore
|
|
||||||
if (view.docView) {
|
|
||||||
setMeta(view, yCursorPluginKey, { awarenessUpdated: true });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const updateCursorInfo = () => {
|
|
||||||
const ystate = ySyncPluginKey.getState(view.state) || view.state['y-sync$'];
|
|
||||||
// @note We make implicit checks when checking for the cursor property
|
|
||||||
const current = awareness.getLocalState() || {};
|
|
||||||
if (view.hasFocus() && ystate.binding !== null) {
|
|
||||||
const selection = getSelection(view.state);
|
|
||||||
/**
|
|
||||||
* @type {Y.RelativePosition}
|
|
||||||
*/
|
|
||||||
const anchor = absolutePositionToRelativePosition(selection.anchor, ystate.type, ystate.binding.mapping);
|
|
||||||
/**
|
|
||||||
* @type {Y.RelativePosition}
|
|
||||||
*/
|
|
||||||
const head = absolutePositionToRelativePosition(selection.head, ystate.type, ystate.binding.mapping);
|
|
||||||
if (
|
|
||||||
current.cursor == null ||
|
|
||||||
!Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.anchor), anchor) ||
|
|
||||||
!Y.compareRelativePositions(Y.createRelativePositionFromJSON(current.cursor.head), head)
|
|
||||||
) {
|
|
||||||
awareness.setLocalStateField(cursorStateField, {
|
|
||||||
anchor,
|
|
||||||
head,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
current.cursor != null &&
|
|
||||||
relativePositionToAbsolutePosition(
|
|
||||||
ystate.doc,
|
|
||||||
ystate.type,
|
|
||||||
Y.createRelativePositionFromJSON(current.cursor.anchor),
|
|
||||||
ystate.binding.mapping
|
|
||||||
) !== null
|
|
||||||
) {
|
|
||||||
// delete cursor information if current cursor information is owned by this editor binding
|
|
||||||
awareness.setLocalStateField(cursorStateField, null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
awareness.on('change', awarenessListener);
|
|
||||||
view.dom.addEventListener('focusin', updateCursorInfo);
|
|
||||||
view.dom.addEventListener('focusout', updateCursorInfo);
|
|
||||||
return {
|
|
||||||
update: updateCursorInfo,
|
|
||||||
destroy: () => {
|
|
||||||
view.dom.removeEventListener('focusin', updateCursorInfo);
|
|
||||||
view.dom.removeEventListener('focusout', updateCursorInfo);
|
|
||||||
awareness.off('change', awarenessListener);
|
|
||||||
awareness.setLocalStateField(cursorStateField, null);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
interface INetworkStatus {
|
||||||
|
online: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useNetwork = () => {
|
||||||
|
const [networkState, setNetworkState] = useState<INetworkStatus>({ online: navigator.onLine });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleOnline = () => {
|
||||||
|
setNetworkState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
online: true,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOffline = () => {
|
||||||
|
setNetworkState((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
online: false,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('online', handleOnline);
|
||||||
|
window.addEventListener('offline', handleOffline);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('online', handleOnline);
|
||||||
|
window.removeEventListener('offline', handleOffline);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return networkState;
|
||||||
|
};
|
|
@ -2,6 +2,7 @@ import type { AppProps } from 'next/app';
|
||||||
import { useSafari100vh } from 'hooks/use-safari-100vh';
|
import { useSafari100vh } from 'hooks/use-safari-100vh';
|
||||||
import 'viewerjs/dist/viewer.css';
|
import 'viewerjs/dist/viewer.css';
|
||||||
import 'styles/globals.scss';
|
import 'styles/globals.scss';
|
||||||
|
import 'tiptap/styles/index.scss';
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
useSafari100vh();
|
useSafari100vh();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
@import '~@douyinfe/semi-ui/dist/css/semi.min.css';
|
@import '~@douyinfe/semi-ui/dist/css/semi.min.css';
|
||||||
@import './var.scss';
|
@import './var.scss';
|
||||||
@import './reset.scss';
|
@import './reset.scss';
|
||||||
@import './editor/index.scss';
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
@ -29,7 +28,7 @@
|
||||||
.Resizer {
|
.Resizer {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background: var(--semi-color-border);
|
background: var(--semi-color-border);
|
||||||
opacity: .2;
|
opacity: 0.2;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background-clip: padding;
|
background-clip: padding;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import { Attachment } from './extensions/attachment';
|
import { Attachment } from './extensions/attachment';
|
||||||
import { BackgroundColor } from './extensions/backgroundColor';
|
import { BackgroundColor } from './extensions/background-color';
|
||||||
import { Banner } from './extensions/banner';
|
import { Banner } from './extensions/banner';
|
||||||
import { Blockquote } from './extensions/blockquote';
|
import { Blockquote } from './extensions/blockquote';
|
||||||
import { Bold } from './extensions/bold';
|
import { Bold } from './extensions/bold';
|
||||||
import { BulletList } from './extensions/bulletList';
|
import { BulletList } from './extensions/bullet-list';
|
||||||
import { Code } from './extensions/code';
|
import { Code } from './extensions/code';
|
||||||
import { CodeBlock } from './extensions/codeBlock';
|
import { CodeBlock } from './extensions/code-block';
|
||||||
import { Color } from './extensions/color';
|
import { Color } from './extensions/color';
|
||||||
import { ColorHighlighter } from './extensions/colorHighlighter';
|
import { ColorHighlighter } from './extensions/color-highlighter';
|
||||||
import { DocumentChildren } from './extensions/documentChildren';
|
import { DocumentChildren } from './extensions/document-children';
|
||||||
import { DocumentReference } from './extensions/documentReference';
|
import { DocumentReference } from './extensions/document-reference';
|
||||||
import { Dropcursor } from './extensions/dropCursor';
|
import { Dropcursor } from './extensions/dropcursor';
|
||||||
import { Emoji } from './extensions/emoji';
|
import { Emoji } from './extensions/emoji';
|
||||||
import { EvokeMenu } from './extensions/evokeMenu';
|
import { EvokeMenu } from './extensions/evoke-menu';
|
||||||
import { Focus } from './extensions/focus';
|
import { Focus } from './extensions/focus';
|
||||||
import { FontSize } from './extensions/fontSize';
|
import { FontSize } from './extensions/font-size';
|
||||||
import { Gapcursor } from './extensions/gapCursor';
|
import { Gapcursor } from './extensions/gapcursor';
|
||||||
import { HardBreak } from './extensions/hardBreak';
|
import { HardBreak } from './extensions/hard-break';
|
||||||
import { Heading } from './extensions/heading';
|
import { Heading } from './extensions/heading';
|
||||||
import { HorizontalRule } from './extensions/horizontalRule';
|
import { HorizontalRule } from './extensions/horizontal-rule';
|
||||||
import { HTMLMarks } from './extensions/htmlMarks';
|
import { HTMLMarks } from './extensions/html-marks';
|
||||||
import { Iframe } from './extensions/iframe';
|
import { Iframe } from './extensions/iframe';
|
||||||
import { Image } from './extensions/image';
|
import { Image } from './extensions/image';
|
||||||
import { Indent } from './extensions/indent';
|
import { Indent } from './extensions/indent';
|
||||||
|
@ -29,7 +29,7 @@ import { Link } from './extensions/link';
|
||||||
import { ListItem } from './extensions/listItem';
|
import { ListItem } from './extensions/listItem';
|
||||||
import { Loading } from './extensions/loading';
|
import { Loading } from './extensions/loading';
|
||||||
import { Mind } from './extensions/mind';
|
import { Mind } from './extensions/mind';
|
||||||
import { OrderedList } from './extensions/orderedList';
|
import { OrderedList } from './extensions/ordered-list';
|
||||||
import { Paragraph } from './extensions/paragraph';
|
import { Paragraph } from './extensions/paragraph';
|
||||||
import { Placeholder } from './extensions/placeholder';
|
import { Placeholder } from './extensions/placeholder';
|
||||||
import { SearchNReplace } from './extensions/search';
|
import { SearchNReplace } from './extensions/search';
|
||||||
|
@ -39,16 +39,16 @@ import { Strike } from './extensions/strike';
|
||||||
import { Subscript } from './extensions/subscript';
|
import { Subscript } from './extensions/subscript';
|
||||||
import { Superscript } from './extensions/superscript';
|
import { Superscript } from './extensions/superscript';
|
||||||
import { Table } from './extensions/table';
|
import { Table } from './extensions/table';
|
||||||
import { TableCell } from './extensions/tableCell';
|
import { TableCell } from './extensions/table-cell';
|
||||||
import { TableHeader } from './extensions/tableHeader';
|
import { TableHeader } from './extensions/table-header';
|
||||||
import { TableRow } from './extensions/tableRow';
|
import { TableRow } from './extensions/table-row';
|
||||||
import { Text } from './extensions/text';
|
import { Text } from './extensions/text';
|
||||||
import { TextAlign } from './extensions/textAlign';
|
import { TextAlign } from './extensions/text-align';
|
||||||
import { TextStyle } from './extensions/textStyle';
|
import { TextStyle } from './extensions/text-style';
|
||||||
import { TaskItem } from './extensions/taskItem';
|
import { TaskItem } from './extensions/task-item';
|
||||||
import { TaskList } from './extensions/taskList';
|
import { TaskList } from './extensions/task-list';
|
||||||
import { Title } from './extensions/title';
|
import { Title } from './extensions/title';
|
||||||
import { TrailingNode } from './extensions/trailingNode';
|
import { TrailingNode } from './extensions/trailing-node';
|
||||||
import { Underline } from './extensions/underline';
|
import { Underline } from './extensions/underline';
|
||||||
import { Paste } from './extensions/paste';
|
import { Paste } from './extensions/paste';
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './collaboration';
|
||||||
|
export * from './helpers/is-change-origin';
|
|
@ -1,7 +1,7 @@
|
||||||
import { Node, Command, mergeAttributes, wrappingInputRule } from '@tiptap/core';
|
import { Node, Command, mergeAttributes, wrappingInputRule } from '@tiptap/core';
|
||||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||||
import { BannerWrapper } from '../wrappers/banner';
|
import { BannerWrapper } from '../wrappers/banner';
|
||||||
import { typesAvailable } from '../services/markdown/markdownToHTML/markdownBanner';
|
import { typesAvailable } from '../services/markdown/markdown-to-html/markdownBanner';
|
||||||
import { getDatasetAttribute } from '../services/dataset';
|
import { getDatasetAttribute } from '../services/dataset';
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
|
@ -1,6 +1,5 @@
|
||||||
import { BulletList as BuiltInBulletList } from '@tiptap/extension-bullet-list';
|
import { BulletList as BuiltInBulletList } from '@tiptap/extension-bullet-list';
|
||||||
import { getMarkdownSource } from '../services/markdown';
|
import { getMarkdownSource } from '../services/markdown';
|
||||||
import { listInputRule } from '../services/listInputRule';
|
|
||||||
|
|
||||||
export const BulletList = BuiltInBulletList.extend({
|
export const BulletList = BuiltInBulletList.extend({
|
||||||
addAttributes() {
|
addAttributes() {
|
|
@ -2,8 +2,8 @@ import { lowlight } from 'lowlight/lib/all';
|
||||||
import { Node, textblockTypeInputRule, mergeAttributes } from '@tiptap/core';
|
import { Node, textblockTypeInputRule, mergeAttributes } from '@tiptap/core';
|
||||||
import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
|
import { Plugin, PluginKey, TextSelection } from 'prosemirror-state';
|
||||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||||
import { LowlightPlugin } from '../services/lowlightPlugin';
|
import { LowlightPlugin } from '../services/lowlight-plugin';
|
||||||
import { CodeBlockWrapper } from '../wrappers/codeBlock';
|
import { CodeBlockWrapper } from '../wrappers/code-block';
|
||||||
|
|
||||||
export interface CodeBlockOptions {
|
export interface CodeBlockOptions {
|
||||||
/**
|
/**
|
|
@ -1,6 +1,6 @@
|
||||||
import { Node, mergeAttributes, wrappingInputRule } from '@tiptap/core';
|
import { Node, mergeAttributes, wrappingInputRule } from '@tiptap/core';
|
||||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||||
import { DocumentChildrenWrapper } from '../wrappers/documentChildren';
|
import { DocumentChildrenWrapper } from '../wrappers/document-children';
|
||||||
import { getDatasetAttribute } from '../services/dataset';
|
import { getDatasetAttribute } from '../services/dataset';
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
|
@ -1,6 +1,6 @@
|
||||||
import { Node, mergeAttributes, wrappingInputRule } from '@tiptap/core';
|
import { Node, mergeAttributes, wrappingInputRule } from '@tiptap/core';
|
||||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||||
import { DocumentReferenceWrapper } from '../wrappers/documentReference';
|
import { DocumentReferenceWrapper } from '../wrappers/document-reference';
|
||||||
import { getDatasetAttribute } from '../services/dataset';
|
import { getDatasetAttribute } from '../services/dataset';
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
|
@ -4,8 +4,8 @@ import { Plugin, PluginKey } from 'prosemirror-state';
|
||||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||||
import Suggestion from '@tiptap/suggestion';
|
import Suggestion from '@tiptap/suggestion';
|
||||||
import tippy from 'tippy.js';
|
import tippy from 'tippy.js';
|
||||||
import { EmojiList } from '../wrappers/emojiList';
|
import { EmojiList } from '../wrappers/emoji-list';
|
||||||
import { emojiSearch, emojisToName } from '../wrappers/emojiList/emojis';
|
import { emojiSearch, emojisToName } from '../wrappers/emoji-list/emojis';
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
||||||
interface Commands<ReturnType> {
|
interface Commands<ReturnType> {
|
|
@ -4,8 +4,8 @@ import { Plugin, PluginKey } from 'prosemirror-state';
|
||||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||||
import Suggestion from '@tiptap/suggestion';
|
import Suggestion from '@tiptap/suggestion';
|
||||||
import tippy from 'tippy.js';
|
import tippy from 'tippy.js';
|
||||||
import { MenuList } from '../wrappers/menuList';
|
import { MenuList } from '../wrappers/menu-list';
|
||||||
import { EVOKE_MENU_ITEMS } from '../menus/evokeMenu';
|
import { EVOKE_MENU_ITEMS } from '../menus/evoke-menu';
|
||||||
|
|
||||||
export const EvokeMenuPluginKey = new PluginKey('evokeMenu');
|
export const EvokeMenuPluginKey = new PluginKey('evokeMenu');
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Mark, mergeAttributes, markInputRule } from '@tiptap/core';
|
import { Mark, mergeAttributes, markInputRule } from '@tiptap/core';
|
||||||
import { PARSE_HTML_PRIORITY_LOWEST } from '../constants';
|
import { PARSE_HTML_PRIORITY_LOWEST } from '../constants';
|
||||||
import { markInputRegex, extractMarkAttributesFromMatch } from '../services/markUtils';
|
import { markInputRegex, extractMarkAttributesFromMatch } from '../services/mark-utils';
|
||||||
|
|
||||||
export const marks = [{ name: 'underline', tag: 'u' }];
|
export const marks = [{ name: 'underline', tag: 'u' }];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Command, Extension } from '@tiptap/core';
|
import { Command, Extension } from '@tiptap/core';
|
||||||
import { sinkListItem, liftListItem } from 'prosemirror-schema-list';
|
import { sinkListItem, liftListItem } from 'prosemirror-schema-list';
|
||||||
import { TextSelection, AllSelection, Transaction } from 'prosemirror-state';
|
import { TextSelection, AllSelection, Transaction } from 'prosemirror-state';
|
||||||
import { isListActive } from '../services/isActive';
|
import { isListActive } from '../services/is-active';
|
||||||
import { clamp } from '../services/clamp';
|
import { clamp } from '../services/clamp';
|
||||||
import { getNodeType } from '../services/type';
|
import { getNodeType } from '../services/type';
|
||||||
import { isListNode } from '../services/node';
|
import { isListNode } from '../services/node';
|
|
@ -14,7 +14,7 @@ import {
|
||||||
selectRow,
|
selectRow,
|
||||||
selectTable,
|
selectTable,
|
||||||
} from '../services/table';
|
} from '../services/table';
|
||||||
import { FloatMenuView } from '../views/floatMenuView';
|
import { FloatMenuView } from '../views/float-menu';
|
||||||
|
|
||||||
export const TableCell = BuiltInTableCell.extend({
|
export const TableCell = BuiltInTableCell.extend({
|
||||||
addAttributes() {
|
addAttributes() {
|
|
@ -6,7 +6,7 @@ import { Tooltip } from 'components/tooltip';
|
||||||
import { Plugin, PluginKey } from 'prosemirror-state';
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
||||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||||
import { getCellsInRow, isColumnSelected, isTableSelected, selectColumn } from '../services/table';
|
import { getCellsInRow, isColumnSelected, isTableSelected, selectColumn } from '../services/table';
|
||||||
import { FloatMenuView } from '../views/floatMenuView';
|
import { FloatMenuView } from '../views/float-menu';
|
||||||
|
|
||||||
// @flow
|
// @flow
|
||||||
/* eslint-disable no-unused-vars */
|
/* eslint-disable no-unused-vars */
|
|
@ -4,7 +4,7 @@ import { TaskItem as BuiltInTaskItem } from '@tiptap/extension-task-item';
|
||||||
import { Plugin } from 'prosemirror-state';
|
import { Plugin } from 'prosemirror-state';
|
||||||
import { findParentNodeClosestToPos } from 'prosemirror-utils';
|
import { findParentNodeClosestToPos } from 'prosemirror-utils';
|
||||||
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
|
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
|
||||||
import { TaskItemWrapper } from '../wrappers/taskItem';
|
import { TaskItemWrapper } from '../wrappers/task-item';
|
||||||
|
|
||||||
const CustomTaskItem = BuiltInTaskItem.extend({
|
const CustomTaskItem = BuiltInTaskItem.extend({
|
||||||
parseHTML() {
|
parseHTML() {
|
|
@ -1,6 +1,6 @@
|
||||||
import { HocuspocusProvider } from '@hocuspocus/provider';
|
import { HocuspocusProvider } from '@hocuspocus/provider';
|
||||||
import { Collaboration } from './collaboration';
|
import { Collaboration } from './collaboration';
|
||||||
import { CollaborationCursor } from './collaborationCursor';
|
import { CollaborationCursor } from './collaboration-cursor';
|
||||||
import History from '@tiptap/extension-history';
|
import History from '@tiptap/extension-history';
|
||||||
import { getRandomColor } from 'helpers/color';
|
import { getRandomColor } from 'helpers/color';
|
||||||
import { Document } from './extensions/document';
|
import { Document } from './extensions/document';
|
|
@ -3,15 +3,15 @@ import { Space, Button } from '@douyinfe/semi-ui';
|
||||||
import { IconUndo, IconRedo } from '@douyinfe/semi-icons';
|
import { IconUndo, IconRedo } from '@douyinfe/semi-icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { IconClear } from 'components/icons';
|
import { IconClear } from 'components/icons';
|
||||||
import { Divider } from './wrappers/divider';
|
import { Divider } from './divider';
|
||||||
import { MediaInsertMenu } from './menus/mediaInsert';
|
import { MediaInsertMenu } from './menus/media-insert';
|
||||||
import { Paragraph } from './menus/paragraph';
|
import { Paragraph } from './menus/paragraph';
|
||||||
import { FontSize } from './menus/fontSize';
|
import { FontSize } from './menus/font-size';
|
||||||
import { BaseMenu } from './menus/baseMenu';
|
import { BaseMenu } from './menus/base-menu';
|
||||||
import { AlignMenu } from './menus/align';
|
import { AlignMenu } from './menus/align';
|
||||||
import { ListMenu } from './menus/list';
|
import { ListMenu } from './menus/list';
|
||||||
import { BaseInsertMenu } from './menus/baseInsert';
|
import { BaseInsertMenu } from './menus/base-insert';
|
||||||
import { BaseBubbleMenu } from './menus/baseBubbleMenu';
|
import { BaseBubbleMenu } from './menus/base-bubble-menu';
|
||||||
import { ImageBubbleMenu } from './menus/image';
|
import { ImageBubbleMenu } from './menus/image';
|
||||||
import { BannerBubbleMenu } from './menus/banner';
|
import { BannerBubbleMenu } from './menus/banner';
|
||||||
import { LinkBubbleMenu } from './menus/link';
|
import { LinkBubbleMenu } from './menus/link';
|
|
@ -1,7 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button, Dropdown, Tooltip } from '@douyinfe/semi-ui';
|
import { Button, Dropdown, Tooltip } from '@douyinfe/semi-ui';
|
||||||
import { IconAlignLeft, IconAlignCenter, IconAlignRight, IconAlignJustify } from '@douyinfe/semi-icons';
|
import { IconAlignLeft, IconAlignCenter, IconAlignRight, IconAlignJustify } from '@douyinfe/semi-icons';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
|
|
||||||
export const AlignMenu = ({ editor }) => {
|
export const AlignMenu = ({ editor }) => {
|
||||||
const current = (() => {
|
const current = (() => {
|
|
@ -1,10 +1,10 @@
|
||||||
import { Space, Button } from '@douyinfe/semi-ui';
|
import { Space, Button } from '@douyinfe/semi-ui';
|
||||||
import { IconDelete, IconTickCircle, IconAlertTriangle, IconClear, IconInfoCircle } from '@douyinfe/semi-icons';
|
import { IconDelete, IconTickCircle, IconAlertTriangle, IconClear, IconInfoCircle } from '@douyinfe/semi-icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { BubbleMenu } from '../views/bubbleMenu';
|
import { BubbleMenu } from '../views/bubble-menu';
|
||||||
import { Divider } from '../wrappers/divider';
|
import { Divider } from '../divider';
|
||||||
import { Banner } from '../extensions/banner';
|
import { Banner } from '../extensions/banner';
|
||||||
import { deleteNode } from '../services/deleteNode';
|
import { deleteNode } from '../services/delete-node';
|
||||||
|
|
||||||
export const BannerBubbleMenu = ({ editor }) => {
|
export const BannerBubbleMenu = ({ editor }) => {
|
||||||
return (
|
return (
|
|
@ -7,16 +7,16 @@ import { Attachment } from '../extensions/attachment';
|
||||||
import { Image } from '../extensions/image';
|
import { Image } from '../extensions/image';
|
||||||
import { Banner } from '../extensions/banner';
|
import { Banner } from '../extensions/banner';
|
||||||
import { Status } from '../extensions/status';
|
import { Status } from '../extensions/status';
|
||||||
import { HorizontalRule } from '../extensions/horizontalRule';
|
import { HorizontalRule } from '../extensions/horizontal-rule';
|
||||||
import { Iframe } from '../extensions/iframe';
|
import { Iframe } from '../extensions/iframe';
|
||||||
import { Mind } from '../extensions/mind';
|
import { Mind } from '../extensions/mind';
|
||||||
import { Table } from '../extensions/table';
|
import { Table } from '../extensions/table';
|
||||||
import { TaskList } from '../extensions/taskList';
|
import { TaskList } from '../extensions/task-list';
|
||||||
import { TaskItem } from '../extensions/taskItem';
|
import { TaskItem } from '../extensions/task-item';
|
||||||
import { Katex } from '../extensions/katex';
|
import { Katex } from '../extensions/katex';
|
||||||
import { DocumentReference } from '../extensions/documentReference';
|
import { DocumentReference } from '../extensions/document-reference';
|
||||||
import { DocumentChildren } from '../extensions/documentChildren';
|
import { DocumentChildren } from '../extensions/document-children';
|
||||||
import { BaseMenu } from './baseMenu';
|
import { BaseMenu } from './base-menu';
|
||||||
|
|
||||||
const OTHER_BUBBLE_MENU_TYPES = [
|
const OTHER_BUBBLE_MENU_TYPES = [
|
||||||
Title.name,
|
Title.name,
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { Button } from '@douyinfe/semi-ui';
|
import { Button } from '@douyinfe/semi-ui';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { IconQuote, IconLink, IconHorizontalRule } from 'components/icons';
|
import { IconQuote, IconLink, IconHorizontalRule } from 'components/icons';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
import { Emoji } from './emoji';
|
import { Emoji } from './emoji';
|
||||||
import { Search } from './search';
|
import { Search } from './search';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Button } from '@douyinfe/semi-ui';
|
||||||
import { IconBold, IconItalic, IconStrikeThrough, IconUnderline, IconCode } from '@douyinfe/semi-icons';
|
import { IconBold, IconItalic, IconStrikeThrough, IconUnderline, IconCode } from '@douyinfe/semi-icons';
|
||||||
import { IconSup, IconSub } from 'components/icons';
|
import { IconSup, IconSub } from 'components/icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
import { ColorMenu } from './color';
|
import { ColorMenu } from './color';
|
||||||
|
|
||||||
export const BaseMenu: React.FC<{ editor: any }> = ({ editor }) => {
|
export const BaseMenu: React.FC<{ editor: any }> = ({ editor }) => {
|
|
@ -2,8 +2,8 @@ import React from 'react';
|
||||||
import { Button } from '@douyinfe/semi-ui';
|
import { Button } from '@douyinfe/semi-ui';
|
||||||
import { IconFont, IconMark } from '@douyinfe/semi-icons';
|
import { IconFont, IconMark } from '@douyinfe/semi-icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
import { ColorPicker } from './colorPicker';
|
import { ColorPicker } from './color-picker';
|
||||||
|
|
||||||
export const ColorMenu: React.FC<{ editor: any }> = ({ editor }) => {
|
export const ColorMenu: React.FC<{ editor: any }> = ({ editor }) => {
|
||||||
const { color, backgroundColor } = editor.getAttributes('textStyle');
|
const { color, backgroundColor } = editor.getAttributes('textStyle');
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Select } from '@douyinfe/semi-ui';
|
import { Select } from '@douyinfe/semi-ui';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
|
|
||||||
export const FONT_SIZES = [12, 13, 14, 15, 16, 19, 22, 24, 29, 32, 40, 48];
|
export const FONT_SIZES = [12, 13, 14, 15, 16, 19, 22, 24, 29, 32, 40, 48];
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { Space, Button, InputNumber, Typography } from '@douyinfe/semi-ui';
|
||||||
import { IconAlignLeft, IconAlignCenter, IconAlignRight, IconUpload, IconDelete } from '@douyinfe/semi-icons';
|
import { IconAlignLeft, IconAlignCenter, IconAlignRight, IconUpload, IconDelete } from '@douyinfe/semi-icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { Upload } from 'components/upload';
|
import { Upload } from 'components/upload';
|
||||||
import { BubbleMenu } from '../views/bubbleMenu';
|
import { BubbleMenu } from '../views/bubble-menu';
|
||||||
import { Divider } from '../wrappers/divider';
|
import { Divider } from '../divider';
|
||||||
import { Image } from '../extensions/image';
|
import { Image } from '../extensions/image';
|
||||||
import { getImageOriginSize } from '../services/image';
|
import { getImageOriginSize } from '../services/image';
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
|
||||||
import { Space, Button, Input } from '@douyinfe/semi-ui';
|
import { Space, Button, Input } from '@douyinfe/semi-ui';
|
||||||
import { IconExternalOpen, IconUnlink, IconTickCircle } from '@douyinfe/semi-icons';
|
import { IconExternalOpen, IconUnlink, IconTickCircle } from '@douyinfe/semi-icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { BubbleMenu } from '../views/bubbleMenu';
|
import { BubbleMenu } from '../views/bubble-menu';
|
||||||
import { Link } from '../extensions/link';
|
import { Link } from '../extensions/link';
|
||||||
|
|
||||||
export const LinkBubbleMenu = ({ editor }) => {
|
export const LinkBubbleMenu = ({ editor }) => {
|
|
@ -4,7 +4,7 @@ import { IconIndentLeft, IconIndentRight } from '@douyinfe/semi-icons';
|
||||||
import { IconOrderedList, IconList } from 'components/icons';
|
import { IconOrderedList, IconList } from 'components/icons';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { IconTask } from 'components/icons';
|
import { IconTask } from 'components/icons';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
|
|
||||||
export const ListMenu: React.FC<{ editor: any }> = ({ editor }) => {
|
export const ListMenu: React.FC<{ editor: any }> = ({ editor }) => {
|
||||||
if (!editor) {
|
if (!editor) {
|
|
@ -16,7 +16,7 @@ import {
|
||||||
IconMath,
|
IconMath,
|
||||||
} from 'components/icons';
|
} from 'components/icons';
|
||||||
import { GridSelect } from 'components/grid-select';
|
import { GridSelect } from 'components/grid-select';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
|
|
||||||
export const MediaInsertMenu: React.FC<{ editor: Editor }> = ({ editor }) => {
|
export const MediaInsertMenu: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
if (!editor) {
|
if (!editor) {
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Select } from '@douyinfe/semi-ui';
|
import { Select } from '@douyinfe/semi-ui';
|
||||||
import { isTitleActive } from '../services/isActive';
|
import { isTitleActive } from '../services/is-active';
|
||||||
|
|
||||||
const getCurrentCaretTitle = (editor) => {
|
const getCurrentCaretTitle = (editor) => {
|
||||||
if (editor.isActive('heading', { level: 1 })) return 1;
|
if (editor.isActive('heading', { level: 1 })) return 1;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue