tiptap: only auto show picker when user is author

This commit is contained in:
fantasticit 2022-04-27 12:11:03 +08:00
parent 2643c5a42e
commit a5a4d95c1b
8 changed files with 49 additions and 21 deletions

View File

@ -5,6 +5,7 @@ import { KatexWrapper } from '../wrappers/katex';
type IKatexAttrs = { type IKatexAttrs = {
text?: string; text?: string;
defaultShowPicker?: boolean; defaultShowPicker?: boolean;
createUser: string;
}; };
declare module '@tiptap/core' { declare module '@tiptap/core' {
@ -43,6 +44,9 @@ export const Katex = Node.create({
defaultShowPicker: { defaultShowPicker: {
default: false, default: false,
}, },
createUser: {
default: null,
},
}; };
}, },
@ -57,7 +61,7 @@ export const Katex = Node.create({
addCommands() { addCommands() {
return { return {
setKatex: setKatex:
(options = {}) => (options) =>
({ commands }) => { ({ commands }) => {
return commands.insertContent({ return commands.insertContent({
type: this.name, type: this.name,

View File

@ -26,7 +26,7 @@ export const QuickInsert = Node.create({
const $from = state.selection.$from; const $from = state.selection.$from;
const tr = state.tr.deleteRange($from.start(), $from.pos); const tr = state.tr.deleteRange($from.start(), $from.pos);
dispatch(tr); dispatch(tr);
props?.command(editor); props?.command(editor, props.user);
editor?.view?.focus(); editor?.view?.focus();
}, },
}, },

View File

@ -7,6 +7,7 @@ type IStatusAttrs = {
color?: string; color?: string;
text?: string; text?: string;
defaultShowPicker?: boolean; defaultShowPicker?: boolean;
createUser: string;
}; };
declare module '@tiptap/core' { declare module '@tiptap/core' {
@ -37,6 +38,9 @@ export const Status = Node.create({
defaultShowPicker: { defaultShowPicker: {
default: false, default: false,
}, },
createUser: {
default: null,
},
}; };
}, },
@ -63,7 +67,7 @@ export const Status = Node.create({
addCommands() { addCommands() {
return { return {
setStatus: setStatus:
(options = {}) => (options) =>
({ commands }) => { ({ commands }) => {
return commands.insertContent({ return commands.insertContent({
type: this.name, type: this.name,

View File

@ -18,6 +18,7 @@ import {
} from 'components/icons'; } from 'components/icons';
import { GridSelect } from 'components/grid-select'; import { GridSelect } from 'components/grid-select';
import { useToggle } from 'hooks/use-toggle'; import { useToggle } from 'hooks/use-toggle';
import { useUser } from 'data/user';
import { createKeysLocalStorageLRUCache } from 'helpers/lru-cache'; import { createKeysLocalStorageLRUCache } from 'helpers/lru-cache';
import { isTitleActive } from '../../utils/is-active'; import { isTitleActive } from '../../utils/is-active';
import { createCountdown } from '../countdown/service'; import { createCountdown } from '../countdown/service';
@ -92,12 +93,13 @@ const COMMANDS = [
{ {
icon: <IconMath />, icon: <IconMath />,
label: '数学公式', label: '数学公式',
action: (editor) => editor.chain().focus().setKatex({ defaultShowPicker: true }).run(), action: (editor, user) => editor.chain().focus().setKatex({ defaultShowPicker: true, createUser: user.name }).run(),
}, },
{ {
icon: <IconStatus />, icon: <IconStatus />,
label: '状态', label: '状态',
action: (editor) => editor.chain().focus().setStatus({ defaultShowPicker: true }).run(), action: (editor, user) =>
editor.chain().focus().setStatus({ defaultShowPicker: true, createUser: user.name }).run(),
}, },
{ {
icon: <IconCallout />, icon: <IconCallout />,
@ -120,6 +122,7 @@ const COMMANDS = [
]; ];
export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => { export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
const { user } = useUser();
const [recentUsed, setRecentUsed] = useState([]); const [recentUsed, setRecentUsed] = useState([]);
const [visible, toggleVisible] = useToggle(false); const [visible, toggleVisible] = useToggle(false);
@ -141,7 +144,7 @@ export const Insert: React.FC<{ editor: Editor }> = ({ editor }) => {
return () => { return () => {
insertMenuLRUCache.put(command.label); insertMenuLRUCache.put(command.label);
setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[])); setRecentUsed(transformToCommands(insertMenuLRUCache.get() as string[]));
command.action(editor); command.action(editor, user);
toggleVisible(false); toggleVisible(false);
}; };
}, },

View File

@ -209,14 +209,19 @@ export const QUICK_INSERT_ITEMS = [
</Space> </Space>
), ),
command: (editor: Editor) => command: (editor: Editor, user) => {
console.log('user', user);
if (!user) return;
editor editor
.chain() .chain()
.focus() .focus()
.setKatex({ .setKatex({
defaultShowPicker: true, defaultShowPicker: true,
createUser: user.name,
}) })
.run(), .run();
},
}, },
{ {
@ -227,14 +232,18 @@ export const QUICK_INSERT_ITEMS = [
</Space> </Space>
), ),
command: (editor: Editor) => command: (editor: Editor, user) => {
if (!user) return;
editor editor
.chain() .chain()
.focus() .focus()
.setStatus({ .setStatus({
defaultShowPicker: true, defaultShowPicker: true,
createUser: user.name,
}) })
.run(), .run();
},
}, },
{ {

View File

@ -5,13 +5,15 @@ 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 { useToggle } from 'hooks/use-toggle';
import { useUser } from 'data/user';
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, defaultShowPicker } = node.attrs; const { text, defaultShowPicker, createUser } = node.attrs;
const { user } = useUser();
const ref = useRef<HTMLTextAreaElement>(); const ref = useRef<HTMLTextAreaElement>();
const [visible, toggleVisible] = useToggle(false); const [visible, toggleVisible] = useToggle(false);
@ -36,19 +38,19 @@ export const KatexWrapper = ({ editor, node, updateAttributes }) => {
const onVisibleChange = useCallback( const onVisibleChange = useCallback(
(value) => { (value) => {
toggleVisible(value); toggleVisible(value);
if (defaultShowPicker) { if (defaultShowPicker && user && createUser === user.name) {
updateAttributes({ defaultShowPicker: false }); updateAttributes({ defaultShowPicker: false });
} }
}, },
[defaultShowPicker, updateAttributes] [defaultShowPicker, updateAttributes, createUser, user]
); );
useEffect(() => { useEffect(() => {
if (defaultShowPicker) { if (defaultShowPicker && user && createUser === user.name) {
toggleVisible(true); toggleVisible(true);
setTimeout(() => ref.current?.focus(), 100); setTimeout(() => ref.current?.focus(), 100);
} }
}, [defaultShowPicker]); }, [defaultShowPicker, 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

@ -2,6 +2,7 @@ import { Editor } from '@tiptap/core';
import React, { useState, useEffect, forwardRef, useImperativeHandle, useRef } from 'react'; import React, { useState, useEffect, forwardRef, useImperativeHandle, useRef } from 'react';
import cls from 'classnames'; import cls from 'classnames';
import scrollIntoView from 'scroll-into-view-if-needed'; import scrollIntoView from 'scroll-into-view-if-needed';
import { useUser } from 'data/user';
import styles from './index.module.scss'; import styles from './index.module.scss';
interface IProps { interface IProps {
@ -11,6 +12,7 @@ interface IProps {
} }
export const MenuList: React.FC<IProps> = forwardRef((props, ref) => { export const MenuList: React.FC<IProps> = forwardRef((props, ref) => {
const { user } = useUser();
const $container = useRef<HTMLDivElement>(); const $container = useRef<HTMLDivElement>();
const [selectedIndex, setSelectedIndex] = useState(0); const [selectedIndex, setSelectedIndex] = useState(0);
@ -18,6 +20,8 @@ export const MenuList: React.FC<IProps> = forwardRef((props, ref) => {
const item = props.items[index]; const item = props.items[index];
if (item) { if (item) {
// @ts-ignore
item.user = user; // 注入用户信息
props.command(item); props.command(item);
} }
}; };

View File

@ -1,9 +1,10 @@
import { NodeViewWrapper, NodeViewContent } from '@tiptap/react'; import { NodeViewWrapper, NodeViewContent } from '@tiptap/react';
import { Button, Collapsible, Space, Popover, Tag, Input } from '@douyinfe/semi-ui'; import { Button, Collapsible, Space, Popover, Tag, Input } from '@douyinfe/semi-ui';
import cls from 'classnames'; import cls from 'classnames';
import { useCallback, useEffect, useRef } from 'react';
import { useUser } from 'data/user';
import { useToggle } from 'hooks/use-toggle'; import { useToggle } from 'hooks/use-toggle';
import styles from './index.module.scss'; import styles from './index.module.scss';
import { useCallback, useEffect, useRef } from 'react';
const colors = [ const colors = [
'#F5222D', '#F5222D',
@ -52,7 +53,8 @@ const colors = [
export const StatusWrapper = ({ editor, node, updateAttributes }) => { export const StatusWrapper = ({ editor, node, updateAttributes }) => {
const isEditable = editor.isEditable; const isEditable = editor.isEditable;
const { color, text, defaultShowPicker } = node.attrs; const { color, text, defaultShowPicker, createUser } = node.attrs;
const { user } = useUser();
const ref = useRef<HTMLInputElement>(); const ref = useRef<HTMLInputElement>();
const [visible, toggleVisible] = useToggle(false); const [visible, toggleVisible] = useToggle(false);
const [isOpen, toggleOpen] = useToggle(false); const [isOpen, toggleOpen] = useToggle(false);
@ -66,19 +68,19 @@ export const StatusWrapper = ({ editor, node, updateAttributes }) => {
const onVisibleChange = useCallback( const onVisibleChange = useCallback(
(value) => { (value) => {
toggleVisible(value); toggleVisible(value);
if (defaultShowPicker) { if (defaultShowPicker && user && user.name === createUser) {
updateAttributes({ defaultShowPicker: false }); updateAttributes({ defaultShowPicker: false });
} }
}, },
[defaultShowPicker, updateAttributes] [defaultShowPicker, updateAttributes, createUser, user]
); );
useEffect(() => { useEffect(() => {
if (defaultShowPicker) { if (defaultShowPicker && user && user.name === createUser) {
toggleVisible(true); toggleVisible(true);
setTimeout(() => ref.current?.focus(), 100); setTimeout(() => ref.current?.focus(), 100);
} }
}, [defaultShowPicker]); }, [defaultShowPicker, createUser, user]);
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {