mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-24 09:52:49 +08:00
refactor(editor): extract surface ref block (#9433)
This commit is contained in:
48
blocksuite/affine/block-surface-ref/package.json
Normal file
48
blocksuite/affine/block-surface-ref/package.json
Normal 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"
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -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';
|
||||
@@ -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(
|
||||
3
blocksuite/affine/block-surface-ref/src/types.ts
Normal file
3
blocksuite/affine/block-surface-ref/src/types.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface EdgelessPreviewer {
|
||||
editorViewportSelector: string;
|
||||
}
|
||||
32
blocksuite/affine/block-surface-ref/tsconfig.json
Normal file
32
blocksuite/affine/block-surface-ref/tsconfig.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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:*",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user