mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 02:42:25 +08:00
refactor: block-hub in tool wrapper (#3073)
(cherry picked from commit fafd93f7dc)
This commit is contained in:
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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]
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
25
packages/component/src/components/block-hub/index.tsx
Normal file
25
packages/component/src/components/block-hub/index.tsx
Normal 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" />;
|
||||||
|
};
|
||||||
@@ -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 ${
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user