mirror of https://github.com/fantasticit/think.git
feat: add defaultShowPicker for katex
parent
c9d4fd5127
commit
f89c1051db
|
@ -2,10 +2,15 @@ import { Node, mergeAttributes, nodeInputRule } from '@tiptap/core';
|
||||||
import { ReactNodeViewRenderer } from '@tiptap/react';
|
import { ReactNodeViewRenderer } from '@tiptap/react';
|
||||||
import { KatexWrapper } from '../wrappers/katex';
|
import { KatexWrapper } from '../wrappers/katex';
|
||||||
|
|
||||||
|
type IKatexAttrs = {
|
||||||
|
text?: string;
|
||||||
|
defaultShowPicker?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
declare module '@tiptap/core' {
|
declare module '@tiptap/core' {
|
||||||
interface Commands<ReturnType> {
|
interface Commands<ReturnType> {
|
||||||
katex: {
|
katex: {
|
||||||
setKatex: () => ReturnType;
|
setKatex: (arg?: IKatexAttrs) => ReturnType;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +40,9 @@ export const Katex = Node.create({
|
||||||
return element.getAttribute('data-text');
|
return element.getAttribute('data-text');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
defaultShowPicker: {
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||||
<IconMind /> 思维导图
|
<IconMind /> 思维导图
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
|
|
||||||
<Dropdown.Item onClick={() => editor.chain().focus().setKatex().run()}>
|
<Dropdown.Item onClick={() => editor.chain().focus().setKatex({ defaultShowPicker: true }).run()}>
|
||||||
<IconMath /> 数学公式
|
<IconMath /> 数学公式
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,14 @@ export const QUICK_INSERT_ITEMS = [
|
||||||
数学公式
|
数学公式
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
command: (editor: Editor) => editor.chain().focus().setKatex().run(),
|
command: (editor: Editor) =>
|
||||||
|
editor
|
||||||
|
.chain()
|
||||||
|
.focus()
|
||||||
|
.setKatex({
|
||||||
|
defaultShowPicker: true,
|
||||||
|
})
|
||||||
|
.run(),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
.wrap {
|
.wrap {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0 8px;
|
transform: translateY(1px);
|
||||||
transform: translateY(8px);
|
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
import { NodeViewWrapper, NodeViewContent } from '@tiptap/react';
|
import { NodeViewWrapper, NodeViewContent } from '@tiptap/react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo, useCallback, useEffect, useRef } from 'react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { Popover, TextArea, Typography, Space } from '@douyinfe/semi-ui';
|
import { Popover, TextArea, Typography, Space } from '@douyinfe/semi-ui';
|
||||||
import { IconHelpCircle } from '@douyinfe/semi-icons';
|
import { IconHelpCircle } from '@douyinfe/semi-icons';
|
||||||
import katex from 'katex';
|
import katex from 'katex';
|
||||||
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
export const KatexWrapper = ({ editor, node, updateAttributes }) => {
|
export const KatexWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const isEditable = editor.isEditable;
|
const isEditable = editor.isEditable;
|
||||||
const { text } = node.attrs;
|
const { text, defaultShowPicker } = node.attrs;
|
||||||
|
const ref = useRef<HTMLTextAreaElement>();
|
||||||
|
const [visible, toggleVisible] = useToggle(false);
|
||||||
|
|
||||||
const formatText = useMemo(() => {
|
const formatText = useMemo(() => {
|
||||||
try {
|
try {
|
||||||
|
@ -20,22 +23,46 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
}
|
}
|
||||||
}, [text]);
|
}, [text]);
|
||||||
|
|
||||||
const content = text.trim() ? (
|
const content = useMemo(
|
||||||
<span contentEditable={false} dangerouslySetInnerHTML={{ __html: formatText }}></span>
|
() =>
|
||||||
) : (
|
text.trim() ? (
|
||||||
<span contentEditable={false}>点击输入公式</span>
|
<span contentEditable={false} dangerouslySetInnerHTML={{ __html: formatText }}></span>
|
||||||
|
) : (
|
||||||
|
<span contentEditable={false}>点击输入公式</span>
|
||||||
|
),
|
||||||
|
[text]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onVisibleChange = useCallback(
|
||||||
|
(value) => {
|
||||||
|
toggleVisible(value);
|
||||||
|
if (defaultShowPicker) {
|
||||||
|
updateAttributes({ defaultShowPicker: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[defaultShowPicker, updateAttributes]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (defaultShowPicker) {
|
||||||
|
toggleVisible(true);
|
||||||
|
setTimeout(() => ref.current?.focus(), 100);
|
||||||
|
}
|
||||||
|
}, [defaultShowPicker]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NodeViewWrapper as="span" className={cls(styles.wrap, 'render-wrapper')} contentEditable={false}>
|
<NodeViewWrapper as="span" className={cls(styles.wrap, 'render-wrapper')} contentEditable={false}>
|
||||||
<NodeViewContent />
|
|
||||||
{isEditable ? (
|
{isEditable ? (
|
||||||
<Popover
|
<Popover
|
||||||
showArrow
|
showArrow
|
||||||
position="bottomLeft"
|
position="bottomLeft"
|
||||||
|
spacing={12}
|
||||||
|
visible={visible}
|
||||||
|
onVisibleChange={onVisibleChange}
|
||||||
content={
|
content={
|
||||||
<div style={{ width: 320 }}>
|
<div style={{ width: 320 }}>
|
||||||
<TextArea
|
<TextArea
|
||||||
|
ref={ref}
|
||||||
autofocus
|
autofocus
|
||||||
placeholder="输入公式"
|
placeholder="输入公式"
|
||||||
autosize
|
autosize
|
||||||
|
@ -59,7 +86,6 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
) : (
|
) : (
|
||||||
content
|
content
|
||||||
)}
|
)}
|
||||||
<NodeViewContent />
|
|
||||||
</NodeViewWrapper>
|
</NodeViewWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue