refactor(editor): extract surface ref block (#9433)

This commit is contained in:
Saul-Mirone
2024-12-30 12:09:26 +00:00
parent d4053a345e
commit e526106f45
25 changed files with 196 additions and 58 deletions

View File

@@ -0,0 +1,48 @@
{
"name": "@blocksuite/affine-block-surface-ref",
"description": "Surface ref block for BlockSuite.",
"type": "module",
"scripts": {
"build": "tsc",
"test:unit": "nx vite:test --run --passWithNoTests",
"test:unit:coverage": "nx vite:test --run --coverage",
"test:e2e": "playwright test"
},
"sideEffects": false,
"keywords": [],
"author": "toeverything",
"license": "MIT",
"dependencies": {
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",
"@blocksuite/block-std": "workspace:*",
"@blocksuite/global": "workspace:*",
"@blocksuite/inline": "workspace:*",
"@blocksuite/store": "workspace:*",
"@lit/context": "^1.1.2",
"@preact/signals-core": "^1.8.0",
"@toeverything/theme": "^1.1.3",
"fractional-indexing": "^3.2.0",
"lit": "^3.2.0",
"lodash.chunk": "^4.2.0",
"nanoid": "^5.0.7",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/dompurify": "^3.0.5",
"@types/lodash.chunk": "^4.2.9"
},
"exports": {
".": "./src/index.ts",
"./effects": "./src/effects.ts"
},
"files": [
"src",
"dist",
"!src/__tests__",
"!dist/__tests__"
],
"version": "0.19.0"
}

View File

@@ -1,7 +1,20 @@
import type { insertSurfaceRefBlockCommand } from './commands.js';
import { SurfaceRefGenericBlockPortal } from './portal/generic-block.js';
import { SurfaceRefNotePortal } from './portal/note.js';
import { SurfaceRefBlockComponent } from './surface-ref-block.js';
import { EdgelessSurfaceRefBlockComponent } from './surface-ref-block-edgeless.js';
export function effects() {
// TODO(@L-Sun): move other effects to this file
customElements.define(
'surface-ref-generic-block-portal',
SurfaceRefGenericBlockPortal
);
customElements.define('affine-surface-ref', SurfaceRefBlockComponent);
customElements.define(
'affine-edgeless-surface-ref',
EdgelessSurfaceRefBlockComponent
);
customElements.define('surface-ref-note-portal', SurfaceRefNotePortal);
}
declare global {

View File

@@ -1,7 +1,10 @@
import '@blocksuite/affine-shared/commands';
export * from './surface-ref-block.js';
export * from './surface-ref-block-edgeless.js';
export {
EdgelessSurfaceRefBlockSpec,
PageSurfaceRefBlockSpec,
} from './surface-ref-spec.js';
export * from './types.js';
export * from './utils.js';

View File

@@ -1,4 +1,5 @@
import {
EdgelessCRUDExtension,
getSurfaceBlock,
type SurfaceBlockModel,
SurfaceElementModel,
@@ -20,7 +21,10 @@ import {
EditPropsStore,
ThemeProvider,
} from '@blocksuite/affine-shared/services';
import { requestConnectedFrame } from '@blocksuite/affine-shared/utils';
import {
requestConnectedFrame,
SpecProvider,
} from '@blocksuite/affine-shared/utils';
import {
type BaseSelection,
BlockComponent,
@@ -29,7 +33,10 @@ import {
type EditorHost,
LifeCycleWatcher,
} from '@blocksuite/block-std';
import { GfxBlockElementModel } from '@blocksuite/block-std/gfx';
import {
GfxBlockElementModel,
GfxControllerIdentifier,
} from '@blocksuite/block-std/gfx';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import {
assertExists,
@@ -43,9 +50,7 @@ import { css, html, nothing, type TemplateResult } from 'lit';
import { query, state } from 'lit/decorators.js';
import { styleMap } from 'lit/directives/style-map.js';
import { SpecProvider } from '../_specs/index.js';
import type { EdgelessRootPreviewBlockComponent } from '../root-block/edgeless/edgeless-root-preview-block.js';
import { EdgelessRootService } from '../root-block/index.js';
import type { EdgelessPreviewer } from './types.js';
import { noContentPlaceholder } from './utils.js';
const REF_LABEL_ICON = {
@@ -418,18 +423,20 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
private _initSpec() {
const refreshViewport = this._refreshViewport.bind(this);
class PageViewWatcher extends BlockServiceWatcher {
static override readonly flavour = 'affine:page';
override mounted() {
this.blockService.disposables.add(
this.blockService.specSlots.viewConnected.once(({ component }) => {
const edgelessBlock =
component as EdgelessRootPreviewBlockComponent;
const edgelessBlock = component as BlockComponent &
EdgelessPreviewer;
edgelessBlock.editorViewportSelector = 'ref-viewport';
refreshViewport();
edgelessBlock.service.viewport.sizeUpdated.once(() => {
const gfx = edgelessBlock.std.get(GfxControllerIdentifier);
gfx.viewport.sizeUpdated.once(() => {
refreshViewport();
});
})
@@ -449,11 +456,12 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
private readonly _disposable = new DisposableGroup();
override mounted() {
const edgelessService = this.std.get(EdgelessRootService);
const crud = this.std.get(EdgelessCRUDExtension);
const { _disposable } = this;
const surfaceModel = getSurfaceBlock(this.std.doc);
if (!surfaceModel) return;
const referenceElement =
edgelessService.crud.getElementById(referenceId);
const referenceElement = crud.getElementById(referenceId);
if (!referenceElement) {
throw new BlockSuiteError(
ErrorCode.MissingViewModelError,
@@ -470,7 +478,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
);
} else if (referenceElement instanceof GroupElementModel) {
_disposable.add(
edgelessService.surface.elementUpdated.on(({ id, oldValues }) => {
surfaceModel.elementUpdated.on(({ id, oldValues }) => {
if (
id === referenceId &&
oldValues.xywh !== referenceElement.xywh
@@ -500,13 +508,10 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
if (!previewEditorHost) return;
const edgelessService = previewEditorHost.std.getService(
'affine:page'
) as EdgelessRootService;
const gfx = previewEditorHost.std.get(GfxControllerIdentifier);
const viewport = gfx.viewport;
edgelessService.viewport.setViewportByBound(
Bound.deserialize(this._referenceXYWH)
);
viewport.setViewportByBound(Bound.deserialize(this._referenceXYWH));
}
private _renderMask(

View File

@@ -0,0 +1,3 @@
export interface EdgelessPreviewer {
editorViewportSelector: string;
}

View File

@@ -0,0 +1,32 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src/",
"outDir": "./dist/",
"noEmit": false
},
"include": ["./src"],
"references": [
{
"path": "../../framework/global"
},
{
"path": "../../framework/store"
},
{
"path": "../../framework/block-std"
},
{
"path": "../../framework/inline"
},
{
"path": "../model"
},
{
"path": "../components"
},
{
"path": "../shared"
}
]
}

View File

@@ -27,6 +27,7 @@
"@blocksuite/affine-block-note": "workspace:*",
"@blocksuite/affine-block-paragraph": "workspace:*",
"@blocksuite/affine-block-surface": "workspace:*",
"@blocksuite/affine-block-surface-ref": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-shared": "workspace:*",

View File

@@ -17,6 +17,10 @@ import {
EdgelessSurfaceBlockSpec,
PageSurfaceBlockSpec,
} from '@blocksuite/affine-block-surface';
import {
EdgelessSurfaceRefBlockSpec,
PageSurfaceRefBlockSpec,
} from '@blocksuite/affine-block-surface-ref';
import {
RefNodeSlotsExtension,
RichTextExtensions,
@@ -31,10 +35,6 @@ import type { ExtensionType } from '@blocksuite/block-std';
import { AdapterFactoryExtensions } from '../_common/adapters/extension.js';
import { DataViewBlockSpec } from '../data-view-block/data-view-spec.js';
import { DatabaseBlockSpec } from '../database-block/database-spec.js';
import {
EdgelessSurfaceRefBlockSpec,
PageSurfaceRefBlockSpec,
} from '../surface-ref-block/surface-ref-spec.js';
export const CommonBlockSpecs: ExtensionType[] = [
DocDisplayMetaService,

View File

@@ -1,4 +1,3 @@
import type { NoteBlockComponent } from '@blocksuite/affine-block-note';
import { CaptionedBlockComponent } from '@blocksuite/affine-components/caption';
import {
menu,
@@ -17,7 +16,10 @@ import {
TelemetryProvider,
} from '@blocksuite/affine-shared/services';
import { getDropResult } from '@blocksuite/affine-widget-drag-handle';
import { RANGE_SYNC_EXCLUDE_ATTR } from '@blocksuite/block-std';
import {
type BlockComponent,
RANGE_SYNC_EXCLUDE_ATTR,
} from '@blocksuite/block-std';
import {
createRecordDetail,
createUniComponentFromWebComponent,
@@ -46,7 +48,6 @@ import { autoUpdate } from '@floating-ui/dom';
import { computed, signal } from '@preact/signals-core';
import { css, html, nothing, unsafeCSS } from 'lit';
import { EdgelessRootBlockComponent } from '../root-block/index.js';
import { popSideDetail } from './components/layout.js';
import type { DatabaseOptionsConfig } from './config.js';
import { HostContextKey } from './context/host-context.js';
@@ -351,9 +352,8 @@ export class DatabaseBlockComponent extends CaptionedBlockComponent<
}
override get topContenteditableElement() {
if (this.rootComponent instanceof EdgelessRootBlockComponent) {
const note = this.closest<NoteBlockComponent>(NOTE_SELECTOR);
return note;
if (this.std.get(DocModeProvider).getEditorMode() === 'edgeless') {
return this.closest<BlockComponent>(NOTE_SELECTOR);
}
return this.rootComponent;
}

View File

@@ -11,6 +11,7 @@ import { effects as blockListEffects } from '@blocksuite/affine-block-list/effec
import { effects as blockNoteEffects } from '@blocksuite/affine-block-note/effects';
import { effects as blockParagraphEffects } from '@blocksuite/affine-block-paragraph/effects';
import { effects as blockSurfaceEffects } from '@blocksuite/affine-block-surface/effects';
import { effects as blockSurfaceRefEffects } from '@blocksuite/affine-block-surface-ref/effects';
import { effects as componentAiItemEffects } from '@blocksuite/affine-components/ai-item';
import { BlockSelection } from '@blocksuite/affine-components/block-selection';
import { BlockZeroWidth } from '@blocksuite/affine-components/block-zero-width';
@@ -209,13 +210,6 @@ import {
MindmapSurfaceBlock,
MiniMindmapPreview,
} from './surface-block/mini-mindmap/index.js';
import { effects as blockSurfaceRefEffects } from './surface-ref-block/effects.js';
import {
EdgelessSurfaceRefBlockComponent,
SurfaceRefBlockComponent,
} from './surface-ref-block/index.js';
import { SurfaceRefGenericBlockPortal } from './surface-ref-block/portal/generic-block.js';
import { SurfaceRefNotePortal } from './surface-ref-block/portal/note.js';
export function effects() {
registerSpecs();
@@ -286,10 +280,6 @@ export function effects() {
'edgeless-copilot-toolbar-entry',
EdgelessCopilotToolbarEntry
);
customElements.define(
'affine-edgeless-surface-ref',
EdgelessSurfaceRefBlockComponent
);
customElements.define(
'edgeless-color-custom-button',
EdgelessColorCustomButton
@@ -302,7 +292,6 @@ export function effects() {
);
customElements.define('affine-custom-modal', AffineCustomModal);
customElements.define('affine-database', DatabaseBlockComponent);
customElements.define('affine-surface-ref', SurfaceRefBlockComponent);
customElements.define('affine-slash-menu', SlashMenu);
customElements.define('inner-slash-menu', InnerSlashMenu);
customElements.define('generating-placeholder', GeneratingPlaceholder);
@@ -321,10 +310,6 @@ export function effects() {
customElements.define('icon-button', IconButton);
customElements.define('loader-element', Loader);
customElements.define('edgeless-brush-menu', EdgelessBrushMenu);
customElements.define(
'surface-ref-generic-block-portal',
SurfaceRefGenericBlockPortal
);
customElements.define('edgeless-brush-tool-button', EdgelessBrushToolButton);
customElements.define(
'edgeless-connector-tool-button',
@@ -334,7 +319,6 @@ export function effects() {
'edgeless-default-tool-button',
EdgelessDefaultToolButton
);
customElements.define('surface-ref-note-portal', SurfaceRefNotePortal);
customElements.define('edgeless-connector-menu', EdgelessConnectorMenu);
customElements.define('smooth-corner', SmoothCorner);
customElements.define('toggle-switch', ToggleSwitch);

View File

@@ -39,7 +39,6 @@ export {
MindmapSurfaceBlock,
MiniMindmapPreview,
} from './surface-block/mini-mindmap/index.js';
export * from './surface-ref-block/index.js';
export * from '@blocksuite/affine-block-attachment';
export * from '@blocksuite/affine-block-bookmark';
export * from '@blocksuite/affine-block-code';
@@ -53,6 +52,7 @@ export * from '@blocksuite/affine-block-list';
export * from '@blocksuite/affine-block-note';
export * from '@blocksuite/affine-block-paragraph';
export * from '@blocksuite/affine-block-surface';
export * from '@blocksuite/affine-block-surface-ref';
export {
type AIError,
type AIItemConfig,

View File

@@ -2,6 +2,7 @@ import type {
SurfaceBlockComponent,
SurfaceBlockModel,
} from '@blocksuite/affine-block-surface';
import type { EdgelessPreviewer } from '@blocksuite/affine-block-surface-ref';
import type { RootBlockModel } from '@blocksuite/affine-model';
import {
FontLoaderService,
@@ -22,11 +23,14 @@ import type { EdgelessRootBlockWidgetName } from '../types.js';
import type { EdgelessRootService } from './edgeless-root-service.js';
import { getBackgroundGrid, isCanvasElement } from './utils/query.js';
export class EdgelessRootPreviewBlockComponent extends BlockComponent<
RootBlockModel,
EdgelessRootService,
EdgelessRootBlockWidgetName
> {
export class EdgelessRootPreviewBlockComponent
extends BlockComponent<
RootBlockModel,
EdgelessRootService,
EdgelessRootBlockWidgetName
>
implements EdgelessPreviewer
{
static override styles = css`
affine-edgeless-root-preview {
pointer-events: none;

View File

@@ -1,7 +1,6 @@
import type { SurfaceRefBlockComponent } from '@blocksuite/affine-block-surface-ref';
import { MenuContext } from '@blocksuite/affine-components/toolbar';
import type { SurfaceRefBlockComponent } from '../../../surface-ref-block/surface-ref-block.js';
export class SurfaceRefToolbarContext extends MenuContext {
override close = () => {
this.abortController.abort();

View File

@@ -1,3 +1,4 @@
import type { SurfaceRefBlockComponent } from '@blocksuite/affine-block-surface-ref';
import { HoverController } from '@blocksuite/affine-components/hover';
import {
CaptionIcon,
@@ -25,7 +26,6 @@ import { ifDefined } from 'lit/directives/if-defined.js';
import { join } from 'lit/directives/join.js';
import { repeat } from 'lit/directives/repeat.js';
import type { SurfaceRefBlockComponent } from '../../../surface-ref-block/index.js';
import { BUILT_IN_GROUPS } from './config.js';
import { SurfaceRefToolbarContext } from './context.js';

View File

@@ -1,10 +1,10 @@
import type { CanvasRenderer } from '@blocksuite/affine-block-surface';
import type { SurfaceRefBlockComponent } from '@blocksuite/affine-block-surface-ref';
import { isTopLevelBlock } from '@blocksuite/affine-shared/utils';
import type { EditorHost } from '@blocksuite/block-std';
import { assertExists, Bound } from '@blocksuite/global/utils';
import { ExportManager } from '../../../_common/export-manager/export-manager.js';
import type { SurfaceRefBlockComponent } from '../../../surface-ref-block/surface-ref-block.js';
export const edgelessToBlob = async (
host: EditorHost,

View File

@@ -65,10 +65,13 @@
"path": "../affine/block-divider"
},
{
"path": "../affine/data-view"
"path": "../affine/block-surface"
},
{
"path": "../affine/block-surface"
"path": "../affine/block-surface-ref"
},
{
"path": "../affine/data-view"
},
{
"path": "../affine/widget-scroll-anchoring"