feat: add lifecycle hook in editor provider

This commit is contained in:
QiShaoXuan
2022-12-14 16:47:33 +08:00
parent 7734fe8928
commit 9253e9af0b
13 changed files with 155 additions and 61 deletions
@@ -4,29 +4,28 @@ import type { PropsWithChildren } from 'react';
import dynamic from 'next/dynamic';
import Loading from './loading';
import { Page, Workspace } from '@blocksuite/store';
import useEditorHandler from './useEditorHandler';
import { EditorHandlers, PageMeta } from './interface';
import useEditorHandler from './hooks/useEditorHandler';
import {
EditorHandlers,
PageMeta,
EditorContextValue,
EditorContextProps,
} from './interface';
import usePropsUpdated from '@/providers/editor-provider/hooks/usePropsUpdated';
import useHistoryUpdated from '@/providers/editor-provider/hooks/useHistoryUpdated';
// Blocksuite has to be imported dynamically since it has a lot of effects
const DynamicEditor = dynamic(() => import('./editor-reactor'), {
ssr: false,
});
type EditorContextValue = {
mode: EditorContainer['mode'];
setMode: (mode: EditorContainer['mode']) => void;
currentPage: Page | void;
editor: EditorContainer | void;
pageList: PageMeta[];
} & EditorHandlers;
type EditorContextProps = PropsWithChildren<{}>;
export const EditorContext = createContext<EditorContextValue>({
mode: 'page',
setMode: () => {},
pageList: [],
currentPage: undefined,
page: undefined,
onPropsUpdated: () => {},
onHistoryUpdated: () => {},
editor: undefined,
...({} as EditorHandlers),
});
@@ -37,12 +36,24 @@ export const EditorProvider = ({
children,
}: PropsWithChildren<EditorContextProps>) => {
const [workspace, setWorkspace] = useState<Workspace>();
const [currentPage, setCurrentPage] = useState<Page>();
const [page, setPage] = useState<Page>();
const [pageList, setPageList] = useState<PageMeta[]>([]);
const [editor, setEditor] = useState<EditorContainer>();
const [mode, setMode] = useState<EditorContainer['mode']>('page');
const editorHandlers = useEditorHandler(workspace);
const onPropsUpdated = usePropsUpdated(editor);
const onHistoryUpdated = useHistoryUpdated(page);
// Modify the updatedDate when history change
useEffect(() => {
if (!workspace) {
return;
}
onHistoryUpdated(page => {
workspace.setPageMeta(page.id, { updatedDate: +new Date() });
});
}, [workspace, onHistoryUpdated]);
useEffect(() => {
const event = new CustomEvent('affine.switch-mode', { detail: mode });
@@ -67,21 +78,23 @@ export const EditorProvider = ({
<EditorContext.Provider
value={{
editor,
currentPage,
page,
mode,
setMode,
pageList,
onHistoryUpdated,
onPropsUpdated,
...editorHandlers,
}}
>
<DynamicEditor
workspace={workspace}
currentPage={currentPage}
currentPage={page}
setEditor={setEditor}
setWorkspace={setWorkspace}
setCurrentPage={setCurrentPage}
setCurrentPage={setPage}
/>
{workspace && currentPage && editor ? children : <Loading />}
{workspace && page && editor ? children : <Loading />}
</EditorContext.Provider>
);
};
@@ -89,7 +89,7 @@ const EditorReactor = ({
const savedPageId = workspace.meta.pageMetas[0]?.id;
if (savedPageId) {
setCurrentPage(workspace.getPage(savedPageId));
setCurrentPage(workspace.getPage(savedPageId) as Page);
return;
}
@@ -1,8 +1,8 @@
import { QueryContent } from '@blocksuite/store/dist/workspace/search';
import { createPage, initialPage, generateDefaultPageId } from './utils';
import { createPage, initialPage, generateDefaultPageId } from '../utils';
import { Workspace } from '@blocksuite/store';
import { useRouter } from 'next/router';
import { EditorHandlers } from './interface';
import { EditorHandlers, PageMeta } from '../interface';
export const useEditorHandler = (workspace?: Workspace): EditorHandlers => {
const router = useRouter();
@@ -15,7 +15,9 @@ export const useEditorHandler = (workspace?: Workspace): EditorHandlers => {
},
getPageMeta(pageId: string) {
pageId = pageId.replace('space:', '');
return workspace!.meta.pageMetas.find(page => page.id === pageId);
return workspace!.meta.pageMetas.find(
page => page.id === pageId
) as PageMeta;
},
openPage: (pageId, query = {}) => {
return router.push({
@@ -29,8 +31,10 @@ export const useEditorHandler = (workspace?: Workspace): EditorHandlers => {
toggleDeletePage: pageId => {
const pageMeta = workspace!.meta.pageMetas.find(p => p.id === pageId);
if (pageMeta) {
workspace!.meta.setPage(pageId, { trashDate: new Date().getTime() });
workspace!.setPageMeta(pageId, { trash: !pageMeta.trash });
workspace!.setPageMeta(pageId, {
trash: !pageMeta.trash,
trashDate: +new Date(),
});
}
},
favoritePage: pageId => {
@@ -0,0 +1,34 @@
import { useEffect, useRef } from 'react';
import { Page } from '@blocksuite/store';
import { EventCallBack } from '../interface';
export type UseHistoryUpdated = (page?: Page) => EventCallBack<Page>;
export const useHistoryUpdate: UseHistoryUpdated = page => {
const callbackQueue = useRef<((page: Page) => void)[]>([]);
useEffect(() => {
if (!page) {
return;
}
setTimeout(() => {
page.signals.historyUpdated.on(() => {
callbackQueue.current.forEach(callback => {
callback(page);
});
});
}, 300);
return () => {
callbackQueue.current = [];
page.signals.historyUpdated.dispose();
};
}, [page]);
return callback => {
callbackQueue.current.push(callback);
};
};
export default useHistoryUpdate;
@@ -0,0 +1,36 @@
import { useEffect, useRef } from 'react';
import { EditorContainer } from '@blocksuite/editor';
import { EventCallBack } from '../interface';
export type UsePropsUpdated = (
editor?: EditorContainer
) => EventCallBack<EditorContainer>;
export const usePropsUpdated: UsePropsUpdated = editor => {
const callbackQueue = useRef<((editor: EditorContainer) => void)[]>([]);
useEffect(() => {
if (!editor?.model) {
return;
}
setTimeout(() => {
editor.model?.propsUpdated.on(() => {
callbackQueue.current.forEach(callback => {
callback(editor);
});
});
}, 300);
return () => {
callbackQueue.current = [];
editor?.model?.propsUpdated.dispose();
};
}, [editor]);
return callback => {
callbackQueue.current.push(callback);
};
};
export default usePropsUpdated;
@@ -1,14 +1,28 @@
import { PropsWithChildren } from 'react';
import { Page } from '@blocksuite/store';
import { QueryContent } from '@blocksuite/store/dist/workspace/search';
import { PageMeta as OriginalPageMeta } from '@blocksuite/store';
import { EditorContainer } from '@blocksuite/editor';
export interface PageMeta {
id: string;
title: string;
export type EventCallBack<T> = (callback: (props: T) => void) => void;
export type EditorContextProps = PropsWithChildren<{}>;
export type EditorContextValue = {
mode: EditorContainer['mode'];
setMode: (mode: EditorContainer['mode']) => void;
page: Page | void;
editor: EditorContainer | void;
pageList: PageMeta[];
onHistoryUpdated: EventCallBack<Page>;
onPropsUpdated: EventCallBack<EditorContainer>;
} & EditorHandlers;
export type PageMeta = {
favorite: boolean;
trash: boolean;
createDate: number;
trashDate: number | null;
}
trashDate: number | void;
updatedDate: number | void;
} & OriginalPageMeta;
export type EditorHandlers = {
createPage: (pageId?: string) => Promise<Page>;