This commit is contained in:
fantasticit 2022-03-28 21:54:31 +08:00
parent 2dbdf3f3ee
commit eb5aaad020
223 changed files with 225 additions and 1164 deletions

View File

@ -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

View File

@ -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",

View File

@ -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);

View File

@ -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';

View File

@ -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}>

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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';

View File

@ -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"

View File

@ -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"

View File

@ -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';

View File

@ -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';

View File

@ -1,2 +0,0 @@
export * from './collaboration';
export * from './helpers/isChangeOrigin';

View File

@ -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);
},
};
},
});

View File

@ -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;
};

View File

@ -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();

View File

@ -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;
} }

View File

@ -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';

View File

@ -0,0 +1,2 @@
export * from './collaboration';
export * from './helpers/is-change-origin';

View File

@ -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' {

View File

@ -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() {

View File

@ -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 {
/** /**

View File

@ -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' {

View File

@ -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' {

View File

@ -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> {

View File

@ -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');

View File

@ -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' }];

View File

@ -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';

View File

@ -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() {

View File

@ -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 */

View File

@ -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() {

View File

@ -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';

View File

@ -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';

View File

@ -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 = (() => {

View File

@ -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 (

View File

@ -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,

View File

@ -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';

View File

@ -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 }) => {

View File

@ -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');

View File

@ -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];

View File

@ -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';

View File

@ -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 }) => {

View File

@ -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) {

View File

@ -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) {

View File

@ -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