refactor: lint code

This commit is contained in:
fantasticit 2022-05-01 23:04:33 +08:00
parent 76cdcff589
commit d0165bad1e
44 changed files with 189 additions and 138 deletions

View File

@ -20,6 +20,7 @@ export const Blockquote = BuiltInBlockquote.extend({
addInputRules() { addInputRules() {
const multilineInputRegex = /^\s*>>>\s$/gm; const multilineInputRegex = /^\s*>>>\s$/gm;
return [ return [
// eslint-disable-next-line no-unsafe-optional-chaining
...this.parent?.(), ...this.parent?.(),
wrappingInputRule({ wrappingInputRule({
find: multilineInputRegex, find: multilineInputRegex,

View File

@ -101,7 +101,9 @@ const lockCollaborationUserEditingNodes = (extensionThis, users) => {
options.collaborationUserCursorCache.set(user.clientId, { user, cursor }); options.collaborationUserCursorCache.set(user.clientId, { user, cursor });
} }
} }
} catch (e) {} } catch (e) {
//
}
}); });
} }
}; };

View File

@ -61,7 +61,7 @@ export const Paste = Extension.create({
if (node) { if (node) {
const doc = safeJSONParse(node); const doc = safeJSONParse(node);
let tr = view.state.tr; const tr = view.state.tr;
const selection = tr.selection; const selection = tr.selection;
view.dispatch(tr.insert(selection.from - 1, view.state.schema.nodeFromJSON(doc)).scrollIntoView()); view.dispatch(tr.insert(selection.from - 1, view.state.schema.nodeFromJSON(doc)).scrollIntoView());
return true; return true;

View File

@ -182,7 +182,7 @@ const gotoSearchResult = ({ view, tr, searchResults, searchResultCurrentClass, g
const result = searchResults[gotoIndex]; const result = searchResults[gotoIndex];
if (result) { if (result) {
let transaction = tr.setMeta('directDecoration', { const transaction = tr.setMeta('directDecoration', {
fromPos: result.from, fromPos: result.from,
toPos: result.to, toPos: result.to,
attrs: { class: searchResultCurrentClass }, attrs: { class: searchResultCurrentClass },

View File

@ -116,7 +116,7 @@ export class Renderer {
} }
renderChildren(node) { renderChildren(node) {
let nodes = []; const nodes = [];
node.childNodes.forEach((child) => { node.childNodes.forEach((child) => {
const NodeClass = this.getMatchingNode(child); const NodeClass = this.getMatchingNode(child);
@ -180,7 +180,7 @@ export class Renderer {
} }
getMatchingClass(node, classes) { getMatchingClass(node, classes) {
for (let i in classes) { for (const i in classes) {
const Class = classes[i]; const Class = classes[i];
const instance = new Class(node); const instance = new Class(node);
if (instance.matching()) { if (instance.matching()) {

View File

@ -18,6 +18,7 @@ export * from './markdown-source-map';
const extractImage = (html) => { const extractImage = (html) => {
let matches = []; let matches = [];
// eslint-disable-next-line no-useless-escape
while ((matches = html.match(/\<p.*?\>\<img(.|\s)*?\>\<\/p\>/g))) { while ((matches = html.match(/\<p.*?\>\<img(.|\s)*?\>\<\/p\>/g))) {
const target = matches[0].match(/<img.*?>/)[0]; const target = matches[0].match(/<img.*?>/)[0];
html = html.replace(matches[0], target); html = html.replace(matches[0], target);

View File

@ -20,7 +20,7 @@ export const createMarkdownContainer = (types: string | Array<string>) => (md) =
if (tag.nesting === 1) { if (tag.nesting === 1) {
tag.attrSet('class', type); tag.attrSet('class', type);
var m = tag.info.trim().match(regexp); const m = tag.info.trim().match(regexp);
if (m[1]) { if (m[1]) {
const data = strToJSON(m[1]); const data = strToJSON(m[1]);
jsonToDOMDataset(data).forEach(({ key, value }) => { jsonToDOMDataset(data).forEach(({ key, value }) => {

View File

@ -1,9 +1,10 @@
/* eslint-disable */
// var katex = require('katex'); // var katex = require('katex');
// Test if potential opening or closing delimieter // Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos] // Assumes that there is a "$" at state.src[pos]
function isValidDelim(state, pos) { function isValidDelim(state, pos) {
var prevChar, let prevChar,
nextChar, nextChar,
max = state.posMax, max = state.posMax,
can_open = true, can_open = true,
@ -32,7 +33,7 @@ function isValidDelim(state, pos) {
} }
function math_inline(state, silent) { function math_inline(state, silent) {
var start, match, token, res, pos, esc_count; let start, match, token, res, pos, esc_count;
if (state.src[state.pos] !== '$') { if (state.src[state.pos] !== '$') {
return false; return false;
@ -107,7 +108,7 @@ function math_inline(state, silent) {
} }
function math_block(state, start, end, silent) { function math_block(state, start, end, silent) {
var firstLine, let firstLine,
lastLine, lastLine,
next, next,
lastPos, lastPos,
@ -179,7 +180,7 @@ function escapeHtml(unsafe) {
.replace(/'/g, '&#039;'); .replace(/'/g, '&#039;');
} }
var katex = { let katex = {
renderToString: (s, opts) => s, renderToString: (s, opts) => s,
}; };
@ -194,7 +195,7 @@ export default function math_plugin(md, options) {
options.blockClass = ''; options.blockClass = '';
} }
var inlineRenderer = function (tokens, idx) { const inlineRenderer = function (tokens, idx) {
return katexBlock(tokens[idx].content); return katexBlock(tokens[idx].content);
}; };
@ -212,7 +213,7 @@ export default function math_plugin(md, options) {
} }
}; };
var blockRenderer = function (tokens, idx) { const blockRenderer = function (tokens, idx) {
return katexBlock(tokens[idx].content) + '\n'; return katexBlock(tokens[idx].content) + '\n';
}; };

View File

@ -1,3 +1,5 @@
/* eslint-disable */
// Copied from https://github.com/markdown-it/markdown-it/blob/master/lib/rules_block/table.js // Copied from https://github.com/markdown-it/markdown-it/blob/master/lib/rules_block/table.js
function isSpace(code) { function isSpace(code) {
@ -10,14 +12,14 @@ function isSpace(code) {
} }
function getLine(state, line) { function getLine(state, line) {
var pos = state.bMarks[line] + state.tShift[line], const pos = state.bMarks[line] + state.tShift[line],
max = state.eMarks[line]; max = state.eMarks[line];
return state.src.substr(pos, max - pos); return state.src.substr(pos, max - pos);
} }
function escapedSplit(str) { function escapedSplit(str) {
var result = [], let result = [],
pos = 0, pos = 0,
max = str.length, max = str.length,
ch, ch,
@ -53,7 +55,7 @@ function escapedSplit(str) {
} }
function table(state, startLine, endLine, silent) { function table(state, startLine, endLine, silent) {
var ch, let ch,
lineText, lineText,
pos, pos,
i, i,

View File

@ -50,8 +50,8 @@ export default function markdownItTaskLists(
} }
function attrSet(token, name, value) { function attrSet(token, name, value) {
var index = token.attrIndex(name); const index = token.attrIndex(name);
var attr = [name, value]; const attr = [name, value];
if (index < 0) { if (index < 0) {
token.attrPush(attr); token.attrPush(attr);

View File

@ -130,6 +130,7 @@ const SerializerConfig = {
[Image.name]: renderImage, [Image.name]: renderImage,
[Katex.name]: (state, node) => { [Katex.name]: (state, node) => {
state.ensureNewLine(); state.ensureNewLine();
// eslint-disable-next-line no-useless-escape
state.write(`\$\$${node.attrs.text || ''}\$\$`); state.write(`\$\$${node.attrs.text || ''}\$\$`);
state.closeBlock(node); state.closeBlock(node);
}, },

View File

@ -17,7 +17,7 @@ export const Size: React.FC<{ width: number; maxWidth?: number; height: number;
$form.current.validate().then((values) => { $form.current.validate().then((values) => {
onOk(values as ISize); onOk(values as ISize);
}); });
}, []); }, [onOk]);
return ( return (
<Dropdown <Dropdown

View File

@ -17,7 +17,7 @@ export const CountdownSettingModal: React.FC<IProps> = ({ editor }) => {
editor.chain().focus().setCountdown({ title: values.title, date: values.date.valueOf() }).run(); editor.chain().focus().setCountdown({ title: values.title, date: values.date.valueOf() }).run();
toggleVisible(false); toggleVisible(false);
}); });
}, []); }, [editor, toggleVisible]);
useEffect(() => { useEffect(() => {
const handler = (data) => { const handler = (data) => {
@ -30,7 +30,7 @@ export const CountdownSettingModal: React.FC<IProps> = ({ editor }) => {
return () => { return () => {
event.off(OPEN_COUNT_SETTING_MODAL, handler); event.off(OPEN_COUNT_SETTING_MODAL, handler);
}; };
}, []); }, [toggleVisible]);
return ( return (
<Modal centered title="倒计时" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)}> <Modal centered title="倒计时" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)}>

View File

@ -6,11 +6,14 @@ import { IconEmoji } from 'components/icons';
import { EmojiPicker } from 'components/emoji-picker'; import { EmojiPicker } from 'components/emoji-picker';
export const Emoji: React.FC<{ editor: Editor }> = ({ editor }) => { export const Emoji: React.FC<{ editor: Editor }> = ({ editor }) => {
const setEmoji = useCallback((emoji) => { const setEmoji = useCallback(
(emoji) => {
const { selection } = editor.state; const { selection } = editor.state;
const { $anchor } = selection; const { $anchor } = selection;
return editor.chain().insertContentAt($anchor.pos, emoji).run(); return editor.chain().insertContentAt($anchor.pos, emoji).run();
}, []); },
[editor]
);
return ( return (
<EmojiPicker onSelectEmoji={setEmoji}> <EmojiPicker onSelectEmoji={setEmoji}>

View File

@ -9,13 +9,16 @@ export const FontSize: React.FC<{ editor: Editor }> = ({ editor }) => {
const currentFontSizePx = editor.getAttributes('textStyle').fontSize || '16px'; const currentFontSizePx = editor.getAttributes('textStyle').fontSize || '16px';
const currentFontSize = +currentFontSizePx.replace('px', ''); const currentFontSize = +currentFontSizePx.replace('px', '');
const toggle = useCallback((val) => { const toggle = useCallback(
(val) => {
editor editor
.chain() .chain()
.focus() .focus()
.setFontSize(val + 'px') .setFontSize(val + 'px')
.run(); .run();
}, []); },
[editor]
);
return ( return (
<Select <Select

View File

@ -14,13 +14,16 @@ const getCurrentCaretTitle = (editor) => {
}; };
export const Heading: React.FC<{ editor: Editor }> = ({ editor }) => { export const Heading: React.FC<{ editor: Editor }> = ({ editor }) => {
const toggle = useCallback((level) => { const toggle = useCallback(
(level) => {
if (level === 'paragraph') { if (level === 'paragraph') {
editor.chain().focus().setParagraph().run(); editor.chain().focus().setParagraph().run();
} else { } else {
editor.chain().focus().toggleHeading({ level }).run(); editor.chain().focus().toggleHeading({ level }).run();
} }
}, []); },
[editor]
);
return ( return (
<Select <Select

View File

@ -27,7 +27,7 @@ export const IframeBubbleMenu = ({ editor }) => {
const handleCancel = useCallback(() => { const handleCancel = useCallback(() => {
toggleVisible(false); toggleVisible(false);
}, []); }, [toggleVisible]);
const handleOk = useCallback(() => { const handleOk = useCallback(() => {
$form.current.validate().then((values) => { $form.current.validate().then((values) => {
@ -41,7 +41,7 @@ export const IframeBubbleMenu = ({ editor }) => {
.run(); .run();
toggleVisible(false); toggleVisible(false);
}); });
}, []); }, [editor, toggleVisible]);
const visitLink = useCallback(() => { const visitLink = useCallback(() => {
window.open(url, '_blank'); window.open(url, '_blank');
@ -49,7 +49,7 @@ export const IframeBubbleMenu = ({ editor }) => {
const openEditLinkModal = useCallback(() => { const openEditLinkModal = useCallback(() => {
toggleVisible(true); toggleVisible(true);
}, []); }, [toggleVisible]);
const setSize = useCallback( const setSize = useCallback(
(size) => { (size) => {

View File

@ -154,14 +154,14 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
toggleVisible(false); toggleVisible(false);
}; };
}, },
[editor, toggleVisible] [editor, toggleVisible, transformToCommands, user]
); );
useEffect(() => { useEffect(() => {
if (!visible) return; if (!visible) return;
insertMenuLRUCache.syncFromStorage(); insertMenuLRUCache.syncFromStorage();
setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[])); setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[]));
}, [visible]); }, [visible, transformToCommands]);
if (!editor) { if (!editor) {
return null; return null;

View File

@ -1,3 +1,4 @@
/* 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';

View File

@ -27,7 +27,7 @@ export const LinkSettingModal: React.FC<IProps> = ({ editor }) => {
view.dispatch(view.state.tr.scrollIntoView()); view.dispatch(view.state.tr.scrollIntoView());
toggleVisible(false); toggleVisible(false);
}); });
}, [initialState]); }, [initialState, editor, toggleVisible]);
useEffect(() => { useEffect(() => {
const handler = (data) => { const handler = (data) => {
@ -40,7 +40,7 @@ export const LinkSettingModal: React.FC<IProps> = ({ editor }) => {
return () => { return () => {
event.off(OPEN_LINK_SETTING_MODAL, handler); event.off(OPEN_LINK_SETTING_MODAL, handler);
}; };
}, [editor]); }, [editor, toggleVisible]);
return ( return (
<Modal title="编辑链接" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)} centered> <Modal title="编辑链接" visible={visible} onOk={handleOk} onCancel={() => toggleVisible(false)} centered>

View File

@ -15,12 +15,16 @@ export const Search: React.FC<{ editor: Editor }> = ({ editor }) => {
const [replaceValue, setReplaceValue] = useState(''); const [replaceValue, setReplaceValue] = useState('');
useEffect(() => { useEffect(() => {
editor?.commands?.setSearchTerm(searchValue); if (editor && editor.commands && editor.commands.setSearchTerm) {
}, [searchValue]); editor.commands.setSearchTerm(searchValue);
}
}, [searchValue, editor]);
useEffect(() => { useEffect(() => {
editor?.commands?.setReplaceTerm(replaceValue); if (editor && editor.commands && editor.commands.setReplaceTerm) {
}, [replaceValue]); editor.commands.setReplaceTerm(replaceValue);
}
}, [replaceValue, editor]);
return ( return (
<Popover <Popover

View File

@ -44,7 +44,9 @@ export function copyNode(nodeOrNodeName: string | Node, editor?: Editor) {
toCopy.push({ text: markdown, format: 'text/markdown' }); toCopy.push({ text: markdown, format: 'text/markdown' });
const html = markdownToHTML(markdown); const html = markdownToHTML(markdown);
toCopy.push({ text: html, format: 'text/html' }); toCopy.push({ text: html, format: 'text/html' });
} catch (e) {} } catch (e) {
//
}
copy(toCopy); copy(toCopy);
} }

View File

@ -47,7 +47,7 @@ export const jsonToDOMDataset = (json: Record<string, unknown>) => {
* @param transformToJSON JSON * @param transformToJSON JSON
*/ */
export const getDatasetAttribute = export const getDatasetAttribute =
(attribute: string, transformToJSON: boolean = false) => (attribute: string, transformToJSON = false) =>
(element: HTMLElement) => { (element: HTMLElement) => {
const dataKey = attribute.startsWith('data-') ? attribute : `data-${attribute}`; const dataKey = attribute.startsWith('data-') ? attribute : `data-${attribute}`;
const value = decodeURIComponent(element.getAttribute(dataKey)); const value = decodeURIComponent(element.getAttribute(dataKey));

View File

@ -1,5 +1,5 @@
export function isValidURL(str) { export function isValidURL(str) {
var pattern = new RegExp( const pattern = new RegExp(
'^(https?:\\/\\/)?' + // protocol '^(https?:\\/\\/)?' + // protocol
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address

View File

@ -1,15 +1,15 @@
export function uuid() { export function uuid() {
var s = []; const s = [];
var hexDigits = '0123456789abcdef'; const hexDigits = '0123456789abcdef';
for (var i = 0; i < 36; i++) { for (let i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
} }
s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010 s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = '-'; s[8] = s[13] = s[18] = s[23] = '-';
var uuid = s.join(''); const uuid = s.join('');
return uuid; return uuid;
} }

View File

@ -48,7 +48,6 @@ export const getProvider = ({
docType, docType,
}, },
maxAttempts: 5, maxAttempts: 5,
forceSyncInterval: 100,
...events, ...events,
} as any); } as any);
pool.set(targetId, provider); pool.set(targetId, provider);

View File

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

View File

@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import cls from 'classnames'; import cls from 'classnames';
import { NodeViewWrapper } from '@tiptap/react'; import { NodeViewWrapper } from '@tiptap/react';
import { Button, Typography, Spin, Collapsible, Space } from '@douyinfe/semi-ui'; import { Button, Typography, Spin, Collapsible, Space } from '@douyinfe/semi-ui';
@ -20,12 +20,13 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
const [loading, toggleLoading] = useToggle(false); const [loading, toggleLoading] = useToggle(false);
const [visible, toggleVisible] = useToggle(false); const [visible, toggleVisible] = useToggle(false);
const selectFile = () => { const selectFile = useCallback(() => {
if (!isEditable || url) return; if (!isEditable || url) return;
isEditable && $upload.current.click(); isEditable && $upload.current.click();
}; }, [isEditable, url]);
const handleFile = async (e) => { const handleFile = useCallback(
async (e) => {
const file = e.target.files && e.target.files[0]; const file = e.target.files && e.target.files[0];
const fileInfo = { const fileInfo = {
fileName: extractFilename(file.name), fileName: extractFilename(file.name),
@ -42,14 +43,16 @@ export const AttachmentWrapper = ({ editor, node, updateAttributes }) => {
updateAttributes({ error: '文件上传失败:' + (error && error.message) || '未知错误' }); updateAttributes({ error: '文件上传失败:' + (error && error.message) || '未知错误' });
toggleLoading(false); toggleLoading(false);
} }
}; },
[toggleLoading, updateAttributes]
);
useEffect(() => { useEffect(() => {
if (!url && !hasTrigger) { if (!url && !hasTrigger) {
selectFile(); selectFile();
updateAttributes({ hasTrigger: true }); updateAttributes({ hasTrigger: true });
} }
}, [url, hasTrigger]); }, [url, hasTrigger, selectFile, updateAttributes]);
const content = (() => { const content = (() => {
if (isEditable && !url) { if (isEditable && !url) {

View File

@ -8,9 +8,12 @@ export const CalloutWrapper = ({ editor, node, updateAttributes }) => {
const { isEditable } = editor; const { isEditable } = editor;
const { emoji, textColor, borderColor, backgroundColor } = node.attrs; const { emoji, textColor, borderColor, backgroundColor } = node.attrs;
const onSelectEmoji = useCallback((emoji) => { const onSelectEmoji = useCallback(
(emoji) => {
updateAttributes({ emoji }); updateAttributes({ emoji });
}, []); },
[updateAttributes]
);
return ( return (
<NodeViewWrapper id="js-bannber-container" className={cls(styles.wrap)}> <NodeViewWrapper id="js-bannber-container" className={cls(styles.wrap)}>

View File

@ -17,7 +17,7 @@ export const DocumentChildrenWrapper = ({ editor, node, updateAttributes }) => {
const { pathname, query } = useRouter(); const { pathname, query } = useRouter();
let { wikiId, documentId } = node.attrs; let { wikiId, documentId } = node.attrs;
if (!wikiId) { if (!wikiId) {
query?.wikiId; wikiId = query?.wikiId;
} }
if (!documentId) { if (!documentId) {
documentId = query?.documentId; documentId = query?.documentId;
@ -31,7 +31,7 @@ export const DocumentChildrenWrapper = ({ editor, node, updateAttributes }) => {
if (attrs.wikiId !== wikiId || attrs.documentId !== documentId) { if (attrs.wikiId !== wikiId || attrs.documentId !== documentId) {
updateAttributes({ wikiId, documentId }); updateAttributes({ wikiId, documentId });
} }
}, [node.attrs, wikiId, documentId]); }, [node.attrs, wikiId, documentId, updateAttributes]);
return ( return (
<NodeViewWrapper <NodeViewWrapper

View File

@ -44,7 +44,7 @@ export const DocumentReferenceWrapper = ({ editor, node, updateAttributes }) =>
</a> </a>
</Link> </Link>
); );
}, [wikiId, documentId]); }, [wikiId, documentId, isEditable, isShare, title]);
return ( return (
<NodeViewWrapper as="div" className={cls(styles.wrap, isEditable && 'render-wrapper')}> <NodeViewWrapper as="div" className={cls(styles.wrap, isEditable && 'render-wrapper')}>

View File

@ -81,3 +81,5 @@ export const EmojiList: React.FC<IProps> = forwardRef((props, ref) => {
</div> </div>
); );
}); });
EmojiList.displayName = 'EmojiList';

View File

@ -13,9 +13,12 @@ export const IframeWrapper = ({ editor, node, updateAttributes }) => {
const { url, width, height } = node.attrs; const { url, width, height } = node.attrs;
const { width: maxWidth } = getEditorContainerDOMSize(editor); const { width: maxWidth } = getEditorContainerDOMSize(editor);
const onResize = useCallback((size) => { const onResize = useCallback(
(size) => {
updateAttributes({ width: size.width, height: size.height }); updateAttributes({ width: size.width, height: size.height });
}, []); },
[updateAttributes]
);
return ( return (
<NodeViewWrapper> <NodeViewWrapper>

View File

@ -22,16 +22,20 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
const $upload = useRef<HTMLInputElement>(); const $upload = useRef<HTMLInputElement>();
const [loading, toggleLoading] = useToggle(false); const [loading, toggleLoading] = useToggle(false);
const onResize = useCallback((size) => { const onResize = useCallback(
(size) => {
updateAttributes({ height: size.height, width: size.width }); updateAttributes({ height: size.height, width: size.width });
}, []); },
[updateAttributes]
);
const selectFile = useCallback(() => { const selectFile = useCallback(() => {
if (!isEditable || error || src) return; if (!isEditable || error || src) return;
isEditable && $upload.current.click(); isEditable && $upload.current.click();
}, [isEditable, error, src]); }, [isEditable, error, src]);
const handleFile = useCallback(async (e) => { const handleFile = useCallback(
async (e) => {
const file = e.target.files && e.target.files[0]; const file = e.target.files && e.target.files[0];
const fileInfo = { const fileInfo = {
@ -52,14 +56,16 @@ export const ImageWrapper = ({ editor, node, updateAttributes }) => {
updateAttributes({ error: '图片上传失败:' + (error && error.message) || '未知错误' }); updateAttributes({ error: '图片上传失败:' + (error && error.message) || '未知错误' });
toggleLoading(false); toggleLoading(false);
} }
}, []); },
[updateAttributes, toggleLoading]
);
useEffect(() => { useEffect(() => {
if (!src && !hasTrigger) { if (!src && !hasTrigger) {
selectFile(); selectFile();
updateAttributes({ hasTrigger: true }); updateAttributes({ hasTrigger: true });
} }
}, [src, hasTrigger]); }, [src, hasTrigger, selectFile, updateAttributes]);
return ( return (
<NodeViewWrapper as="div" style={{ textAlign, fontSize: 0, maxWidth: '100%' }}> <NodeViewWrapper as="div" style={{ textAlign, fontSize: 0, maxWidth: '100%' }}>

View File

@ -32,7 +32,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
) : ( ) : (
<span contentEditable={false}></span> <span contentEditable={false}></span>
), ),
[text] [text, formatText]
); );
const onVisibleChange = useCallback( const onVisibleChange = useCallback(
@ -42,7 +42,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
updateAttributes({ defaultShowPicker: false }); updateAttributes({ defaultShowPicker: false });
} }
}, },
[defaultShowPicker, updateAttributes, createUser, user] [defaultShowPicker, toggleVisible, updateAttributes, createUser, user]
); );
useEffect(() => { useEffect(() => {
@ -50,7 +50,7 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
toggleVisible(true); toggleVisible(true);
setTimeout(() => ref.current?.focus(), 100); setTimeout(() => ref.current?.focus(), 100);
} }
}, [defaultShowPicker, createUser, user]); }, [defaultShowPicker, toggleVisible, createUser, user]);
return ( return (
<NodeViewWrapper as="span" className={cls(styles.wrap, 'render-wrapper')} contentEditable={false}> <NodeViewWrapper as="span" className={cls(styles.wrap, 'render-wrapper')} contentEditable={false}>

View File

@ -81,3 +81,5 @@ export const MentionList: React.FC<IProps> = forwardRef((props, ref) => {
</div> </div>
); );
}); });
MentionList.displayName = 'MentionList';

View File

@ -87,3 +87,5 @@ export const MenuList: React.FC<IProps> = forwardRef((props, ref) => {
</div> </div>
); );
}); });
MenuList.displayName = 'MenuList';

View File

@ -47,7 +47,7 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
style={{ ...INHERIT_SIZE_STYLE, overflow: 'hidden' }} style={{ ...INHERIT_SIZE_STYLE, overflow: 'hidden' }}
></div> ></div>
); );
}, [loading, error, width, height]); }, [loading, error]);
const onResize = useCallback( const onResize = useCallback(
(size) => { (size) => {
@ -69,11 +69,12 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
.catch((e) => { .catch((e) => {
setError(e); setError(e);
}); });
}, []); }, [toggleLoading]);
// 初始化渲染 // 初始化渲染
useEffect(() => { useEffect(() => {
if (loading || !$container.current) return; const container = $container.current;
if (loading || !container) return;
const onChange = () => { const onChange = () => {
updateAttributes({ data: mind.getAllData() }); updateAttributes({ data: mind.getAllData() });
@ -89,8 +90,8 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
isEnter = false; isEnter = false;
}; };
$container.current.addEventListener('onmouseenter', onMouseEnter); container.addEventListener('onmouseenter', onMouseEnter);
$container.current.addEventListener('onMouseLeave', onMouseLeave); container.addEventListener('onMouseLeave', onMouseLeave);
try { try {
mind = new window.MindElixir({ mind = new window.MindElixir({
@ -115,16 +116,18 @@ export const MindWrapper = ({ editor, node, updateAttributes }) => {
} }
return () => { return () => {
if ($container.current) { if (container) {
$container.current.removeEventListener('onmouseenter', onMouseEnter); container.removeEventListener('onmouseenter', onMouseEnter);
$container.current.removeEventListener('onMouseLeave', onMouseLeave); container.removeEventListener('onMouseLeave', onMouseLeave);
} }
if (mind) { if (mind) {
mind.destroy(); mind.destroy();
} }
}; };
}, [loading, editor, updateAttributes]); // data 的更新交给下方 effect
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [loading, editor, updateAttributes, toggleLoading]);
useEffect(() => { useEffect(() => {
const mind = $mind.current; const mind = $mind.current;

View File

@ -14,8 +14,8 @@ import { SIDE, GAP, TURNPOINT_R, PRIMARY_NODE_HORIZONTAL_GAP, PRIMARY_NODE_VERTI
* @param {object} primaryNode process the specific primary node only * @param {object} primaryNode process the specific primary node only
*/ */
export default function linkDiv(primaryNode) { export default function linkDiv(primaryNode) {
var primaryNodeHorizontalGap = this.primaryNodeHorizontalGap || PRIMARY_NODE_HORIZONTAL_GAP; const primaryNodeHorizontalGap = this.primaryNodeHorizontalGap || PRIMARY_NODE_HORIZONTAL_GAP;
var primaryNodeVerticalGap = this.primaryNodeVerticalGap || PRIMARY_NODE_VERTICAL_GAP; const primaryNodeVerticalGap = this.primaryNodeVerticalGap || PRIMARY_NODE_VERTICAL_GAP;
console.time('linkDiv'); console.time('linkDiv');
const root = this.root; const root = this.root;
root.style.cssText = `top:${10000 - root.offsetHeight / 2}px;left:${10000 - root.offsetWidth / 2}px;`; root.style.cssText = `top:${10000 - root.offsetHeight / 2}px;left:${10000 - root.offsetWidth / 2}px;`;

View File

@ -86,6 +86,7 @@ const Toolbar = ({ mind, toggleBold, setFontColor, setBackgroundColor, setLink }
return () => { return () => {
mind.bus.removeListener('selectNode', listener); mind.bus.removeListener('selectNode', listener);
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, []);
return ( return (

View File

@ -137,6 +137,7 @@ export function createInputDiv(tpc: Topic) {
div.addEventListener('blur', () => { div.addEventListener('blur', () => {
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
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;

View File

@ -51,11 +51,12 @@ export function refreshIds(data: NodeObj) {
} }
export const throttle = (fn: (any) => void, wait: number) => { export const throttle = (fn: (any) => void, wait: number) => {
var pre = Date.now(); let pre = Date.now();
return function () { return function () {
var context = this; const context = this;
var args = arguments; // eslint-disable-next-line prefer-rest-params
var now = Date.now(); const args = arguments;
const now = Date.now();
if (now - pre >= wait) { if (now - pre >= wait) {
fn.apply(context, args); fn.apply(context, args);
pre = Date.now(); pre = Date.now();
@ -78,7 +79,7 @@ export function getArrowPoints(p3x: number, p3y: number, p4x: number, p4y: numbe
} }
const arrowLength = 20; const arrowLength = 20;
const arrowAngle = 30; const arrowAngle = 30;
var a1 = angle + arrowAngle; const a1 = angle + arrowAngle;
const a2 = angle - arrowAngle; const a2 = angle - arrowAngle;
return { return {
x1: p4x + Math.cos((Math.PI * a1) / 180) * arrowLength, x1: p4x + Math.cos((Math.PI * a1) / 180) * arrowLength,

View File

@ -11,19 +11,19 @@ Bus.prototype = {
}, },
fire: function (type, ...payload) { fire: function (type, ...payload) {
if (this.handlers[type] instanceof Array) { if (this.handlers[type] instanceof Array) {
var handlers = this.handlers[type]; const handlers = this.handlers[type];
for (var i = 0; i < handlers.length; i++) { for (let i = 0; i < handlers.length; i++) {
handlers[i](...payload); handlers[i](...payload);
} }
} }
}, },
removeListener: function (type, handler) { removeListener: function (type, handler) {
if (!this.handlers[type]) return; if (!this.handlers[type]) return;
var handlers = this.handlers[type]; const handlers = this.handlers[type];
if (!handler) { if (!handler) {
handlers.length = 0; handlers.length = 0;
} else if (handlers.length) { } else if (handlers.length) {
for (var i = 0; i < handlers.length; i++) { for (let i = 0; i < handlers.length; i++) {
if (handlers[i] === handler) { if (handlers[i] === handler) {
this.handlers[type].splice(i, 1); this.handlers[type].splice(i, 1);
} }

View File

@ -72,7 +72,7 @@ export const StatusWrapper = ({ editor, node, updateAttributes }) => {
updateAttributes({ defaultShowPicker: false }); updateAttributes({ defaultShowPicker: false });
} }
}, },
[defaultShowPicker, updateAttributes, createUser, user] [defaultShowPicker, toggleVisible, updateAttributes, createUser, user]
); );
useEffect(() => { useEffect(() => {
@ -80,7 +80,7 @@ export const StatusWrapper = ({ editor, node, updateAttributes }) => {
toggleVisible(true); toggleVisible(true);
setTimeout(() => ref.current?.focus(), 100); setTimeout(() => ref.current?.focus(), 100);
} }
}, [defaultShowPicker, createUser, user]); }, [defaultShowPicker, toggleVisible, createUser, user]);
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {