feat: add global event center

pull/25/head
fantasticit 2022-04-03 11:06:21 +08:00
parent a8d9f41734
commit 11ce42dbe3
11 changed files with 72 additions and 65 deletions

View File

@ -17,11 +17,11 @@ import {
} from '@douyinfe/semi-ui'; } from '@douyinfe/semi-ui';
import { IconUserAdd, IconDelete } from '@douyinfe/semi-icons'; import { IconUserAdd, IconDelete } from '@douyinfe/semi-icons';
import { useUser } from 'data/user'; import { useUser } from 'data/user';
import { EventEmitter } from 'helpers/event-emitter';
import { useToggle } from 'hooks/use-toggle'; import { useToggle } from 'hooks/use-toggle';
import { useCollaborationDocument } from 'data/document'; import { useCollaborationDocument } from 'data/document';
import { DataRender } from 'components/data-render'; import { DataRender } from 'components/data-render';
import { DocumentLinkCopyer } from 'components/document/link'; import { DocumentLinkCopyer } from 'components/document/link';
import { event, JOIN_USER } from 'event';
interface IProps { interface IProps {
wikiId: string; wikiId: string;
@ -31,13 +31,6 @@ interface IProps {
const { Paragraph } = Typography; const { Paragraph } = Typography;
const { Column } = Table; const { Column } = Table;
const CollaborationEventEmitter = new EventEmitter();
const KEY = 'JOIN_USER';
export const joinUser = (users) => {
CollaborationEventEmitter.emit(KEY, users);
};
const renderChecked = (onChange, authKey: 'readable' | 'editable') => (checked, docAuth) => { const renderChecked = (onChange, authKey: 'readable' | 'editable') => (checked, docAuth) => {
const handle = (evt) => { const handle = (evt) => {
const data = { const data = {
@ -56,7 +49,6 @@ export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId })
const [visible, toggleVisible] = useToggle(false); const [visible, toggleVisible] = useToggle(false);
const { users, loading, error, addUser, updateUser, deleteUser } = useCollaborationDocument(documentId); const { users, loading, error, addUser, updateUser, deleteUser } = useCollaborationDocument(documentId);
const [inviteUser, setInviteUser] = useState(''); const [inviteUser, setInviteUser] = useState('');
const [collaborationUsers, setCollaborationUsers] = useState([]); const [collaborationUsers, setCollaborationUsers] = useState([]);
const handleOk = () => { const handleOk = () => {
@ -75,7 +67,7 @@ export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId })
}; };
useEffect(() => { useEffect(() => {
CollaborationEventEmitter.on(KEY, ({ states: users }) => { const handler = (users) => {
const newCollaborationUsers = users const newCollaborationUsers = users
.filter(Boolean) .filter(Boolean)
.filter((state) => state.user) .filter((state) => state.user)
@ -97,10 +89,11 @@ export const DocumentCollaboration: React.FC<IProps> = ({ wikiId, documentId })
}); });
setCollaborationUsers(newCollaborationUsers); setCollaborationUsers(newCollaborationUsers);
}); };
event.on(JOIN_USER, handler);
return () => { return () => {
CollaborationEventEmitter.destroy(); event.off(JOIN_USER, handler);
}; };
}, [collaborationUsers, currentUser]); }, [collaborationUsers, currentUser]);

View File

@ -3,7 +3,7 @@ import Router from 'next/router';
import { Typography, Space, Modal } from '@douyinfe/semi-ui'; import { Typography, Space, Modal } from '@douyinfe/semi-ui';
import { IconDelete } from '@douyinfe/semi-icons'; import { IconDelete } from '@douyinfe/semi-icons';
import { useDeleteDocument } from 'data/document'; import { useDeleteDocument } from 'data/document';
import { triggerRefreshTocs } from 'components/wiki/tocs/event'; import { triggerRefreshTocs } from 'event';
interface IProps { interface IProps {
wikiId: string; wikiId: string;

View File

@ -18,10 +18,9 @@ import {
destoryIndexdbProvider, destoryIndexdbProvider,
} from 'tiptap'; } from 'tiptap';
import { DataRender } from 'components/data-render'; import { DataRender } from 'components/data-render';
import { joinUser } from 'components/document/collaboration';
import { Banner } from 'components/banner'; import { Banner } from 'components/banner';
import { debounce } from 'helpers/debounce'; import { debounce } from 'helpers/debounce';
import { em, changeTitle, USE_DATA_VERSION } from './index'; import { event, triggerChangeDocumentTitle, triggerJoinUser, USE_DOCUMENT_VERSION } from 'event';
import styles from './index.module.scss'; import styles from './index.module.scss';
interface IProps { interface IProps {
@ -45,7 +44,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
docType: 'document', docType: 'document',
events: { events: {
onAwarenessUpdate({ states }) { onAwarenessUpdate({ states }) {
joinUser({ states }); triggerJoinUser(states);
}, },
}, },
}); });
@ -62,7 +61,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
onTransaction: debounce(({ transaction }) => { onTransaction: debounce(({ transaction }) => {
try { try {
const title = transaction.doc.content.firstChild.content.firstChild.textContent; const title = transaction.doc.content.firstChild.content.firstChild.textContent;
changeTitle(title); triggerChangeDocumentTitle(title);
} catch (e) {} } catch (e) {}
}, 50), }, 50),
}); });
@ -92,10 +91,9 @@ export const Editor: React.FC<IProps> = ({ user, documentId, authority, classNam
useEffect(() => { useEffect(() => {
if (!editor) return; if (!editor) return;
const handler = (data) => editor.commands.setContent(data); const handler = (data) => editor.commands.setContent(data);
em.on(USE_DATA_VERSION, handler); event.on(USE_DOCUMENT_VERSION, handler);
return () => { return () => {
em.off(USE_DATA_VERSION, handler); event.off(USE_DOCUMENT_VERSION, handler);
}; };
}, [editor]); }, [editor]);

View File

@ -16,24 +16,12 @@ import { DocumentVersion } from 'components/document/version';
import { User } from 'components/user'; import { User } from 'components/user';
import { Divider } from 'components/divider'; import { Divider } from 'components/divider';
import { useDocumentStyle } from 'hooks/use-document-style'; import { useDocumentStyle } from 'hooks/use-document-style';
import { EventEmitter } from 'helpers/event-emitter'; import { event, CHANGE_DOCUMENT_TITLE, triggerUseDocumentVersion } from 'event';
import { Editor } from './editor'; import { Editor } from './editor';
import styles from './index.module.scss'; import styles from './index.module.scss';
const { Text } = Typography; const { Text } = Typography;
export const em = new EventEmitter();
const TITLE_CHANGE_EVENT = 'TITLE_CHANGE_EVENT';
export const USE_DATA_VERSION = 'USE_DATA_VERSION';
export const changeTitle = (title) => {
em.emit(TITLE_CHANGE_EVENT, title);
};
const useVersion = (data) => {
em.emit(USE_DATA_VERSION, data);
};
interface IProps { interface IProps {
documentId: string; documentId: string;
} }
@ -77,10 +65,10 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
); );
useEffect(() => { useEffect(() => {
em.on(TITLE_CHANGE_EVENT, setTitle); event.on(CHANGE_DOCUMENT_TITLE, setTitle);
return () => { return () => {
em.destroy(); event.off(CHANGE_DOCUMENT_TITLE, setTitle);
}; };
}, []); }, []);
@ -97,7 +85,7 @@ export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
<DocumentCollaboration key="collaboration" wikiId={document.wikiId} documentId={documentId} /> <DocumentCollaboration key="collaboration" wikiId={document.wikiId} documentId={documentId} />
)} )}
<DocumentShare key="share" documentId={documentId} /> <DocumentShare key="share" documentId={documentId} />
<DocumentVersion key="version" documentId={documentId} onSelect={useVersion} /> <DocumentVersion key="version" documentId={documentId} onSelect={triggerUseDocumentVersion} />
<DocumentStar key="star" documentId={documentId} /> <DocumentStar key="star" documentId={documentId} />
<Popover key="style" zIndex={1061} position="bottomLeft" content={<DocumentStyle />}> <Popover key="style" zIndex={1061} position="bottomLeft" content={<DocumentStyle />}>
<Button icon={<IconArticle />} theme="borderless" type="tertiary" /> <Button icon={<IconArticle />} theme="borderless" type="tertiary" />

View File

@ -14,7 +14,7 @@ import {
} from '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 { triggerJoinUser } from 'event';
import { CreateUser } from './user'; import { CreateUser } from './user';
import styles from './index.module.scss'; import styles from './index.module.scss';
@ -36,7 +36,7 @@ export const Editor: React.FC<IProps> = ({ user, documentId, document }) => {
docType: 'document', docType: 'document',
events: { events: {
onAwarenessUpdate({ states }) { onAwarenessUpdate({ states }) {
joinUser({ states }); triggerJoinUser(states);
}, },
}, },
}); });

View File

@ -1,20 +0,0 @@
import { IDocument, IWiki } from '@think/domains';
import { event } from 'helpers/event-emitter';
export const REFRESH_TOCS = `REFRESH_TOCS`; // 刷新知识库目录
export const CREATE_DOCUMENT = `CREATE_DOCUMENT`;
/**
*
*/
export const triggerRefreshTocs = () => {
event.emit(REFRESH_TOCS);
};
/**
*
* @param data
*/
export const triggerCreateDocument = (data: { wikiId: IWiki['id']; documentId: IDocument['id'] | null }) => {
event.emit(CREATE_DOCUMENT, data);
};

View File

@ -9,8 +9,7 @@ import { Seo } from 'components/seo';
import { findParents } from 'components/wiki/tocs/utils'; import { findParents } from 'components/wiki/tocs/utils';
import { IconDocument, IconSetting, IconOverview, IconGlobe } from 'components/icons'; import { IconDocument, IconSetting, IconOverview, IconGlobe } from 'components/icons';
import { DataRender } from 'components/data-render'; import { DataRender } from 'components/data-render';
import { event } from 'helpers/event-emitter'; import { event, REFRESH_TOCS, triggerCreateDocument } from 'event';
import { REFRESH_TOCS, triggerCreateDocument } from './event';
import { NavItem } from './nav-item'; import { NavItem } from './nav-item';
import { Tree } from './tree'; import { Tree } from './tree';
import styles from './index.module.scss'; import styles from './index.module.scss';

View File

@ -5,8 +5,7 @@ import { IconMore, IconPlus } from '@douyinfe/semi-icons';
import { useToggle } from 'hooks/use-toggle'; import { useToggle } from 'hooks/use-toggle';
import { DocumentActions } from 'components/document/actions'; import { DocumentActions } from 'components/document/actions';
import { DocumentCreator as DocumenCreatorForm } from 'components/document/create'; import { DocumentCreator as DocumenCreatorForm } from 'components/document/create';
import { event } from 'helpers/event-emitter'; import { event, CREATE_DOCUMENT, triggerCreateDocument } from 'event';
import { CREATE_DOCUMENT, triggerCreateDocument } from './event';
import styles from './index.module.scss'; import styles from './index.module.scss';
const Actions = ({ node }) => { const Actions = ({ node }) => {

View File

@ -0,0 +1,51 @@
import { IUser, IDocument, IWiki } from '@think/domains';
import { EventEmitter } from 'helpers/event-emitter';
export const event = new EventEmitter();
export const REFRESH_TOCS = `REFRESH_TOCS`; // 刷新知识库目录
export const CREATE_DOCUMENT = `CREATE_DOCUMENT`;
/**
*
*/
export const triggerRefreshTocs = () => {
event.emit(REFRESH_TOCS);
};
/**
*
* @param data
*/
export const triggerCreateDocument = (data: { wikiId: IWiki['id']; documentId: IDocument['id'] | null }) => {
event.emit(CREATE_DOCUMENT, data);
};
export const CHANGE_DOCUMENT_TITLE = `CHANGE_DOCUMENT_TITLE`;
/**
*
* @param title
*/
export const triggerChangeDocumentTitle = (title: string) => {
event.emit(CHANGE_DOCUMENT_TITLE, title);
};
export const USE_DOCUMENT_VERSION = `USE_DOCUMENT_VERSION`;
/**
* 使
* @param data
*/
export const triggerUseDocumentVersion = (data: Record<string, unknown>) => {
event.emit(USE_DOCUMENT_VERSION, data);
};
export const JOIN_USER = `JOIN_USER`;
type CollaborationUser = {
clientId: number;
user: IUser;
};
/**
*
* @param users
*/
export const triggerJoinUser = (users: Array<CollaborationUser>) => {
event.emit(JOIN_USER, users);
};

View File

@ -39,5 +39,3 @@ export class EventEmitter {
this.callbacks = {}; this.callbacks = {};
} }
} }
export const event = new EventEmitter();

View File

@ -26,7 +26,8 @@
"layout/*": ["layout/*"], "layout/*": ["layout/*"],
"constants/*": ["constants/*"], "constants/*": ["constants/*"],
"helpers/*": ["helpers/*"], "helpers/*": ["helpers/*"],
"tiptap/*": ["tiptap/*"] "tiptap/*": ["tiptap/*"],
"event/*": ["event/*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],