refactor: add eslint

This commit is contained in:
fantasticit 2022-05-02 00:15:13 +08:00
parent 881b1c6846
commit 8a1da277f5
33 changed files with 116 additions and 145 deletions

View File

@ -2,5 +2,5 @@ node_modules
**/.next/** **/.next/**
**/_next/** **/_next/**
**/dist/** **/dist/**
./packages/client/src/tiptap/next.config.js .eslintrc.js
./packages/client/src/tiptap/wrappers/mind/mind-elixir/iconfont/iconfont.js ./packages/client/src/tiptap/wrappers/mind/mind-elixir/iconfont/iconfont.js

View File

@ -1,17 +1,15 @@
module.exports = { module.exports = {
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 8,
sourceType: 'module',
ecmaFeatures: {
impliedStrict: true,
experimentalObjectRestSpread: true,
},
allowImportExportEverywhere: true,
project: ['./packages/client/tsconfig.json'],
},
plugins: ['@typescript-eslint', 'react-hooks'], plugins: ['@typescript-eslint', 'react-hooks'],
extends: ['eslint:recommended', 'plugin:react/recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], extends: ['eslint:recommended', 'plugin:react/recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
overrides: [
{
files: ['*.ts', '*.tsx', '.js', '.jsx'],
parserOptions: {
project: ['./packages/client/tsconfig.json'],
},
},
],
settings: { settings: {
react: { react: {
version: 'detect', version: 'detect',

View File

@ -4,7 +4,7 @@
"author": "fantasticit", "author": "fantasticit",
"scripts": { "scripts": {
"clean": "npx rimraf ./node_modules ./packages/**/node_modules", "clean": "npx rimraf ./node_modules ./packages/**/node_modules",
"dev": "concurrently \"pnpm:dev:*\"", "dev": "concurrently 'pnpm:dev:*'",
"dev:server": "pnpm run --dir packages/server dev", "dev:server": "pnpm run --dir packages/server dev",
"dev:client": "pnpm run --dir packages/client dev", "dev:client": "pnpm run --dir packages/client dev",
"build": "pnpm build:server && pnpm build:client", "build": "pnpm build:server && pnpm build:client",
@ -14,17 +14,18 @@
"build:config": "pnpm run --dir packages/config build", "build:config": "pnpm run --dir packages/config build",
"build:server": "pnpm run --dir packages/server build", "build:server": "pnpm run --dir packages/server build",
"build:client": "pnpm run --dir packages/client build", "build:client": "pnpm run --dir packages/client build",
"start": "concurrently \"pnpm:start:*\"", "start": "concurrently 'pnpm:start:*'",
"start:server": "pnpm run --dir packages/server start", "start:server": "pnpm run --dir packages/server start",
"start:client": "pnpm run --dir packages/client start", "start:client": "pnpm run --dir packages/client start",
"pm2": "pnpm run pm2:server && pnpm run pm2:client", "pm2": "pnpm run pm2:server && pnpm run pm2:client",
"pm2:server": "pnpm run --dir packages/server pm2", "pm2:server": "pnpm run --dir packages/server pm2",
"pm2:client": "pnpm run --dir packages/client pm2", "pm2:client": "pnpm run --dir packages/client pm2",
"lint": "concurrently 'pnpm:lint:*'",
"lint:client": "eslint --fix './packages/client/**/*.{ts,tsx,js,jsx}' -c '.eslintrc.client.js'", "lint:client": "eslint --fix './packages/client/**/*.{ts,tsx,js,jsx}' -c '.eslintrc.client.js'",
"lint:server": "eslint --fix './packages/server/src/*.{ts,js}' -c '.eslintrc.server.js'", "lint:server": "eslint --fix './packages/server/src/*.{ts,js}' -c '.eslintrc.server.js'",
"format": "concurrently \"pnpm:format:*\"", "format": "concurrently 'pnpm:format:*'",
"format:ts": "prettier --write --parser typescript \"packages/**/*.{ts,tsx,js,jsx}\"", "format:ts": "prettier --write --parser typescript 'packages/**/*.{ts,tsx,js,jsx}'",
"format:css": "stylelint --fix --formatter verbose --allow-empty-input \"packages/**/*.{css,scss,sass}\"", "format:css": "stylelint --fix --formatter verbose --allow-empty-input 'packages/**/*.{css,scss,sass}'",
"prepare": "husky install", "prepare": "husky install",
"precommit": "lint-staged" "precommit": "lint-staged"
}, },
@ -62,6 +63,12 @@
}, },
"lint-staged": { "lint-staged": {
"*.{ts,tsx,js,jsx}": "prettier --write", "*.{ts,tsx,js,jsx}": "prettier --write",
"./packages/client/**/*.{ts,tsx,js,jsx}": [
"eslint --fix -c '.eslintrc.client.js'"
],
"./packages/server/src/*.{ts,js}": [
"eslint --fix -c '.eslintrc.server.js'"
],
"*.{css,scss,sass}": " stylelint --fix --formatter verbose --allow-empty-input" "*.{css,scss,sass}": " stylelint --fix --formatter verbose --allow-empty-input"
} }
} }

View File

@ -1,14 +1,16 @@
/* eslint-disable */ /* eslint-env es6 */
const semi = require('@douyinfe/semi-next').default({});
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const { getConfig } = require('@think/config'); const { getConfig } = require('@think/config');
const config = getConfig(); const config = getConfig();
const nextConfig = require('@douyinfe/semi-next').default({})({ /** @type {import('next').NextConfig} */
const nextConfig = semi({
assetPrefix: config.assetPrefix, assetPrefix: config.assetPrefix,
env: { env: {
SERVER_API_URL: config?.client?.apiUrl, SERVER_API_URL: config.client.apiUrl,
COLLABORATION_API_URL: config?.client?.collaborationUrl, COLLABORATION_API_URL: config.client.collaborationUrl,
ENABLE_ALIYUN_OSS: !!config?.oss?.aliyun?.accessKeyId, ENABLE_ALIYUN_OSS: !!config.oss.aliyun.accessKeyId,
}, },
webpack: (config, { dev, isServer }) => { webpack: (config, { dev, isServer }) => {
config.resolve.plugins.push(new TsconfigPathsPlugin()); config.resolve.plugins.push(new TsconfigPathsPlugin());

View File

@ -37,7 +37,6 @@ interface IProps {
} }
export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, authority, className, style }) => { export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, authority, className, style }) => {
if (!currentUser) return null;
const $hasShowUserSettingModal = useRef(false); const $hasShowUserSettingModal = useRef(false);
const { users, addUser, updateUser } = useCollaborationDocument(documentId); const { users, addUser, updateUser } = useCollaborationDocument(documentId);
const [status, setStatus] = useState<ProviderStatus>('connecting'); const [status, setStatus] = useState<ProviderStatus>('connecting');
@ -64,7 +63,7 @@ export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, author
}, },
}, },
}); });
}, [documentId, currentUser.token]); }, [documentId, currentUser, toggleLoading]);
const editor = useEditor({ const editor = useEditor({
editable: authority && authority.editable, editable: authority && authority.editable,
extensions: [ extensions: [
@ -77,7 +76,9 @@ export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, author
try { try {
const title = transaction.doc.content.firstChild.content.firstChild.textContent; const title = transaction.doc.content.firstChild.content.firstChild.textContent;
triggerChangeDocumentTitle(title); triggerChangeDocumentTitle(title);
} catch (e) {} } catch (e) {
//
}
}, 50), }, 50),
}); });
const [mentionUsersSettingVisible, toggleMentionUsersSettingVisible] = useToggle(false); const [mentionUsersSettingVisible, toggleMentionUsersSettingVisible] = useToggle(false);
@ -98,7 +99,7 @@ export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, author
destoryProvider(provider, 'EDITOR'); destoryProvider(provider, 'EDITOR');
destoryIndexdbProvider(documentId); destoryIndexdbProvider(documentId);
}; };
}, []); }, [documentId, provider]);
useEffect(() => { useEffect(() => {
if (!editor) return; if (!editor) return;
@ -157,7 +158,7 @@ export const Editor: React.FC<IProps> = ({ user: currentUser, documentId, author
Router.events.off('routeChangeStart', handler); Router.events.off('routeChangeStart', handler);
window.removeEventListener('unload', handler); window.removeEventListener('unload', handler);
}; };
}, [editor, users, currentUser]); }, [editor, users, currentUser, toggleMentionUsersSettingVisible]);
useEffect(() => { useEffect(() => {
const listener = (event: KeyboardEvent) => { const listener = (event: KeyboardEvent) => {

View File

@ -27,7 +27,6 @@ interface IProps {
} }
export const DocumentEditor: React.FC<IProps> = ({ documentId }) => { export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
if (!documentId) return null;
const { width: windowWith } = useWindowSize(); const { width: windowWith } = useWindowSize();
const { width, fontSize } = useDocumentStyle(); const { width, fontSize } = useDocumentStyle();
const editorWrapClassNames = useMemo(() => { const editorWrapClassNames = useMemo(() => {
@ -42,7 +41,7 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
Router.push({ Router.push({
pathname: `/wiki/${document.wikiId}/document/${documentId}`, pathname: `/wiki/${document.wikiId}/document/${documentId}`,
}); });
}, [document]); }, [document, documentId]);
const DocumentTitle = ( const DocumentTitle = (
<> <>

View File

@ -49,7 +49,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, document, children
}, },
}, },
}); });
}, [documentId, user.token]); }, [documentId, user, toggleLoading]);
const editor = useEditor({ const editor = useEditor({
editable: false, editable: false,
extensions: [ extensions: [
@ -68,7 +68,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, document, children
return () => { return () => {
destoryProvider(provider, 'READER'); destoryProvider(provider, 'READER');
}; };
}, []); }, [provider]);
return ( return (
<DataRender <DataRender

View File

@ -64,7 +64,7 @@ export const DocumentPublicReader: React.FC<IProps> = ({ documentId, hideLogo =
hasCancel: false, hasCancel: false,
maskClosable: false, maskClosable: false,
onOk() { onOk() {
const $input = document.querySelector('#js-share-document-password') as HTMLInputElement; const $input = document.querySelector('#js-share-document-password');
query($input.value); query($input.value);
}, },
}); });

View File

@ -12,7 +12,7 @@ export const ImageViewer: React.FC<IProps> = ({ container, containerSelector })
if (!el) { if (!el) {
return null; return null;
} }
const viewer = new Viewer(el as HTMLElement, { inline: false }); const viewer = new Viewer(el, { inline: false });
const io = new MutationObserver(() => { const io = new MutationObserver(() => {
viewer.update(); viewer.update();
}); });

View File

@ -117,25 +117,32 @@ const MessageBox = () => {
Notification.info({ Notification.info({
title: '消息通知', title: '消息通知',
content: ( content: (
<Link href={msg.url}> <>
<a className={styles.item}> <div>
<div className={styles.leftWrap}> <Text
<Text ellipsis={{
ellipsis={{ showTooltip: {
showTooltip: { opts: { content: msg.message },
opts: { content: msg.message }, },
}, }}
}} style={{ width: 240 }}
style={{ width: 240 }} >
> {msg.title}
{msg.title} </Text>
</Text> </div>
</div> <div>
</a> <Text link>
</Link> <Link href={msg.url}>
<a className={styles.item} target="_blank">
</a>
</Link>
</Text>
</div>
</>
), ),
duration: 3, duration: 3,
showClose: true,
onHookClose() { onHookClose() {
readMessage(msg.id); readMessage(msg.id);
}, },

View File

@ -43,11 +43,7 @@ import { Iframe } from './menus/iframe';
import { Table } from './menus/table'; import { Table } from './menus/table';
import { Mind } from './menus/mind'; import { Mind } from './menus/mind';
export const MenuBar: React.FC<{ editor: any }> = ({ editor }) => { const _MenuBar: React.FC<{ editor: any }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<div> <div>
<Space spacing={2}> <Space spacing={2}>
@ -87,8 +83,8 @@ export const MenuBar: React.FC<{ editor: any }> = ({ editor }) => {
<Divider /> <Divider />
<Emoji editor={editor} /> <Emoji editor={editor} />
<Link editor={editor} />
<Blockquote editor={editor} /> <Blockquote editor={editor} />
<Link editor={editor} />
<HorizontalRule editor={editor} /> <HorizontalRule editor={editor} />
<Search editor={editor} /> <Search editor={editor} />
@ -107,11 +103,11 @@ export const MenuBar: React.FC<{ editor: any }> = ({ editor }) => {
); );
}; };
export const CommentMenuBar: React.FC<{ editor: any }> = ({ editor }) => { export const MenuBar = React.memo(_MenuBar, (prevProps, nextProps) => {
if (!editor) { return prevProps.editor === nextProps.editor;
return null; });
}
const _CommentMenuBar: React.FC<{ editor: any }> = ({ editor }) => {
return ( return (
<> <>
<Space spacing={2}> <Space spacing={2}>
@ -135,3 +131,7 @@ export const CommentMenuBar: React.FC<{ editor: any }> = ({ editor }) => {
</> </>
); );
}; };
export const CommentMenuBar = React.memo(_CommentMenuBar, (prevProps, nextProps) => {
return prevProps.editor === nextProps.editor;
});

View File

@ -9,10 +9,6 @@ import { ColorPicker } from '../_components/color-picker';
export const BackgroundColor: React.FC<{ editor: Editor }> = ({ editor }) => { export const BackgroundColor: React.FC<{ editor: Editor }> = ({ editor }) => {
const { backgroundColor } = editor.getAttributes('textStyle'); const { backgroundColor } = editor.getAttributes('textStyle');
if (!editor) {
return null;
}
return ( return (
<ColorPicker <ColorPicker
onSetColor={(color) => { onSetColor={(color) => {

View File

@ -6,10 +6,6 @@ import { Tooltip } from 'components/tooltip';
import { isTitleActive } from 'tiptap/prose-utils'; import { isTitleActive } from 'tiptap/prose-utils';
export const Bold: React.FC<{ editor: Editor }> = ({ editor }) => { export const Bold: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="粗体"> <Tooltip content="粗体">
<Button <Button

View File

@ -5,10 +5,6 @@ import { IconClear } from 'components/icons';
import { Tooltip } from 'components/tooltip'; import { Tooltip } from 'components/tooltip';
export const CleadrNodeAndMarks: React.FC<{ editor: Editor }> = ({ editor }) => { export const CleadrNodeAndMarks: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="清除格式"> <Tooltip content="清除格式">
<Button <Button

View File

@ -6,10 +6,6 @@ import { Tooltip } from 'components/tooltip';
import { isTitleActive } from 'tiptap/prose-utils'; import { isTitleActive } from 'tiptap/prose-utils';
export const Code: React.FC<{ editor: Editor }> = ({ editor }) => { export const Code: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="行内代码"> <Tooltip content="行内代码">
<Button <Button

View File

@ -163,10 +163,6 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[])); setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[]));
}, [visible, transformToCommands]); }, [visible, transformToCommands]);
if (!editor) {
return null;
}
return ( return (
<Dropdown <Dropdown
zIndex={10000} zIndex={10000}
@ -181,13 +177,13 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
}} }}
render={ render={
<Dropdown.Menu> <Dropdown.Menu>
{renderedCommands.map((command) => { {renderedCommands.map((command, index) => {
return command.title ? ( return command.title ? (
<Dropdown.Title>{command.title}</Dropdown.Title> <Dropdown.Title key={'title' + index}>{command.title}</Dropdown.Title>
) : command.custom ? ( ) : command.custom ? (
command.custom(editor, runCommand) command.custom(editor, runCommand)
) : ( ) : (
<Dropdown.Item onClick={runCommand(command)}> <Dropdown.Item key={command.label} onClick={runCommand(command)}>
{command.icon} {command.icon}
{command.label} {command.label}
</Dropdown.Item> </Dropdown.Item>

View File

@ -6,10 +6,6 @@ import { Tooltip } from 'components/tooltip';
import { isTitleActive } from 'tiptap/prose-utils'; import { isTitleActive } from 'tiptap/prose-utils';
export const Italic: React.FC<{ editor: Editor }> = ({ editor }) => { export const Italic: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="斜体"> <Tooltip content="斜体">
<Button <Button

View File

@ -1,4 +1,3 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { useEffect, useState, useRef, useCallback } from 'react'; import { useEffect, useState, useRef, useCallback } from 'react';
import { Space, Button } from '@douyinfe/semi-ui'; import { Space, Button } from '@douyinfe/semi-ui';
import { IconExternalOpen, IconUnlink, IconEdit } from '@douyinfe/semi-icons'; import { IconExternalOpen, IconUnlink, IconEdit } from '@douyinfe/semi-icons';
@ -12,7 +11,6 @@ import { triggerOpenLinkSettingModal } from '../_event';
export const LinkBubbleMenu = ({ editor }) => { export const LinkBubbleMenu = ({ editor }) => {
const attrs = editor.getAttributes(Link.name); const attrs = editor.getAttributes(Link.name);
const { href, target } = attrs; const { href, target } = attrs;
const isLinkActive = editor.isActive(Link.name);
const [text, setText] = useState(); const [text, setText] = useState();
const [from, setFrom] = useState(-1); const [from, setFrom] = useState(-1);
const [to, setTo] = useState(-1); const [to, setTo] = useState(-1);
@ -28,30 +26,40 @@ export const LinkBubbleMenu = ({ editor }) => {
const unsetLink = useCallback(() => editor.chain().extendMarkRange(Link.name).unsetLink().run(), [editor]); const unsetLink = useCallback(() => editor.chain().extendMarkRange(Link.name).unsetLink().run(), [editor]);
useEffect(() => { useEffect(() => {
if (!isLinkActive) return; const listener = () => {
const isLinkActive = editor.isActive(Link.name);
const { state } = editor; if (!isLinkActive) return;
const isInLink = isMarkActive(state.schema.marks.link)(state);
if (!isInLink) return; const { state } = editor;
const isInLink = isMarkActive(state.schema.marks.link)(state);
const { $head } = editor.state.selection; if (!isInLink) return;
const marks = $head.marks();
if (!marks.length) return;
const mark = marks[0]; const { $head } = editor.state.selection;
const node = $head.node($head.depth); const marks = $head.marks();
const startPosOfThisLine = $head.pos - (($head.nodeBefore && $head.nodeBefore.nodeSize) || 0); if (!marks.length) return;
const endPosOfThisLine = $head.nodeAfter
? startPosOfThisLine + $head.nodeAfter.nodeSize
: $head.pos - $head.parentOffset + node.content.size;
const { start, end } = findMarkPosition(state, mark, startPosOfThisLine, endPosOfThisLine); const mark = marks[0];
const text = state.doc.textBetween(start, end); const node = $head.node($head.depth);
setText(text); const startPosOfThisLine = $head.pos - (($head.nodeBefore && $head.nodeBefore.nodeSize) || 0);
setFrom(start); const endPosOfThisLine = $head.nodeAfter
setTo(end); ? startPosOfThisLine + $head.nodeAfter.nodeSize
}); : $head.pos - $head.parentOffset + node.content.size;
const { start, end } = findMarkPosition(state, mark, startPosOfThisLine, endPosOfThisLine);
const text = state.doc.textBetween(start, end);
setText(text);
setFrom(start);
setTo(end);
};
editor.on('selectionUpdate', listener);
return () => {
editor.off('selectionUpdate', listener);
};
}, [editor]);
return ( return (
<BubbleMenu <BubbleMenu

View File

@ -9,10 +9,6 @@ import { LinkBubbleMenu } from './bubble';
import { LinkSettingModal } from './modal'; import { LinkSettingModal } from './modal';
export const Link: React.FC<{ editor: Editor }> = ({ editor }) => { export const Link: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<> <>
<Tooltip content="插入链接"> <Tooltip content="插入链接">

View File

@ -21,6 +21,9 @@ export const LinkSettingModal: React.FC<IProps> = ({ editor }) => {
const { from, to } = initialState; const { from, to } = initialState;
const { view } = editor; const { view } = editor;
console.log(from, to);
const schema = view.state.schema; const schema = view.state.schema;
const node = schema.text(values.text, [schema.marks.link.create({ href: values.href })]); const node = schema.text(values.text, [schema.marks.link.create({ href: values.href })]);
view.dispatch(view.state.tr.replaceRangeWith(from, to, node)); view.dispatch(view.state.tr.replaceRangeWith(from, to, node));

View File

@ -5,10 +5,6 @@ import { IconRedo } from '@douyinfe/semi-icons';
import { Tooltip } from 'components/tooltip'; import { Tooltip } from 'components/tooltip';
export const Redo: React.FC<{ editor: Editor }> = ({ editor }) => { export const Redo: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="撤销"> <Tooltip content="撤销">
<Button <Button

View File

@ -6,10 +6,6 @@ import { Tooltip } from 'components/tooltip';
import { isTitleActive } from 'tiptap/prose-utils'; import { isTitleActive } from 'tiptap/prose-utils';
export const Strike: React.FC<{ editor: Editor }> = ({ editor }) => { export const Strike: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="删除线"> <Tooltip content="删除线">
<Button <Button

View File

@ -5,10 +5,6 @@ import { Tooltip } from 'components/tooltip';
import { isTitleActive } from 'tiptap/prose-utils'; import { isTitleActive } from 'tiptap/prose-utils';
export const Subscript: React.FC<{ editor: any }> = ({ editor }) => { export const Subscript: React.FC<{ editor: any }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="下标"> <Tooltip content="下标">
<Button <Button

View File

@ -5,10 +5,6 @@ import { Tooltip } from 'components/tooltip';
import { isTitleActive } from 'tiptap/prose-utils'; import { isTitleActive } from 'tiptap/prose-utils';
export const Superscript: React.FC<{ editor: any }> = ({ editor }) => { export const Superscript: React.FC<{ editor: any }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="上标"> <Tooltip content="上标">
<Button <Button

View File

@ -9,10 +9,6 @@ import { ColorPicker } from '../_components/color-picker';
export const TextColor: React.FC<{ editor: Editor }> = ({ editor }) => { export const TextColor: React.FC<{ editor: Editor }> = ({ editor }) => {
const { color } = editor.getAttributes('textStyle'); const { color } = editor.getAttributes('textStyle');
if (!editor) {
return null;
}
return ( return (
<ColorPicker <ColorPicker
onSetColor={(color) => { onSetColor={(color) => {

View File

@ -6,10 +6,6 @@ import { Tooltip } from 'components/tooltip';
import { isTitleActive } from 'tiptap/prose-utils'; import { isTitleActive } from 'tiptap/prose-utils';
export const Underline: React.FC<{ editor: Editor }> = ({ editor }) => { export const Underline: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="下划线"> <Tooltip content="下划线">
<Button <Button

View File

@ -5,10 +5,6 @@ import { IconUndo } from '@douyinfe/semi-icons';
import { Tooltip } from 'components/tooltip'; import { Tooltip } from 'components/tooltip';
export const Undo: React.FC<{ editor: Editor }> = ({ editor }) => { export const Undo: React.FC<{ editor: Editor }> = ({ editor }) => {
if (!editor) {
return null;
}
return ( return (
<Tooltip content="撤销"> <Tooltip content="撤销">
<Button <Button

View File

@ -19,6 +19,7 @@ export const extractMarkAttributesFromMatch = ([, , , attrsString]) => {
export function findMarkPosition(state: EditorState, mark, from, to) { export function findMarkPosition(state: EditorState, mark, from, to) {
let markPos = { start: -1, end: -1 }; let markPos = { start: -1, end: -1 };
state.doc.nodesBetween(from, to, (node, pos) => { state.doc.nodesBetween(from, to, (node, pos) => {
if (markPos.start > -1) { if (markPos.start > -1) {
return false; return false;

View File

@ -6,6 +6,7 @@
table { table {
width: 100%; width: 100%;
max-width: 100%;
margin: 0.75em 0 0; margin: 0.75em 0 0;
overflow: hidden; overflow: hidden;
border-collapse: collapse; border-collapse: collapse;

View File

@ -40,8 +40,8 @@ export const BubbleMenu: React.FC<BubbleMenuProps> = (props) => {
editor.registerPlugin(plugin); editor.registerPlugin(plugin);
return () => editor.unregisterPlugin(pluginKey); return () => editor.unregisterPlugin(pluginKey);
// TODO: 检验是否应该是 props.editor // eslint-disable-next-line react-hooks/exhaustive-deps
}, [props, element]); }, [props.editor, element]);
return ( return (
<div ref={setElement} className={props.className} style={{ visibility: 'hidden' }}> <div ref={setElement} className={props.className} style={{ visibility: 'hidden' }}>

View File

@ -196,7 +196,7 @@ function MindElixir(
mobileMenu, mobileMenu,
}: Options }: Options
) { ) {
const box = document.querySelector(el) as HTMLElement; const box = document.querySelector(el);
if (!box) return; if (!box) return;
this.mindElixirBox = box; this.mindElixirBox = box;
this.before = before || {}; this.before = before || {};

View File

@ -103,7 +103,7 @@ export function createInputDiv(tpc: Topic) {
console.time('createInputDiv'); console.time('createInputDiv');
if (!tpc) return; if (!tpc) return;
let div = $d.createElement('div'); let div = $d.createElement('div');
const origin = tpc.childNodes[0].textContent as string; const origin = tpc.childNodes[0].textContent;
tpc.appendChild(div); tpc.appendChild(div);
div.id = 'input-box'; div.id = 'input-box';
div.innerText = origin; div.innerText = origin;
@ -138,7 +138,7 @@ export function createInputDiv(tpc: Topic) {
if (!div) return; // 防止重复blur if (!div) return; // 防止重复blur
const node = tpc.nodeObj; const node = tpc.nodeObj;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const topic = div.textContent!.trim(); const topic = div.textContent.trim();
if (topic === '') node.topic = origin; if (topic === '') node.topic = origin;
else node.topic = topic; else node.topic = topic;
div.remove(); div.remove();

View File

@ -31,5 +31,5 @@
} }
}, },
"include": ["next-env.d.ts", "global.d.ts", "**/*.ts", "**/*.tsx"], "include": ["next-env.d.ts", "global.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"] "exclude": ["node_modules", "next.config.js"]
} }