mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
131 lines
3.6 KiB
TypeScript
131 lines
3.6 KiB
TypeScript
import type { BlockHub } from '@blocksuite/blocks';
|
|
import { EditorContainer } from '@blocksuite/editor';
|
|
import { assertExists } from '@blocksuite/global/utils';
|
|
import type { Page } from '@blocksuite/store';
|
|
import type { CSSProperties, ReactElement } from 'react';
|
|
import { memo, useCallback, useEffect, useRef } from 'react';
|
|
import type { FallbackProps } from 'react-error-boundary';
|
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
|
|
export type EditorProps = {
|
|
page: Page;
|
|
mode: 'page' | 'edgeless';
|
|
onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
|
|
onLoad?: (page: Page, editor: EditorContainer) => void;
|
|
style?: CSSProperties;
|
|
};
|
|
|
|
export type ErrorBoundaryProps = {
|
|
onReset?: () => void;
|
|
};
|
|
|
|
declare global {
|
|
// eslint-disable-next-line no-var
|
|
var currentPage: Page | undefined;
|
|
// eslint-disable-next-line no-var
|
|
var currentEditor: EditorContainer | undefined;
|
|
}
|
|
|
|
const BlockSuiteEditorImpl = (props: EditorProps): ReactElement => {
|
|
const page = props.page;
|
|
assertExists(page, 'page should not be null');
|
|
const editorRef = useRef<EditorContainer | null>(null);
|
|
const blockHubRef = useRef<BlockHub | null>(null);
|
|
if (editorRef.current === null) {
|
|
editorRef.current = new EditorContainer();
|
|
editorRef.current.autofocus = true;
|
|
globalThis.currentEditor = editorRef.current;
|
|
}
|
|
const editor = editorRef.current;
|
|
assertExists(editorRef, 'editorRef.current should not be null');
|
|
if (editor.mode !== props.mode) {
|
|
editor.mode = props.mode;
|
|
}
|
|
if (editor.page !== props.page) {
|
|
editor.page = props.page;
|
|
if (page.root === null) {
|
|
props.onInit(page, editor);
|
|
}
|
|
props.onLoad?.(page, editor);
|
|
}
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const editor = editorRef.current;
|
|
assertExists(editor);
|
|
const container = ref.current;
|
|
if (!container) {
|
|
return;
|
|
}
|
|
if (page.awarenessStore.getFlag('enable_block_hub')) {
|
|
editor.createBlockHub().then(blockHub => {
|
|
if (blockHubRef.current) {
|
|
blockHubRef.current.remove();
|
|
}
|
|
blockHubRef.current = blockHub;
|
|
const toolWrapper = document.querySelector('#toolWrapper');
|
|
if (!toolWrapper) {
|
|
console.warn(
|
|
'toolWrapper not found, block hub feature will not be available.'
|
|
);
|
|
} else {
|
|
toolWrapper.appendChild(blockHub);
|
|
}
|
|
});
|
|
}
|
|
|
|
container.appendChild(editor);
|
|
return () => {
|
|
blockHubRef.current?.remove();
|
|
container.removeChild(editor);
|
|
};
|
|
}, [page]);
|
|
return (
|
|
<div
|
|
data-testid={`editor-${props.page.id}`}
|
|
className="editor-wrapper"
|
|
style={props.style}
|
|
ref={ref}
|
|
/>
|
|
);
|
|
};
|
|
|
|
const BlockSuiteErrorFallback = (
|
|
props: FallbackProps & ErrorBoundaryProps
|
|
): ReactElement => {
|
|
return (
|
|
<div>
|
|
<h1>Sorry.. there was an error</h1>
|
|
<div>{props.error.message}</div>
|
|
<button
|
|
data-testid="error-fallback-reset-button"
|
|
onClick={() => {
|
|
props.onReset?.();
|
|
props.resetErrorBoundary();
|
|
}}
|
|
>
|
|
Try again
|
|
</button>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const BlockSuiteEditor = memo(function BlockSuiteEditor(
|
|
props: EditorProps & ErrorBoundaryProps
|
|
): ReactElement {
|
|
return (
|
|
<ErrorBoundary
|
|
fallbackRender={useCallback(
|
|
(fallbackProps: FallbackProps) => (
|
|
<BlockSuiteErrorFallback {...fallbackProps} onReset={props.onReset} />
|
|
),
|
|
[props.onReset]
|
|
)}
|
|
>
|
|
<BlockSuiteEditorImpl {...props} />
|
|
</ErrorBoundary>
|
|
);
|
|
});
|
|
|
|
BlockSuiteEditor.displayName = 'BlockSuiteEditor';
|