refactor: block-hub in tool wrapper (#3073)

(cherry picked from commit fafd93f7dc)
This commit is contained in:
Alex Yang
2023-07-06 23:18:58 +08:00
parent 424580971e
commit 44dbe39001
8 changed files with 58 additions and 39 deletions

View File

@@ -1,6 +1,8 @@
/* deepscan-disable USELESS_ARROW_FUNC_BIND */ /* deepscan-disable USELESS_ARROW_FUNC_BIND */
import { BlockHubWrapper } from '@affine/component/block-hub';
import type { EditorProps } from '@affine/component/block-suite-editor'; import type { EditorProps } from '@affine/component/block-suite-editor';
import { BlockSuiteEditor } from '@affine/component/block-suite-editor'; import { BlockSuiteEditor } from '@affine/component/block-suite-editor';
import { rootBlockHubAtom } from '@affine/workspace/atom';
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models'; import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
import type { EditorContainer } from '@blocksuite/editor'; import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
@@ -54,13 +56,13 @@ const Template: StoryFn<EditorProps> = (props: Partial<EditorProps>) => {
}} }}
> >
<BlockSuiteEditor onInit={initPage} page={page} mode="page" {...props} /> <BlockSuiteEditor onInit={initPage} page={page} mode="page" {...props} />
<div <BlockHubWrapper
style={{ style={{
position: 'absolute', position: 'absolute',
right: 12, right: 12,
bottom: 12, bottom: 12,
}} }}
id="toolWrapper" blockHubAtom={rootBlockHubAtom}
/> />
</div> </div>
); );

View File

@@ -1,7 +1,9 @@
import { BlockHubWrapper } from '@affine/component/block-hub';
import { BlockSuiteEditor } from '@affine/component/block-suite-editor'; import { BlockSuiteEditor } from '@affine/component/block-suite-editor';
import { ImagePreviewModal } from '@affine/component/image-preview-modal'; import { ImagePreviewModal } from '@affine/component/image-preview-modal';
import { initEmptyPage } from '@affine/env/blocksuite'; import { initEmptyPage } from '@affine/env/blocksuite';
import { WorkspaceFlavour } from '@affine/env/workspace'; import { WorkspaceFlavour } from '@affine/env/workspace';
import { rootBlockHubAtom } from '@affine/workspace/atom';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils'; import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import type { Meta } from '@storybook/react'; import type { Meta } from '@storybook/react';
@@ -54,13 +56,13 @@ export const Default = () => {
> >
<BlockSuiteEditor mode="page" page={page} onInit={initEmptyPage} /> <BlockSuiteEditor mode="page" page={page} onInit={initEmptyPage} />
</div> </div>
<div <BlockHubWrapper
style={{ style={{
position: 'absolute', position: 'absolute',
right: 12, right: 12,
bottom: 12, bottom: 12,
}} }}
id="toolWrapper" blockHubAtom={rootBlockHubAtom}
/> />
</> </>
); );

View File

@@ -4,7 +4,7 @@ import {
DEFAULT_HELLO_WORLD_PAGE_ID, DEFAULT_HELLO_WORLD_PAGE_ID,
PageNotFoundError, PageNotFoundError,
} from '@affine/env/constant'; } from '@affine/env/constant';
import { rootCurrentEditorAtom } from '@affine/workspace/atom'; import { rootBlockHubAtom } from '@affine/workspace/atom';
import type { EditorContainer } from '@blocksuite/editor'; import type { EditorContainer } from '@blocksuite/editor';
import { assertExists } from '@blocksuite/global/utils'; import { assertExists } from '@blocksuite/global/utils';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
@@ -22,13 +22,7 @@ import clsx from 'clsx';
import { useAtomValue, useSetAtom } from 'jotai'; import { useAtomValue, useSetAtom } from 'jotai';
import Head from 'next/head'; import Head from 'next/head';
import type { FC, ReactElement } from 'react'; import type { FC, ReactElement } from 'react';
import React, { import React, { memo, Suspense, useCallback, useMemo } from 'react';
memo,
startTransition,
Suspense,
useCallback,
useMemo,
} from 'react';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import { pageSettingFamily } from '../atoms'; import { pageSettingFamily } from '../atoms';
@@ -73,7 +67,7 @@ const EditorWrapper = memo(function EditorWrapper({
pageSetting?.mode ?? pageSetting?.mode ??
(DEFAULT_HELLO_WORLD_PAGE_ID === pageId ? 'edgeless' : 'page'); (DEFAULT_HELLO_WORLD_PAGE_ID === pageId ? 'edgeless' : 'page');
const setEditor = useSetAtom(rootCurrentEditorAtom); const setBlockHub = useSetAtom(rootBlockHubAtom);
const [appSettings] = useAppSetting(); const [appSettings] = useAppSetting();
assertExists(meta); assertExists(meta);
@@ -88,18 +82,13 @@ const EditorWrapper = memo(function EditorWrapper({
page={page} page={page}
onInit={useCallback( onInit={useCallback(
(page: Page, editor: Readonly<EditorContainer>) => { (page: Page, editor: Readonly<EditorContainer>) => {
startTransition(() => {
setEditor(editor);
});
onInit(page, editor); onInit(page, editor);
}, },
[onInit, setEditor] [onInit]
)} )}
setBlockHub={setBlockHub}
onLoad={useCallback( onLoad={useCallback(
(page: Page, editor: EditorContainer) => { (page: Page, editor: EditorContainer) => {
startTransition(() => {
setEditor(editor);
});
page.workspace.setPageMeta(page.id, { page.workspace.setPageMeta(page.id, {
updatedDate: Date.now(), updatedDate: Date.now(),
}); });
@@ -119,7 +108,7 @@ const EditorWrapper = memo(function EditorWrapper({
dispose(); dispose();
}; };
}, },
[plugins, onLoad, setEditor] [plugins, onLoad]
)} )}
/> />
); );

View File

@@ -1,6 +1,7 @@
import { Content, displayFlex } from '@affine/component'; import { Content, displayFlex } from '@affine/component';
import { AffineWatermark } from '@affine/component/affine-watermark'; import { AffineWatermark } from '@affine/component/affine-watermark';
import { appSidebarResizingAtom } from '@affine/component/app-sidebar'; import { appSidebarResizingAtom } from '@affine/component/app-sidebar';
import { BlockHubWrapper } from '@affine/component/block-hub';
import { NotificationCenter } from '@affine/component/notification-center'; import { NotificationCenter } from '@affine/component/notification-center';
import type { DraggableTitleCellData } from '@affine/component/page-list'; import type { DraggableTitleCellData } from '@affine/component/page-list';
import { StyledTitleLink } from '@affine/component/page-list'; import { StyledTitleLink } from '@affine/component/page-list';
@@ -13,6 +14,7 @@ import { initEmptyPage, initPageWithPreloading } from '@affine/env/blocksuite';
import { DEFAULT_HELLO_WORLD_PAGE_ID, isDesktop } from '@affine/env/constant'; import { DEFAULT_HELLO_WORLD_PAGE_ID, isDesktop } from '@affine/env/constant';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { import {
rootBlockHubAtom,
rootCurrentPageIdAtom, rootCurrentPageIdAtom,
rootCurrentWorkspaceIdAtom, rootCurrentWorkspaceIdAtom,
rootWorkspacesMetadataAtom, rootWorkspacesMetadataAtom,
@@ -432,10 +434,7 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
<MainContainer> <MainContainer>
{children} {children}
<ToolContainer> <ToolContainer>
{/* fixme(himself65): remove this */} <BlockHubWrapper blockHubAtom={rootBlockHubAtom} />
<div id="toolWrapper" style={{ marginBottom: '12px' }}>
{/* Slot for block hub */}
</div>
{!isPublicWorkspace && ( {!isPublicWorkspace && (
<HelpIsland <HelpIsland
showList={router.query.pageId ? undefined : showList} showList={router.query.pageId ? undefined : showList}

View File

@@ -1,4 +1,6 @@
import { BlockHubWrapper } from '@affine/component/block-hub';
import { MainContainer } from '@affine/component/workspace'; import { MainContainer } from '@affine/component/workspace';
import { rootBlockHubAtom } from '@affine/workspace/atom';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { lazy, Suspense } from 'react'; import { lazy, Suspense } from 'react';
@@ -23,7 +25,7 @@ const InitPagePage: NextPageWithLayout = () => {
<Suspense> <Suspense>
<Editor /> <Editor />
</Suspense> </Suspense>
<div id="toolWrapper" /> <BlockHubWrapper blockHubAtom={rootBlockHubAtom} />
</MainContainer> </MainContainer>
</AppContainer> </AppContainer>
); );

View File

@@ -0,0 +1,25 @@
import type { BlockHub } from '@blocksuite/blocks';
import type { Atom } from 'jotai';
import { useAtomValue } from 'jotai';
import type { HTMLAttributes, ReactElement } from 'react';
import { useRef } from 'react';
export interface BlockHubProps extends HTMLAttributes<HTMLDivElement> {
blockHubAtom: Atom<Readonly<BlockHub> | null>;
}
export const BlockHubWrapper = (props: BlockHubProps): ReactElement => {
const blockHub = useAtomValue(props.blockHubAtom);
const ref = useRef<HTMLDivElement>(null);
if (ref.current) {
const div = ref.current;
if (!blockHub) {
if (div.hasChildNodes()) {
div.removeChild(div.firstChild as ChildNode);
}
} else {
div.appendChild(blockHub);
}
}
return <div ref={ref} data-testid="block-hub" />;
};

View File

@@ -28,6 +28,7 @@ export type EditorProps = {
page: Page; page: Page;
mode: 'page' | 'edgeless'; mode: 'page' | 'edgeless';
onInit: (page: Page, editor: Readonly<EditorContainer>) => void; onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
setBlockHub?: (blockHub: BlockHub | null) => void;
onLoad?: (page: Page, editor: EditorContainer) => () => void; onLoad?: (page: Page, editor: EditorContainer) => () => void;
style?: CSSProperties; style?: CSSProperties;
className?: string; className?: string;
@@ -96,6 +97,8 @@ const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
const ref = useRef<HTMLDivElement>(null); const ref = useRef<HTMLDivElement>(null);
const setBlockHub = props.setBlockHub;
useEffect(() => { useEffect(() => {
const editor = editorRef.current; const editor = editorRef.current;
assertExists(editor); assertExists(editor);
@@ -111,13 +114,8 @@ const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
blockHubRef.current.remove(); blockHubRef.current.remove();
} }
blockHubRef.current = blockHub; blockHubRef.current = blockHub;
const toolWrapper = document.querySelector('#toolWrapper'); if (setBlockHub) {
if (!toolWrapper) { setBlockHub(blockHub);
console.warn(
'toolWrapper not found, block hub feature will not be available.'
);
} else {
toolWrapper.appendChild(blockHub);
} }
}) })
.catch(err => { .catch(err => {
@@ -127,10 +125,13 @@ const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
container.appendChild(editor); container.appendChild(editor);
return () => { return () => {
if (setBlockHub) {
setBlockHub(null);
}
blockHubRef.current?.remove(); blockHubRef.current?.remove();
container.removeChild(editor); container.removeChild(editor);
}; };
}, [editor, page]); }, [editor, setBlockHub, page]);
// issue: https://github.com/toeverything/AFFiNE/issues/2004 // issue: https://github.com/toeverything/AFFiNE/issues/2004
const className = `editor-wrapper ${editor.mode}-mode ${ const className = `editor-wrapper ${editor.mode}-mode ${

View File

@@ -1,6 +1,6 @@
import type { WorkspaceAdapter } from '@affine/env/workspace'; import type { WorkspaceAdapter } from '@affine/env/workspace';
import { WorkspaceFlavour, WorkspaceVersion } from '@affine/env/workspace'; import { WorkspaceFlavour, WorkspaceVersion } from '@affine/env/workspace';
import type { EditorContainer } from '@blocksuite/editor'; import type { BlockHub } from '@blocksuite/blocks';
import { assertExists } from '@blocksuite/global/utils'; import { assertExists } from '@blocksuite/global/utils';
import { atom } from 'jotai'; import { atom } from 'jotai';
import Router from 'next/router'; import Router from 'next/router';
@@ -264,8 +264,7 @@ rootCurrentPageIdAtom.onMount = set => {
return; return;
}; };
// current editor atom, each app should have only one editor in the same time // blocksuite atoms,
export const rootCurrentEditorAtom = atom<Readonly<EditorContainer> | null>( // each app should have only one block-hub in the same time
null export const rootBlockHubAtom = atom<Readonly<BlockHub> | null>(null);
);
//#endregion //#endregion