From 5ac15f12e678ed40c0e379c1d22a34142494fda0 Mon Sep 17 00:00:00 2001 From: Saul-Mirone Date: Thu, 20 Feb 2025 14:20:32 +0000 Subject: [PATCH] refactor: replace editor container with editor host (#10328) ### TL;DR Refactored editor access to use `EditorHost` instead of `AffineEditorContainer` and updated mode access through `DocModeProvider`. ### What changed? - Changed editor property types from `AffineEditorContainer` to `EditorHost` across multiple components - Updated mode access to use `DocModeProvider` service instead of direct editor mode access - Modified editor references to use `editor.host` where appropriate - Updated scroll and highlight utilities to work with `EditorHost` ### How to test? 1. Open a document in both page and edgeless modes 2. Verify outline panel functionality works as expected 3. Test outline viewer navigation and highlighting 4. Confirm mobile outline menu operates correctly 5. Check that frame panel and TOC features work in all modes ### Why make this change? This change improves architectural consistency by using `EditorHost` directly and accessing mode through the proper service provider. This makes the code more maintainable and follows better dependency practices by using the correct abstraction levels. --- .../components/custom-outline-panel.ts | 2 +- .../components/custom-outline-viewer.ts | 2 +- .../outline/body/outline-panel-body.ts | 5 ++- .../presets/src/fragments/outline/config.ts | 5 +-- .../fragments/outline/mobile-outline-panel.ts | 15 +++++--- .../src/fragments/outline/outline-panel.ts | 18 ++++++--- .../src/fragments/outline/outline-viewer.ts | 15 +++++--- .../src/fragments/outline/utils/scroll.ts | 37 +++++++++---------- .../blocksuite/outline-viewer/index.tsx | 4 +- .../workspace/detail-page/detail-page.tsx | 6 +-- .../workspace/detail-page/tabs/frame.tsx | 20 ++++------ .../workspace/detail-page/tabs/outline.tsx | 4 +- .../pages/workspace/share/share-page.tsx | 2 +- .../src/mobile/components/toc-menu/index.tsx | 12 ++---- .../detail/page-header-more-button.tsx | 2 +- .../view/doc-preview/doc-peek-view.tsx | 2 +- 16 files changed, 80 insertions(+), 71 deletions(-) diff --git a/blocksuite/playground/apps/_common/components/custom-outline-panel.ts b/blocksuite/playground/apps/_common/components/custom-outline-panel.ts index c412913f3..9fc85e13d 100644 --- a/blocksuite/playground/apps/_common/components/custom-outline-panel.ts +++ b/blocksuite/playground/apps/_common/components/custom-outline-panel.ts @@ -22,7 +22,7 @@ export class CustomOutlinePanel extends WithDisposable(ShadowlessElement) { private _renderPanel() { return html``; } diff --git a/blocksuite/playground/apps/_common/components/custom-outline-viewer.ts b/blocksuite/playground/apps/_common/components/custom-outline-viewer.ts index 5ced1b25d..555b2e31a 100644 --- a/blocksuite/playground/apps/_common/components/custom-outline-viewer.ts +++ b/blocksuite/playground/apps/_common/components/custom-outline-viewer.ts @@ -17,7 +17,7 @@ export class CustomOutlineViewer extends WithDisposable(LitElement) { private _renderViewer() { return html``; } diff --git a/blocksuite/presets/src/fragments/outline/body/outline-panel-body.ts b/blocksuite/presets/src/fragments/outline/body/outline-panel-body.ts index 21cbdafb9..ff73429c2 100644 --- a/blocksuite/presets/src/fragments/outline/body/outline-panel-body.ts +++ b/blocksuite/presets/src/fragments/outline/body/outline-panel-body.ts @@ -2,6 +2,7 @@ import { effects } from '@blocksuite/affine-block-note/effects'; import { ShadowlessElement, SurfaceSelection } from '@blocksuite/block-std'; import { changeNoteDisplayMode, + DocModeProvider, matchModels, NoteBlockModel, NoteDisplayMode, @@ -224,7 +225,9 @@ export class OutlinePanelBody extends SignalWatcher( private _watchSelectedNotes() { return effect(() => { - const { std, doc, mode } = this.editor; + const { std, doc } = this.editor; + const docModeService = this.editor.std.get(DocModeProvider); + const mode = docModeService.getEditorMode(); if (mode !== 'edgeless') return; const currSelectedNotes = std.selection diff --git a/blocksuite/presets/src/fragments/outline/config.ts b/blocksuite/presets/src/fragments/outline/config.ts index b5a4e6d8f..cca821d0c 100644 --- a/blocksuite/presets/src/fragments/outline/config.ts +++ b/blocksuite/presets/src/fragments/outline/config.ts @@ -1,3 +1,4 @@ +import type { EditorHost } from '@blocksuite/block-std'; import type { ParagraphBlockModel, Signal } from '@blocksuite/blocks'; import { AttachmentIcon, @@ -22,8 +23,6 @@ import { import { createContext } from '@lit/context'; import type { TemplateResult } from 'lit'; -import type { AffineEditorContainer } from '../../editors/editor-container.js'; - const _16px = { width: '16px', height: '16px' }; const paragraphIconMap: Record< @@ -85,7 +84,7 @@ export const headingKeys = new Set( export const outlineSettingsKey = 'outlinePanelSettings'; export type TocContext = { - editor$: Signal; + editor$: Signal; enableSorting$: Signal; showIcons$: Signal; fitPadding$: Signal; diff --git a/blocksuite/presets/src/fragments/outline/mobile-outline-panel.ts b/blocksuite/presets/src/fragments/outline/mobile-outline-panel.ts index 1a5284c82..a18b189fc 100644 --- a/blocksuite/presets/src/fragments/outline/mobile-outline-panel.ts +++ b/blocksuite/presets/src/fragments/outline/mobile-outline-panel.ts @@ -1,6 +1,11 @@ import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme'; -import { PropTypes, requiredProperties } from '@blocksuite/block-std'; import { + type EditorHost, + PropTypes, + requiredProperties, +} from '@blocksuite/block-std'; +import { + DocModeProvider, matchModels, NoteDisplayMode, ParagraphBlockModel, @@ -14,7 +19,6 @@ import { property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { repeat } from 'lit/directives/repeat.js'; -import type { AffineEditorContainer } from '../../editors/editor-container.js'; import { getHeadingBlocksFromDoc } from './utils/query.js'; import { observeActiveHeadingDuringScroll, @@ -162,8 +166,9 @@ export class MobileOutlineMenu extends SignalWatcher( }; override render() { - if (this.editor.doc.root === null || this.editor.mode === 'edgeless') - return nothing; + const docModeService = this.editor.std.get(DocModeProvider); + const mode = docModeService.getEditorMode(); + if (this.editor.doc.root === null || mode === 'edgeless') return nothing; const headingBlocks = getHeadingBlocksFromDoc( this.editor.doc, @@ -182,7 +187,7 @@ export class MobileOutlineMenu extends SignalWatcher( } @property({ attribute: false }) - accessor editor!: AffineEditorContainer; + accessor editor!: EditorHost; } declare global { diff --git a/blocksuite/presets/src/fragments/outline/outline-panel.ts b/blocksuite/presets/src/fragments/outline/outline-panel.ts index 49ea790d0..0e54b217c 100644 --- a/blocksuite/presets/src/fragments/outline/outline-panel.ts +++ b/blocksuite/presets/src/fragments/outline/outline-panel.ts @@ -1,15 +1,16 @@ import { + type EditorHost, PropTypes, requiredProperties, ShadowlessElement, } from '@blocksuite/block-std'; +import { DocModeProvider } from '@blocksuite/blocks'; import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils'; import { provide } from '@lit/context'; import { effect, signal } from '@preact/signals-core'; import { html, type PropertyValues } from 'lit'; import { property } from 'lit/decorators.js'; -import type { AffineEditorContainer } from '../../editors/editor-container.js'; import { outlineSettingsKey, type TocContext, tocContext } from './config.js'; import * as styles from './outline-panel.css'; @@ -21,6 +22,12 @@ export const AFFINE_OUTLINE_PANEL = 'affine-outline-panel'; export class OutlinePanel extends SignalWatcher( WithDisposable(ShadowlessElement) ) { + private _getEditorMode(host: EditorHost) { + const docModeService = host.std.get(DocModeProvider); + const mode = docModeService.getEditorMode(); + return mode; + } + private _setContext() { this._context = { editor$: signal(this.editor), @@ -39,7 +46,7 @@ export class OutlinePanel extends SignalWatcher( } const editor = this._context.editor$.value; - if (editor.mode === 'edgeless') { + if (this._getEditorMode(editor) === 'edgeless') { this._context.enableSorting$.value = true; } else if (settings) { this._context.enableSorting$.value = settings.enableSorting; @@ -51,7 +58,8 @@ export class OutlinePanel extends SignalWatcher( private _watchSettingsChange() { this.disposables.add( effect(() => { - if (this._context.editor$.value.mode === 'edgeless') return; + if (this._getEditorMode(this._context.editor$.value) === 'edgeless') + return; const showPreviewIcon = this._context.showIcons$.value; const enableNotesSorting = this._context.enableSorting$.value; @@ -84,7 +92,7 @@ export class OutlinePanel extends SignalWatcher( } override render() { - if (!this.editor.host) return; + if (!this.editor) return; return html` @@ -97,7 +105,7 @@ export class OutlinePanel extends SignalWatcher( private accessor _context!: TocContext; @property({ attribute: false }) - accessor editor!: AffineEditorContainer; + accessor editor!: EditorHost; @property({ attribute: false }) accessor fitPadding!: number[]; diff --git a/blocksuite/presets/src/fragments/outline/outline-viewer.ts b/blocksuite/presets/src/fragments/outline/outline-viewer.ts index 4bdbf0474..ca410643e 100644 --- a/blocksuite/presets/src/fragments/outline/outline-viewer.ts +++ b/blocksuite/presets/src/fragments/outline/outline-viewer.ts @@ -1,9 +1,14 @@ import { + type EditorHost, PropTypes, requiredProperties, ShadowlessElement, } from '@blocksuite/block-std'; -import { NoteDisplayMode, scrollbarStyle } from '@blocksuite/blocks'; +import { + DocModeProvider, + NoteDisplayMode, + scrollbarStyle, +} from '@blocksuite/blocks'; import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils'; import { TocIcon } from '@blocksuite/icons/lit'; import { provide } from '@lit/context'; @@ -13,7 +18,6 @@ import { property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { repeat } from 'lit/directives/repeat.js'; -import type { AffineEditorContainer } from '../../editors/editor-container.js'; import { type TocContext, tocContext } from './config.js'; import { getHeadingBlocksFromDoc } from './utils/query.js'; import { @@ -219,8 +223,9 @@ export class OutlineViewer extends SignalWatcher( } override render() { - if (this.editor.doc.root === null || this.editor.mode === 'edgeless') - return nothing; + const docModeService = this.editor.std.get(DocModeProvider); + const mode = docModeService.getEditorMode(); + if (this.editor.doc.root === null || mode === 'edgeless') return nothing; const headingBlocks = getHeadingBlocksFromDoc( this.editor.doc, @@ -308,7 +313,7 @@ export class OutlineViewer extends SignalWatcher( private accessor _showViewer: boolean = false; @property({ attribute: false }) - accessor editor!: AffineEditorContainer; + accessor editor!: EditorHost; @property({ attribute: false }) accessor toggleOutlinePanel: (() => void) | null = null; diff --git a/blocksuite/presets/src/fragments/outline/utils/scroll.ts b/blocksuite/presets/src/fragments/outline/utils/scroll.ts index c1fedbd3c..855de2c1c 100644 --- a/blocksuite/presets/src/fragments/outline/utils/scroll.ts +++ b/blocksuite/presets/src/fragments/outline/utils/scroll.ts @@ -1,13 +1,17 @@ import type { EditorHost } from '@blocksuite/block-std'; -import { getDocTitleByEditorHost, NoteDisplayMode } from '@blocksuite/blocks'; +import { + DocModeProvider, + getDocTitleByEditorHost, + NoteDisplayMode, +} from '@blocksuite/blocks'; import { clamp, DisposableGroup } from '@blocksuite/global/utils'; -import type { AffineEditorContainer } from '../../../editors/editor-container.js'; import { getHeadingBlocksFromDoc } from './query.js'; -export function scrollToBlock(editor: AffineEditorContainer, blockId: string) { - const { host, mode } = editor; - if (mode === 'edgeless' || !host) return; +export function scrollToBlock(host: EditorHost, blockId: string) { + const docModeService = host.std.get(DocModeProvider); + const mode = docModeService.getEditorMode(); + if (mode === 'edgeless') return; if (editor.doc.root?.id === blockId) { const docTitle = getDocTitleByEditorHost(host); @@ -49,12 +53,11 @@ export function isBlockBeforeViewportCenter( } export const observeActiveHeadingDuringScroll = ( - getEditor: () => AffineEditorContainer, // workaround for editor changed + getEditor: () => EditorHost, // workaround for editor changed update: (activeHeading: string | null) => void ) => { const handler = () => { - const { host } = getEditor(); - if (!host) return; + const host = getEditor(); const headings = getHeadingBlocksFromDoc( host.doc, @@ -81,13 +84,10 @@ export const observeActiveHeadingDuringScroll = ( let highlightMask: HTMLDivElement | null = null; let highlightTimeoutId: ReturnType | null = null; -function highlightBlock(editor: AffineEditorContainer, blockId: string) { +function highlightBlock(host: EditorHost, blockId: string) { const emptyClear = () => {}; - const { host } = editor; - if (!host) return emptyClear; - - if (editor.doc.root?.id === blockId) return emptyClear; + if (host.doc.root?.id === blockId) return emptyClear; const rootComponent = host.querySelector('affine-page-root'); if (!rootComponent) return emptyClear; @@ -152,11 +152,11 @@ function highlightBlock(editor: AffineEditorContainer, blockId: string) { // this function is useful when the scroll need smooth animation let highlightIntervalId: ReturnType | null = null; export async function scrollToBlockWithHighlight( - editor: AffineEditorContainer, + host: EditorHost, blockId: string, timeout = 3000 ) { - scrollToBlock(editor, blockId); + scrollToBlock(host, blockId); let timeCount = 0; @@ -173,10 +173,9 @@ export async function scrollToBlockWithHighlight( return; } - const { host } = editor; - const block = host?.view.getBlock(blockId); + const block = host.view.getBlock(blockId); - if (!host || !block || timeCount > timeout) { + if (!block || timeCount > timeout) { clearInterval(highlightIntervalId); resolve(() => {}); return; @@ -194,7 +193,7 @@ export async function scrollToBlockWithHighlight( clearInterval(highlightIntervalId); // highlight block - resolve(highlightBlock(editor, blockId)); + resolve(highlightBlock(host, blockId)); }, 100); }); } diff --git a/packages/frontend/core/src/components/blocksuite/outline-viewer/index.tsx b/packages/frontend/core/src/components/blocksuite/outline-viewer/index.tsx index 7b18cd837..97fb92a13 100644 --- a/packages/frontend/core/src/components/blocksuite/outline-viewer/index.tsx +++ b/packages/frontend/core/src/components/blocksuite/outline-viewer/index.tsx @@ -1,4 +1,4 @@ -import type { AffineEditorContainer } from '@blocksuite/affine/presets'; +import type { EditorHost } from '@blocksuite/affine/block-std'; import { OutlineViewer } from '@blocksuite/affine/presets'; import { useCallback, useRef } from 'react'; @@ -9,7 +9,7 @@ export const EditorOutlineViewer = ({ show, openOutlinePanel, }: { - editor: AffineEditorContainer | null; + editor: EditorHost | null; show: boolean; openOutlinePanel?: () => void; }) => { diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx index fcb7f34e4..b998cbf89 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/detail-page.tsx @@ -310,7 +310,7 @@ const DetailPageImpl = memo(function DetailPageImpl() { /> @@ -350,7 +350,7 @@ const DetailPageImpl = memo(function DetailPageImpl() { }> - + @@ -359,7 +359,7 @@ const DetailPageImpl = memo(function DetailPageImpl() { }> - + diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/frame.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/frame.tsx index 57be5fecf..f8d070257 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/frame.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/frame.tsx @@ -1,34 +1,30 @@ +import type { EditorHost } from '@blocksuite/affine/block-std'; import { FramePanel } from '@blocksuite/affine/blocks'; -import type { AffineEditorContainer } from '@blocksuite/affine/presets'; import { useCallback, useEffect, useRef } from 'react'; import * as styles from './frame.css'; // A wrapper for FramePanel -export const EditorFramePanel = ({ - editor, -}: { - editor: AffineEditorContainer | null; -}) => { +export const EditorFramePanel = ({ editor }: { editor: EditorHost | null }) => { const framePanelRef = useRef(null); const onRefChange = useCallback( (container: HTMLDivElement | null) => { - if (editor?.host && container && container.children.length === 0) { + if (editor && container && container.children.length === 0) { framePanelRef.current = new FramePanel(); - framePanelRef.current.host = editor.host; + framePanelRef.current.host = editor; framePanelRef.current.fitPadding = [20, 20, 20, 20]; container.append(framePanelRef.current); } }, - [editor?.host] + [editor] ); useEffect(() => { - if (editor?.host && framePanelRef.current) { - framePanelRef.current.host = editor.host; + if (editor && framePanelRef.current) { + framePanelRef.current.host = editor; } - }, [editor?.host]); + }, [editor]); return
; }; diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/outline.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/outline.tsx index 3c20399fb..9912fc356 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/outline.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/outline.tsx @@ -1,4 +1,4 @@ -import type { AffineEditorContainer } from '@blocksuite/affine/presets'; +import type { EditorHost } from '@blocksuite/affine/block-std'; import { OutlinePanel } from '@blocksuite/affine/presets'; import { useCallback, useEffect, useRef } from 'react'; @@ -8,7 +8,7 @@ import * as styles from './outline.css'; export const EditorOutlinePanel = ({ editor, }: { - editor: AffineEditorContainer | null; + editor: EditorHost | null; }) => { const outlinePanelRef = useRef(null); diff --git a/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx b/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx index 1eff12db4..02c616369 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/share/share-page.tsx @@ -268,7 +268,7 @@ const SharePageInner = ({ {!BUILD_CONFIG.isElectron && } diff --git a/packages/frontend/core/src/mobile/components/toc-menu/index.tsx b/packages/frontend/core/src/mobile/components/toc-menu/index.tsx index bdd8b07a2..48b07c69f 100644 --- a/packages/frontend/core/src/mobile/components/toc-menu/index.tsx +++ b/packages/frontend/core/src/mobile/components/toc-menu/index.tsx @@ -1,14 +1,8 @@ -import { - type AffineEditorContainer, - MobileOutlineMenu, -} from '@blocksuite/affine/presets'; +import type { EditorHost } from '@blocksuite/affine/block-std'; +import { MobileOutlineMenu } from '@blocksuite/affine/presets'; import { useCallback, useRef } from 'react'; -export const MobileTocMenu = ({ - editor, -}: { - editor: AffineEditorContainer | null; -}) => { +export const MobileTocMenu = ({ editor }: { editor: EditorHost | null }) => { const outlineMenuRef = useRef(null); const onRefChange = useCallback((container: HTMLDivElement | null) => { if (container) { diff --git a/packages/frontend/core/src/mobile/pages/workspace/detail/page-header-more-button.tsx b/packages/frontend/core/src/mobile/pages/workspace/detail/page-header-more-button.tsx index 2307b92a9..9833caf16 100644 --- a/packages/frontend/core/src/mobile/pages/workspace/detail/page-header-more-button.tsx +++ b/packages/frontend/core/src/mobile/pages/workspace/detail/page-header-more-button.tsx @@ -127,7 +127,7 @@ export const PageHeaderMenuButton = () => { title={t['com.affine.header.menu.toc']()} items={
- +
} > diff --git a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx index d490cdf2f..15022daa6 100644 --- a/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx +++ b/packages/frontend/core/src/modules/peek-view/view/doc-preview/doc-peek-view.tsx @@ -179,7 +179,7 @@ function DocPeekPreviewEditor({ {!BUILD_CONFIG.isMobileEdition && !BUILD_CONFIG.isMobileWeb ? (