mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-26 14:58:55 +08:00
refactor(component): render react element into lit (#6124)
See docs in https://insider.affine.pro/share/af3478a2-9c9c-4d16-864d-bffa1eb10eb6/oL1ifjA4rKv7HRn5nYzIF This PR also enables opening split view by ctrl-click a page link in a doc.
This commit is contained in:
@@ -4,12 +4,13 @@ import { WorkbenchLink } from '@affine/core/modules/workbench';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { LinkedPageIcon, TodayIcon } from '@blocksuite/icons';
|
||||
import type { DocCollection } from '@blocksuite/store';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { type PropsWithChildren } from 'react';
|
||||
|
||||
import * as styles from './styles.css';
|
||||
|
||||
export interface PageReferenceRendererOptions {
|
||||
pageId: string;
|
||||
docCollection: DocCollection;
|
||||
pageMetaHelper: ReturnType<typeof useDocMetaHelper>;
|
||||
journalHelper: ReturnType<typeof useJournalHelper>;
|
||||
t: ReturnType<typeof useAFFiNEI18N>;
|
||||
@@ -32,6 +33,7 @@ export function pageReferenceRenderer({
|
||||
title = localizedJournalDate;
|
||||
icon = <TodayIcon className={styles.pageReferenceIcon} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{icon}
|
||||
@@ -58,6 +60,7 @@ export function AffinePageReference({
|
||||
pageId,
|
||||
pageMetaHelper,
|
||||
journalHelper,
|
||||
docCollection,
|
||||
t,
|
||||
});
|
||||
|
||||
|
||||
+6
-7
@@ -18,7 +18,7 @@ import {
|
||||
} from 'react';
|
||||
|
||||
import {
|
||||
pageReferenceRenderer,
|
||||
AffinePageReference,
|
||||
type PageReferenceRendererOptions,
|
||||
} from '../../affine/reference-link';
|
||||
import { BlocksuiteEditorContainer } from './blocksuite-editor-container';
|
||||
@@ -61,7 +61,6 @@ function usePageRoot(page: Doc) {
|
||||
return page.root;
|
||||
}
|
||||
|
||||
// we cannot pass components to lit renderers, but give them the rendered elements
|
||||
const customRenderersFactory: (
|
||||
opts: Omit<PageReferenceRendererOptions, 'pageId'>
|
||||
) => InlineRenderers = opts => ({
|
||||
@@ -70,10 +69,9 @@ const customRenderersFactory: (
|
||||
if (!pageId) {
|
||||
return <span />;
|
||||
}
|
||||
return pageReferenceRenderer({
|
||||
...opts,
|
||||
pageId,
|
||||
});
|
||||
return (
|
||||
<AffinePageReference docCollection={opts.docCollection} pageId={pageId} />
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -119,8 +117,9 @@ const BlockSuiteEditorImpl = forwardRef<AffineEditorContainer, EditorProps>(
|
||||
pageMetaHelper,
|
||||
journalHelper,
|
||||
t,
|
||||
docCollection: page.collection,
|
||||
});
|
||||
}, [journalHelper, pageMetaHelper, t]);
|
||||
}, [journalHelper, page.collection, pageMetaHelper, t]);
|
||||
|
||||
return (
|
||||
<BlocksuiteEditorContainer
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { createReactComponentFromLit } from '@affine/component';
|
||||
import {
|
||||
createReactComponentFromLit,
|
||||
useLitPortalFactory,
|
||||
} from '@affine/component';
|
||||
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
|
||||
import {
|
||||
BiDirectionalLinkPanel,
|
||||
@@ -10,6 +13,7 @@ import {
|
||||
import { type Doc } from '@blocksuite/store';
|
||||
import React, {
|
||||
forwardRef,
|
||||
Fragment,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
@@ -80,9 +84,11 @@ export const BlocksuiteDocEditor = forwardRef<
|
||||
[ref]
|
||||
);
|
||||
|
||||
const [litToTemplate, portals] = useLitPortalFactory();
|
||||
|
||||
const specs = useMemo(() => {
|
||||
return patchSpecs(docModeSpecs, customRenderers);
|
||||
}, [customRenderers]);
|
||||
return patchSpecs(docModeSpecs, litToTemplate, customRenderers);
|
||||
}, [customRenderers, litToTemplate]);
|
||||
|
||||
useEffect(() => {
|
||||
// auto focus the title
|
||||
@@ -128,6 +134,9 @@ export const BlocksuiteDocEditor = forwardRef<
|
||||
<adapted.BiDirectionalLinkPanel doc={page} pageRoot={docPage} />
|
||||
) : null}
|
||||
</div>
|
||||
{portals.map(p => (
|
||||
<Fragment key={p.id}>{p.portal}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -136,8 +145,16 @@ export const BlocksuiteEdgelessEditor = forwardRef<
|
||||
EdgelessEditor,
|
||||
BlocksuiteDocEditorProps
|
||||
>(function BlocksuiteEdgelessEditor({ page, customRenderers }, ref) {
|
||||
const [litToTemplate, portals] = useLitPortalFactory();
|
||||
const specs = useMemo(() => {
|
||||
return patchSpecs(edgelessModeSpecs, customRenderers);
|
||||
}, [customRenderers]);
|
||||
return <adapted.EdgelessEditor ref={ref} doc={page} specs={specs} />;
|
||||
return patchSpecs(edgelessModeSpecs, litToTemplate, customRenderers);
|
||||
}, [customRenderers, litToTemplate]);
|
||||
return (
|
||||
<>
|
||||
<adapted.EdgelessEditor ref={ref} doc={page} specs={specs} />
|
||||
{portals.map(p => (
|
||||
<Fragment key={p.id}>{p.portal}</Fragment>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { ElementOrFactory } from '@affine/component';
|
||||
import type { BlockSpec } from '@blocksuite/block-std';
|
||||
import type { ParagraphService, RootService } from '@blocksuite/blocks';
|
||||
import {
|
||||
@@ -9,8 +10,7 @@ import {
|
||||
PageRootService,
|
||||
} from '@blocksuite/blocks';
|
||||
import bytes from 'bytes';
|
||||
import { html, unsafeStatic } from 'lit/static-html.js';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import type { TemplateResult } from 'lit';
|
||||
|
||||
class CustomAttachmentService extends AttachmentService {
|
||||
override mounted(): void {
|
||||
@@ -53,12 +53,12 @@ export interface InlineRenderers {
|
||||
|
||||
function patchSpecsWithReferenceRenderer(
|
||||
specs: BlockSpec<string>[],
|
||||
pageReferenceRenderer: PageReferenceRenderer
|
||||
pageReferenceRenderer: PageReferenceRenderer,
|
||||
toLitTemplate: (element: ElementOrFactory) => TemplateResult
|
||||
) {
|
||||
const renderer = (reference: AffineReference) => {
|
||||
const node = pageReferenceRenderer(reference);
|
||||
const inner = ReactDOMServer.renderToString(node);
|
||||
return html`${unsafeStatic(inner)}`;
|
||||
return toLitTemplate(node);
|
||||
};
|
||||
return specs.map(spec => {
|
||||
if (
|
||||
@@ -84,13 +84,15 @@ function patchSpecsWithReferenceRenderer(
|
||||
*/
|
||||
export function patchSpecs(
|
||||
specs: BlockSpec<string>[],
|
||||
toLitTemplate: (element: ElementOrFactory) => TemplateResult,
|
||||
inlineRenderers?: InlineRenderers
|
||||
) {
|
||||
let newSpecs = specs;
|
||||
if (inlineRenderers?.pageReference) {
|
||||
newSpecs = patchSpecsWithReferenceRenderer(
|
||||
newSpecs,
|
||||
inlineRenderers.pageReference
|
||||
inlineRenderers.pageReference,
|
||||
toLitTemplate
|
||||
);
|
||||
}
|
||||
return newSpecs;
|
||||
|
||||
Reference in New Issue
Block a user