mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-16 05:47:09 +08:00
feat(editor): replace spec provider with extension manager (#11861)
Closes: BS-3273
This commit is contained in:
@@ -208,7 +208,9 @@
|
||||
"./model": "./src/model/index.ts",
|
||||
"./sync": "./src/sync/index.ts",
|
||||
"./adapters": "./src/adapters/index.ts",
|
||||
"./extensions": "./src/extensions/index.ts"
|
||||
"./extensions": "./src/extensions/index.ts",
|
||||
"./extensions/store": "./src/extensions/store.ts",
|
||||
"./extensions/view": "./src/extensions/view.ts"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
|
||||
153
blocksuite/affine/all/src/extensions/migrating.ts
Normal file
153
blocksuite/affine/all/src/extensions/migrating.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
import { AttachmentBlockSpec } from '@blocksuite/affine-block-attachment';
|
||||
import { BookmarkBlockSpec } from '@blocksuite/affine-block-bookmark';
|
||||
import { CalloutBlockSpec } from '@blocksuite/affine-block-callout';
|
||||
import { CodeBlockSpec } from '@blocksuite/affine-block-code';
|
||||
import { DataViewBlockSpec } from '@blocksuite/affine-block-data-view';
|
||||
import { DatabaseBlockSpec } from '@blocksuite/affine-block-database';
|
||||
import { DividerBlockSpec } from '@blocksuite/affine-block-divider';
|
||||
import { EdgelessTextBlockSpec } from '@blocksuite/affine-block-edgeless-text';
|
||||
import { EmbedExtensions } from '@blocksuite/affine-block-embed';
|
||||
import { FrameBlockSpec } from '@blocksuite/affine-block-frame';
|
||||
import { ImageBlockSpec } from '@blocksuite/affine-block-image';
|
||||
import { LatexBlockSpec } from '@blocksuite/affine-block-latex';
|
||||
import { ListBlockSpec } from '@blocksuite/affine-block-list';
|
||||
import {
|
||||
EdgelessNoteBlockSpec,
|
||||
NoteBlockSpec,
|
||||
} from '@blocksuite/affine-block-note';
|
||||
import { ParagraphBlockSpec } from '@blocksuite/affine-block-paragraph';
|
||||
import {
|
||||
EdgelessBuiltInSpecs,
|
||||
PageRootBlockSpec,
|
||||
PreviewEdgelessRootBlockSpec,
|
||||
PreviewPageRootBlockSpec,
|
||||
ReadOnlyClipboard,
|
||||
} from '@blocksuite/affine-block-root';
|
||||
import {
|
||||
EdgelessSurfaceBlockAdapterExtensions,
|
||||
EdgelessSurfaceBlockSpec,
|
||||
PageSurfaceBlockSpec,
|
||||
SurfaceBlockAdapterExtensions,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
EdgelessSurfaceRefBlockSpec,
|
||||
PageSurfaceRefBlockSpec,
|
||||
} from '@blocksuite/affine-block-surface-ref';
|
||||
import { TableBlockSpec } from '@blocksuite/affine-block-table';
|
||||
import {
|
||||
brushToMarkdownAdapterMatcher,
|
||||
brushToPlainTextAdapterMatcher,
|
||||
} from '@blocksuite/affine-gfx-brush';
|
||||
import {
|
||||
connectorToMarkdownAdapterMatcher,
|
||||
connectorToPlainTextAdapterMatcher,
|
||||
} from '@blocksuite/affine-gfx-connector';
|
||||
import {
|
||||
groupToMarkdownAdapterMatcher,
|
||||
groupToPlainTextAdapterMatcher,
|
||||
} from '@blocksuite/affine-gfx-group';
|
||||
import {
|
||||
mindmapToMarkdownAdapterMatcher,
|
||||
mindmapToPlainTextAdapterMatcher,
|
||||
} from '@blocksuite/affine-gfx-mindmap';
|
||||
import {
|
||||
shapeToMarkdownAdapterMatcher,
|
||||
shapeToPlainTextAdapterMatcher,
|
||||
} from '@blocksuite/affine-gfx-shape';
|
||||
import {
|
||||
textToMarkdownAdapterMatcher,
|
||||
textToPlainTextAdapterMatcher,
|
||||
} from '@blocksuite/affine-gfx-text';
|
||||
import { inlinePresetExtensions } from '@blocksuite/affine-inline-preset';
|
||||
import {
|
||||
DefaultOpenDocExtension,
|
||||
DocDisplayMetaService,
|
||||
EditPropsStore,
|
||||
FontLoaderService,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
const elementToPlainTextAdapterMatchers = [
|
||||
groupToPlainTextAdapterMatcher,
|
||||
shapeToPlainTextAdapterMatcher,
|
||||
connectorToPlainTextAdapterMatcher,
|
||||
brushToPlainTextAdapterMatcher,
|
||||
textToPlainTextAdapterMatcher,
|
||||
mindmapToPlainTextAdapterMatcher,
|
||||
];
|
||||
|
||||
const elementToMarkdownAdapterMatchers = [
|
||||
groupToMarkdownAdapterMatcher,
|
||||
shapeToMarkdownAdapterMatcher,
|
||||
connectorToMarkdownAdapterMatcher,
|
||||
brushToMarkdownAdapterMatcher,
|
||||
textToMarkdownAdapterMatcher,
|
||||
mindmapToMarkdownAdapterMatcher,
|
||||
];
|
||||
|
||||
const CommonBlockSpecs: ExtensionType[] = [
|
||||
inlinePresetExtensions,
|
||||
DocDisplayMetaService,
|
||||
EditPropsStore,
|
||||
LatexBlockSpec,
|
||||
ListBlockSpec,
|
||||
DatabaseBlockSpec,
|
||||
TableBlockSpec,
|
||||
DataViewBlockSpec,
|
||||
DividerBlockSpec,
|
||||
BookmarkBlockSpec,
|
||||
EmbedExtensions,
|
||||
AttachmentBlockSpec,
|
||||
CodeBlockSpec,
|
||||
ImageBlockSpec,
|
||||
ParagraphBlockSpec,
|
||||
DefaultOpenDocExtension,
|
||||
FontLoaderService,
|
||||
CalloutBlockSpec,
|
||||
FrameBlockSpec,
|
||||
|
||||
elementToPlainTextAdapterMatchers,
|
||||
elementToMarkdownAdapterMatchers,
|
||||
].flat();
|
||||
|
||||
const PageFirstPartyBlockSpecs: ExtensionType[] = [
|
||||
CommonBlockSpecs,
|
||||
NoteBlockSpec,
|
||||
PageSurfaceBlockSpec,
|
||||
PageSurfaceRefBlockSpec,
|
||||
|
||||
...SurfaceBlockAdapterExtensions,
|
||||
].flat();
|
||||
|
||||
const EdgelessFirstPartyBlockSpecs: ExtensionType[] = [
|
||||
CommonBlockSpecs,
|
||||
|
||||
EdgelessNoteBlockSpec,
|
||||
EdgelessSurfaceBlockSpec,
|
||||
EdgelessSurfaceRefBlockSpec,
|
||||
EdgelessTextBlockSpec,
|
||||
|
||||
...EdgelessSurfaceBlockAdapterExtensions,
|
||||
].flat();
|
||||
|
||||
export const MigratingEdgelessEditorBlockSpecs: ExtensionType[] = [
|
||||
EdgelessBuiltInSpecs,
|
||||
EdgelessFirstPartyBlockSpecs,
|
||||
].flat();
|
||||
|
||||
export const MigratingPageEditorBlockSpecs: ExtensionType[] = [
|
||||
PageRootBlockSpec,
|
||||
PageFirstPartyBlockSpecs,
|
||||
].flat();
|
||||
|
||||
export const MigratingPreviewEdgelessEditorBlockSpecs: ExtensionType[] = [
|
||||
PreviewEdgelessRootBlockSpec,
|
||||
EdgelessFirstPartyBlockSpecs,
|
||||
ReadOnlyClipboard,
|
||||
].flat();
|
||||
|
||||
export const MigratingPreviewPageEditorBlockSpecs: ExtensionType[] = [
|
||||
PreviewPageRootBlockSpec,
|
||||
PageFirstPartyBlockSpecs,
|
||||
ReadOnlyClipboard,
|
||||
].flat();
|
||||
@@ -4,6 +4,10 @@ import { EmbedIframeConfigExtensions } from '@blocksuite/affine-block-embed';
|
||||
import { ImageStoreSpec } from '@blocksuite/affine-block-image';
|
||||
import { SurfaceBlockSchemaExtension } from '@blocksuite/affine-block-surface';
|
||||
import { TableSelectionExtension } from '@blocksuite/affine-block-table';
|
||||
import {
|
||||
type StoreExtensionContext,
|
||||
StoreExtensionProvider,
|
||||
} from '@blocksuite/affine-ext-loader';
|
||||
import {
|
||||
AttachmentBlockSchemaExtension,
|
||||
BookmarkBlockSchemaExtension,
|
||||
@@ -110,3 +114,12 @@ export const StoreExtensions: ExtensionType[] = [
|
||||
EmbedIframeConfigExtensions,
|
||||
EmbedIframeService,
|
||||
].flat();
|
||||
|
||||
export class MigratingStoreExtension extends StoreExtensionProvider {
|
||||
override name = 'migrating';
|
||||
|
||||
override setup(context: StoreExtensionContext) {
|
||||
super.setup(context);
|
||||
context.register(StoreExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
42
blocksuite/affine/all/src/extensions/view.ts
Normal file
42
blocksuite/affine/all/src/extensions/view.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
type ViewExtensionContext,
|
||||
ViewExtensionProvider,
|
||||
} from '@blocksuite/affine-ext-loader';
|
||||
|
||||
import { effects } from '../effects';
|
||||
import {
|
||||
MigratingEdgelessEditorBlockSpecs,
|
||||
MigratingPageEditorBlockSpecs,
|
||||
MigratingPreviewEdgelessEditorBlockSpecs,
|
||||
MigratingPreviewPageEditorBlockSpecs,
|
||||
} from './migrating';
|
||||
|
||||
export class MigratingViewExtension extends ViewExtensionProvider {
|
||||
override name = 'migrating';
|
||||
|
||||
override effect() {
|
||||
super.effect();
|
||||
effects();
|
||||
}
|
||||
|
||||
override setup(context: ViewExtensionContext) {
|
||||
super.setup(context);
|
||||
const scope = context.scope;
|
||||
if (scope === 'preview-page') {
|
||||
context.register(MigratingPreviewPageEditorBlockSpecs);
|
||||
return;
|
||||
}
|
||||
if (scope === 'preview-edgeless') {
|
||||
context.register(MigratingPreviewEdgelessEditorBlockSpecs);
|
||||
return;
|
||||
}
|
||||
if (scope === 'page' || scope === 'mobile-page') {
|
||||
context.register(MigratingPageEditorBlockSpecs);
|
||||
return;
|
||||
}
|
||||
if (scope === 'edgeless' || scope === 'mobile-edgeless') {
|
||||
context.register(MigratingEdgelessEditorBlockSpecs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine-ext-loader';
|
||||
import {
|
||||
type DocMode,
|
||||
ImageBlockModel,
|
||||
@@ -9,7 +10,7 @@ import {
|
||||
} from '@blocksuite/affine-model';
|
||||
import { EMBED_CARD_HEIGHT } from '@blocksuite/affine-shared/consts';
|
||||
import { NotificationProvider } from '@blocksuite/affine-shared/services';
|
||||
import { matchModels, SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
import { matchModels } from '@blocksuite/affine-shared/utils';
|
||||
import { BlockStdScope, EditorLifeCycleExtension } from '@blocksuite/std';
|
||||
import {
|
||||
type BlockModel,
|
||||
@@ -202,10 +203,13 @@ async function renderNoteContent(
|
||||
match: ids.map(id => ({ id, viewType: 'display' })),
|
||||
};
|
||||
const previewDoc = doc.doc.getStore({ query });
|
||||
const previewSpec = SpecProvider._.getSpec('preview:page');
|
||||
const std = card.host.std;
|
||||
const previewSpec = std
|
||||
.get(ViewExtensionManagerIdentifier)
|
||||
.get('preview-page');
|
||||
const previewStd = new BlockStdScope({
|
||||
store: previewDoc,
|
||||
extensions: previewSpec.value,
|
||||
extensions: previewSpec,
|
||||
});
|
||||
const previewTemplate = previewStd.render();
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
@@ -70,7 +70,7 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
|
||||
<div class="affine-page-viewport" data-theme=${appTheme}>
|
||||
${new BlockStdScope({
|
||||
store: syncedDoc,
|
||||
extensions: this._buildPreviewSpec('preview:page'),
|
||||
extensions: this._buildPreviewSpec('preview-page'),
|
||||
}).render()}
|
||||
</div>
|
||||
`,
|
||||
@@ -81,7 +81,7 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
|
||||
<div class="affine-edgeless-viewport" data-theme=${edgelessTheme}>
|
||||
${new BlockStdScope({
|
||||
store: syncedDoc,
|
||||
extensions: this._buildPreviewSpec('preview:edgeless'),
|
||||
extensions: this._buildPreviewSpec('preview-edgeless'),
|
||||
}).render()}
|
||||
</div>
|
||||
`,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Peekable } from '@blocksuite/affine-components/peek';
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine-ext-loader';
|
||||
import {
|
||||
type DocLinkClickedEvent,
|
||||
RefNodeSlotsProvider,
|
||||
@@ -20,10 +21,7 @@ import {
|
||||
ThemeExtensionIdentifier,
|
||||
ThemeProvider,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import {
|
||||
cloneReferenceInfo,
|
||||
SpecProvider,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { cloneReferenceInfo } from '@blocksuite/affine-shared/utils';
|
||||
import { Bound, getCommonBound } from '@blocksuite/global/gfx';
|
||||
import {
|
||||
BlockSelection,
|
||||
@@ -113,9 +111,10 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
||||
],
|
||||
};
|
||||
|
||||
protected _buildPreviewSpec = (name: 'preview:page' | 'preview:edgeless') => {
|
||||
protected _buildPreviewSpec = (name: 'preview-page' | 'preview-edgeless') => {
|
||||
const nextDepth = this.depth + 1;
|
||||
const previewSpecBuilder = SpecProvider._.getSpec(name);
|
||||
const viewExtensionManager = this.std.get(ViewExtensionManagerIdentifier);
|
||||
const previewSpec = viewExtensionManager.get(name);
|
||||
const currentDisposables = this.disposables;
|
||||
const editorSetting = this.std.getOptional(EditorSettingProvider) ?? {
|
||||
setting$: signal(GeneralSettingSchema.parse({})),
|
||||
@@ -157,13 +156,11 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
||||
}
|
||||
}
|
||||
|
||||
previewSpecBuilder.extend([
|
||||
return previewSpec.concat([
|
||||
EmbedSyncedDocWatcher,
|
||||
GfxViewportInitializer,
|
||||
EditorSettingExtension(editorSetting),
|
||||
]);
|
||||
|
||||
return previewSpecBuilder.value;
|
||||
};
|
||||
|
||||
protected _renderSyncedView = () => {
|
||||
@@ -204,7 +201,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
||||
<div class="affine-page-viewport" data-theme=${appTheme}>
|
||||
${new BlockStdScope({
|
||||
store: syncedDoc,
|
||||
extensions: this._buildPreviewSpec('preview:page'),
|
||||
extensions: this._buildPreviewSpec('preview-page'),
|
||||
}).render()}
|
||||
</div>
|
||||
`,
|
||||
@@ -215,7 +212,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
||||
<div class="affine-edgeless-viewport" data-theme=${edgelessTheme}>
|
||||
${new BlockStdScope({
|
||||
store: syncedDoc,
|
||||
extensions: this._buildPreviewSpec('preview:edgeless'),
|
||||
extensions: this._buildPreviewSpec('preview-edgeless'),
|
||||
}).render()}
|
||||
</div>
|
||||
`,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@blocksuite/affine-block-frame": "workspace:*",
|
||||
"@blocksuite/affine-block-surface": "workspace:*",
|
||||
"@blocksuite/affine-components": "workspace:*",
|
||||
"@blocksuite/affine-ext-loader": "workspace:*",
|
||||
"@blocksuite/affine-inline-reference": "workspace:*",
|
||||
"@blocksuite/affine-model": "workspace:*",
|
||||
"@blocksuite/affine-shared": "workspace:*",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { CanvasRenderer } from '@blocksuite/affine-block-surface';
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine-ext-loader';
|
||||
import type { NoteBlockModel } from '@blocksuite/affine-model';
|
||||
import {
|
||||
DefaultTheme,
|
||||
@@ -10,7 +11,6 @@ import {
|
||||
EDGELESS_BLOCK_CHILD_PADDING,
|
||||
} from '@blocksuite/affine-shared/consts';
|
||||
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
import { deserializeXYWH } from '@blocksuite/global/gfx';
|
||||
import { WithDisposable } from '@blocksuite/global/lit';
|
||||
import {
|
||||
@@ -122,10 +122,12 @@ export class SurfaceRefNotePortal extends WithDisposable(ShadowlessElement) {
|
||||
query: this.query,
|
||||
readonly: true,
|
||||
});
|
||||
const previewSpec = SpecProvider._.getSpec('preview:page');
|
||||
const previewSpec = this.host.std
|
||||
.get(ViewExtensionManagerIdentifier)
|
||||
.get('preview-page');
|
||||
return new BlockStdScope({
|
||||
store: doc,
|
||||
extensions: previewSpec.value.slice(),
|
||||
extensions: previewSpec,
|
||||
}).render();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import type { BlockCaptionEditor } from '@blocksuite/affine-components/caption';
|
||||
import { whenHover } from '@blocksuite/affine-components/hover';
|
||||
import { Peekable } from '@blocksuite/affine-components/peek';
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine-ext-loader';
|
||||
import { RefNodeSlotsProvider } from '@blocksuite/affine-inline-reference';
|
||||
import {
|
||||
FrameBlockModel,
|
||||
@@ -20,10 +21,7 @@ import {
|
||||
ViewportElementExtension,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
|
||||
import {
|
||||
requestConnectedFrame,
|
||||
SpecProvider,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { requestConnectedFrame } from '@blocksuite/affine-shared/utils';
|
||||
import { DisposableGroup } from '@blocksuite/global/disposable';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import {
|
||||
@@ -46,7 +44,7 @@ import {
|
||||
type GfxModel,
|
||||
GfxPrimitiveElementModel,
|
||||
} from '@blocksuite/std/gfx';
|
||||
import type { BaseSelection, Store } from '@blocksuite/store';
|
||||
import type { BaseSelection, ExtensionType, Store } from '@blocksuite/store';
|
||||
import { effect, signal } from '@preact/signals-core';
|
||||
import { css, html, nothing } from 'lit';
|
||||
import { query } from 'lit/decorators.js';
|
||||
@@ -114,9 +112,18 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
||||
|
||||
private _previewDoc: Store | null = null;
|
||||
|
||||
private readonly _previewSpec = SpecProvider._.getSpec(
|
||||
'preview:edgeless'
|
||||
).extend([ViewportElementExtension('.ref-viewport')]);
|
||||
private _runtimePreviewExt: ExtensionType[] = [];
|
||||
|
||||
private get _viewExtensionManager() {
|
||||
return this.std.get(ViewExtensionManagerIdentifier);
|
||||
}
|
||||
|
||||
private get _previewSpec() {
|
||||
return [
|
||||
...this._viewExtensionManager.get('preview-edgeless'),
|
||||
ViewportElementExtension('.ref-viewport'),
|
||||
];
|
||||
}
|
||||
|
||||
private _referencedModel: GfxModel | null = null;
|
||||
|
||||
@@ -338,7 +345,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
||||
}
|
||||
}
|
||||
|
||||
this._previewSpec.extend([SurfaceRefViewportWatcher]);
|
||||
this._runtimePreviewExt = [SurfaceRefViewportWatcher];
|
||||
}
|
||||
|
||||
private _initHover() {
|
||||
@@ -366,7 +373,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
||||
|
||||
private _renderRefContent(referencedModel: GfxModel) {
|
||||
const [, , w, h] = deserializeXYWH(referencedModel.xywh);
|
||||
const _previewSpec = this._previewSpec.value;
|
||||
const _previewSpec = this._previewSpec.concat(this._runtimePreviewExt);
|
||||
|
||||
return html`<div class="ref-content">
|
||||
<div
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
{ "path": "../frame" },
|
||||
{ "path": "../surface" },
|
||||
{ "path": "../../components" },
|
||||
{ "path": "../../ext-loader" },
|
||||
{ "path": "../../inlines/reference" },
|
||||
{ "path": "../../model" },
|
||||
{ "path": "../../shared" },
|
||||
|
||||
@@ -54,14 +54,17 @@ describe('multiple scopes', () => {
|
||||
class ViewExt1 extends ViewExtensionProvider {
|
||||
override name = 'ViewExt1';
|
||||
|
||||
override setup(context: ViewExtensionContext) {
|
||||
super.setup(context);
|
||||
constructor() {
|
||||
super();
|
||||
setup1();
|
||||
}
|
||||
|
||||
override setup(context: ViewExtensionContext, option?: { foo: number }) {
|
||||
super.setup(context, option);
|
||||
if (context.scope === 'page') {
|
||||
setup1();
|
||||
context.register(Ext2);
|
||||
}
|
||||
if (context.scope === 'edgeless') {
|
||||
setup2();
|
||||
context.register(Ext3);
|
||||
}
|
||||
}
|
||||
@@ -69,6 +72,11 @@ describe('multiple scopes', () => {
|
||||
class ViewExt2 extends ViewExtensionProvider {
|
||||
override name = 'ViewExt2';
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
setup2();
|
||||
}
|
||||
|
||||
override setup(context: ViewExtensionContext) {
|
||||
super.setup(context);
|
||||
if (context.scope === 'page') {
|
||||
@@ -87,7 +95,7 @@ describe('multiple scopes', () => {
|
||||
expect(edgelessExtensions).toEqual([Ext3, Ext5]);
|
||||
});
|
||||
|
||||
it('should setup be cached', () => {
|
||||
it('should cache provider instances', () => {
|
||||
manager.get('page');
|
||||
manager.get('edgeless');
|
||||
expect(setup1).toHaveBeenCalledTimes(1);
|
||||
|
||||
@@ -84,16 +84,17 @@ export class ExtensionManager<Scope extends string> {
|
||||
|
||||
/**
|
||||
* Retrieves all extensions registered for a specific scope.
|
||||
* If the scope hasn't been built yet, it triggers the build process.
|
||||
* It triggers the build process.
|
||||
*
|
||||
* @param scope - The scope to retrieve extensions for
|
||||
* @returns An array of extensions registered for the specified scope
|
||||
* @throws {BlockSuiteError} If the scope is not found
|
||||
*/
|
||||
get(scope: Scope) {
|
||||
if (!this._extensions.has(scope)) {
|
||||
this._build(scope);
|
||||
if (this._extensions.has(scope)) {
|
||||
this._extensions.delete(scope);
|
||||
}
|
||||
this._build(scope);
|
||||
const extensionSet = this._extensions.get(scope);
|
||||
if (!extensionSet) {
|
||||
throw new BlockSuiteError(
|
||||
@@ -117,14 +118,19 @@ export class ExtensionManager<Scope extends string> {
|
||||
provider: typeof BaseExtensionProvider<Scope, T>,
|
||||
options: ((prev: T | undefined) => T | undefined) | T | undefined
|
||||
) {
|
||||
const prev = this._providerOptions.get(provider);
|
||||
|
||||
let config: T | undefined;
|
||||
if (typeof options === 'function') {
|
||||
const prev = this._providerOptions.get(provider);
|
||||
config = (options as (prev: unknown) => T)(prev);
|
||||
} else {
|
||||
config = options;
|
||||
}
|
||||
|
||||
if (prev === config) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config === undefined) {
|
||||
this._providerOptions.delete(provider);
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@blocksuite/affine-block-frame": "workspace:*",
|
||||
"@blocksuite/affine-block-surface": "workspace:*",
|
||||
"@blocksuite/affine-components": "workspace:*",
|
||||
"@blocksuite/affine-ext-loader": "workspace:*",
|
||||
"@blocksuite/affine-model": "workspace:*",
|
||||
"@blocksuite/affine-rich-text": "workspace:*",
|
||||
"@blocksuite/affine-shared": "workspace:*",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine-ext-loader';
|
||||
import type { FrameBlockModel } from '@blocksuite/affine-model';
|
||||
import {
|
||||
DocModeExtension,
|
||||
DocModeProvider,
|
||||
ViewportElementExtension,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
import { DisposableGroup } from '@blocksuite/global/disposable';
|
||||
import { Bound, deserializeXYWH } from '@blocksuite/global/gfx';
|
||||
import { WithDisposable } from '@blocksuite/global/lit';
|
||||
@@ -15,13 +15,12 @@ import {
|
||||
ShadowlessElement,
|
||||
} from '@blocksuite/std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
|
||||
import { type Query, type Store } from '@blocksuite/store';
|
||||
import { type ExtensionType, type Query, type Store } from '@blocksuite/store';
|
||||
import { css, html, nothing, type PropertyValues } from 'lit';
|
||||
import { property, query, state } from 'lit/decorators.js';
|
||||
import { guard } from 'lit/directives/guard.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import debounce from 'lodash-es/debounce';
|
||||
|
||||
const DEFAULT_PREVIEW_CONTAINER_WIDTH = 280;
|
||||
const DEFAULT_PREVIEW_CONTAINER_HEIGHT = 166;
|
||||
|
||||
@@ -86,7 +85,15 @@ export class FramePreview extends WithDisposable(ShadowlessElement) {
|
||||
|
||||
private _previewDoc: Store | null = null;
|
||||
|
||||
private readonly _previewSpec = SpecProvider._.getSpec('preview:edgeless');
|
||||
private _runtimePreviewExt: ExtensionType[] = [];
|
||||
|
||||
private get _viewExtensionManager() {
|
||||
return this.std.get(ViewExtensionManagerIdentifier);
|
||||
}
|
||||
|
||||
private get _previewSpec() {
|
||||
return this._viewExtensionManager.get('preview-edgeless');
|
||||
}
|
||||
|
||||
private readonly _updateFrameViewportWH = () => {
|
||||
const [, , w, h] = deserializeXYWH(this.frame.xywh);
|
||||
@@ -143,11 +150,11 @@ export class FramePreview extends WithDisposable(ShadowlessElement) {
|
||||
}
|
||||
|
||||
const docModeService = this.std.get(DocModeProvider);
|
||||
this._previewSpec.extend([
|
||||
this._runtimePreviewExt = [
|
||||
ViewportElementExtension('.frame-preview-viewport'),
|
||||
FramePreviewWatcher,
|
||||
DocModeExtension(docModeService),
|
||||
]);
|
||||
];
|
||||
}
|
||||
|
||||
private _refreshViewport() {
|
||||
@@ -163,7 +170,7 @@ export class FramePreview extends WithDisposable(ShadowlessElement) {
|
||||
private _renderSurfaceContent() {
|
||||
const { width, height } = this.frameViewportWH;
|
||||
|
||||
const _previewSpec = this._previewSpec.value;
|
||||
const _previewSpec = this._previewSpec.concat(this._runtimePreviewExt);
|
||||
return html`<div
|
||||
class="frame-preview-surface-container"
|
||||
style=${styleMap({
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
{ "path": "../../blocks/frame" },
|
||||
{ "path": "../../blocks/surface" },
|
||||
{ "path": "../../components" },
|
||||
{ "path": "../../ext-loader" },
|
||||
{ "path": "../../model" },
|
||||
{ "path": "../../rich-text" },
|
||||
{ "path": "../../shared" },
|
||||
|
||||
@@ -35,7 +35,7 @@ export function EditorSettingExtension(
|
||||
): ExtensionType {
|
||||
return {
|
||||
setup: di => {
|
||||
di.addImpl(EditorSettingProvider, () => service);
|
||||
di.override(EditorSettingProvider, () => service);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"@blocksuite/affine-block-paragraph": "workspace:*",
|
||||
"@blocksuite/affine-block-surface": "workspace:*",
|
||||
"@blocksuite/affine-components": "workspace:*",
|
||||
"@blocksuite/affine-ext-loader": "workspace:*",
|
||||
"@blocksuite/affine-model": "workspace:*",
|
||||
"@blocksuite/affine-shared": "workspace:*",
|
||||
"@blocksuite/global": "workspace:*",
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ViewExtensionManagerIdentifier } from '@blocksuite/affine-ext-loader';
|
||||
import {
|
||||
DocModeExtension,
|
||||
DocModeProvider,
|
||||
EditorSettingExtension,
|
||||
EditorSettingProvider,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
import { BlockStdScope, BlockViewIdentifier } from '@blocksuite/std';
|
||||
import type {
|
||||
BlockModel,
|
||||
@@ -69,7 +69,9 @@ export class PreviewHelper {
|
||||
const editorSetting = std.get(EditorSettingProvider);
|
||||
const query = this._calculateQuery(blockIds as string[]);
|
||||
const store = widget.doc.doc.getStore({ query });
|
||||
const previewSpec = SpecProvider._.getSpec('preview:page');
|
||||
let previewSpec = widget.std
|
||||
.get(ViewExtensionManagerIdentifier)
|
||||
.get('preview-page');
|
||||
const settingSignal = signal({ ...editorSetting.setting$.peek() });
|
||||
const extensions = [
|
||||
DocModeExtension(docModeService),
|
||||
@@ -99,7 +101,7 @@ export class PreviewHelper {
|
||||
} as ExtensionType,
|
||||
];
|
||||
|
||||
previewSpec.extend(extensions);
|
||||
previewSpec = previewSpec.concat(extensions);
|
||||
|
||||
settingSignal.value = {
|
||||
...settingSignal.value,
|
||||
@@ -108,7 +110,7 @@ export class PreviewHelper {
|
||||
|
||||
const previewStd = new BlockStdScope({
|
||||
store,
|
||||
extensions: previewSpec.value,
|
||||
extensions: previewSpec,
|
||||
});
|
||||
|
||||
let width: number = 500;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
{ "path": "../../blocks/paragraph" },
|
||||
{ "path": "../../blocks/surface" },
|
||||
{ "path": "../../components" },
|
||||
{ "path": "../../ext-loader" },
|
||||
{ "path": "../../model" },
|
||||
{ "path": "../../shared" },
|
||||
{ "path": "../../../framework/global" },
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
},
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./effects": "./src/effects.ts"
|
||||
"./effects": "./src/effects.ts",
|
||||
"./store": "./src/store.ts",
|
||||
"./view": "./src/view.ts"
|
||||
},
|
||||
"files": [
|
||||
"src",
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import '@toeverything/theme/style.css';
|
||||
import '@toeverything/theme/fonts.css';
|
||||
|
||||
import { effects as blocksEffects } from '@blocksuite/affine/effects';
|
||||
import {
|
||||
EdgelessEditorBlockSpecs,
|
||||
PageEditorBlockSpecs,
|
||||
registerStoreSpecs,
|
||||
StoreExtensions,
|
||||
} from '@blocksuite/affine/extensions';
|
||||
import { registerStoreSpecs } from '@blocksuite/affine/extensions';
|
||||
import type { DocMode } from '@blocksuite/affine/model';
|
||||
import { AffineSchemas } from '@blocksuite/affine/schemas';
|
||||
import {
|
||||
@@ -27,11 +21,17 @@ import {
|
||||
|
||||
import { effects } from '../../effects.js';
|
||||
import { TestAffineEditorContainer } from '../../index.js';
|
||||
import { getTestStoreManager } from '../../store.js';
|
||||
import { getTestViewManager } from '../../view.js';
|
||||
|
||||
// FIXME: used for test import/export
|
||||
registerStoreSpecs();
|
||||
blocksEffects();
|
||||
const storeManager = getTestStoreManager();
|
||||
const viewManager = getTestViewManager();
|
||||
effects();
|
||||
|
||||
const storeExtensions = storeManager.get('store');
|
||||
|
||||
export function getRenderer() {
|
||||
return editor.std.get(
|
||||
ViewportTurboRendererIdentifier
|
||||
@@ -85,12 +85,12 @@ async function createEditor(
|
||||
editor.doc = doc;
|
||||
editor.mode = mode;
|
||||
editor.pageSpecs = [
|
||||
...PageEditorBlockSpecs,
|
||||
...viewManager.get('page'),
|
||||
FontConfigExtension(CommunityCanvasTextFonts),
|
||||
...extensions,
|
||||
];
|
||||
editor.edgelessSpecs = [
|
||||
...EdgelessEditorBlockSpecs,
|
||||
...viewManager.get('edgeless'),
|
||||
FontConfigExtension(CommunityCanvasTextFonts),
|
||||
...extensions,
|
||||
];
|
||||
@@ -123,7 +123,7 @@ export async function setupEditor(
|
||||
extensions: ExtensionType[] = []
|
||||
) {
|
||||
const collection = new TestWorkspace(createCollectionOptions());
|
||||
collection.storeExtensions = StoreExtensions;
|
||||
collection.storeExtensions = storeExtensions;
|
||||
collection.meta.initialize();
|
||||
|
||||
window.collection = collection;
|
||||
|
||||
7
blocksuite/integration-test/src/store.ts
Normal file
7
blocksuite/integration-test/src/store.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { StoreExtensionManager } from '@blocksuite/affine/ext-loader';
|
||||
import { MigratingStoreExtension } from '@blocksuite/affine/extensions/store';
|
||||
|
||||
export function getTestStoreManager() {
|
||||
const manager = new StoreExtensionManager([MigratingStoreExtension]);
|
||||
return manager;
|
||||
}
|
||||
7
blocksuite/integration-test/src/view.ts
Normal file
7
blocksuite/integration-test/src/view.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { ViewExtensionManager } from '@blocksuite/affine/ext-loader';
|
||||
import { MigratingViewExtension } from '@blocksuite/affine/extensions/view';
|
||||
|
||||
export function getTestViewManager() {
|
||||
const manager = new ViewExtensionManager([MigratingViewExtension]);
|
||||
return manager;
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import '../../style.css';
|
||||
|
||||
import * as databaseBlocks from '@blocksuite/affine/blocks/database';
|
||||
import * as noteBlocks from '@blocksuite/affine/blocks/note';
|
||||
import { effects as blocksEffects } from '@blocksuite/affine/effects';
|
||||
import { registerStoreSpecs } from '@blocksuite/affine/extensions';
|
||||
import * as globalUtils from '@blocksuite/affine/global/utils';
|
||||
import * as services from '@blocksuite/affine/shared/services';
|
||||
@@ -10,7 +9,8 @@ import * as blockStd from '@blocksuite/affine/std';
|
||||
import * as store from '@blocksuite/affine/store';
|
||||
import * as affineModel from '@blocksuite/affine-model';
|
||||
import * as editor from '@blocksuite/integration-test';
|
||||
import { effects as presetsEffects } from '@blocksuite/integration-test/effects';
|
||||
import { effects as itEffects } from '@blocksuite/integration-test/effects';
|
||||
import { getTestStoreManager } from '@blocksuite/integration-test/store';
|
||||
|
||||
import { setupEdgelessTemplate } from '../_common/setup.js';
|
||||
import { effects as commentEffects } from '../comment/effects.js';
|
||||
@@ -22,8 +22,8 @@ import { mountDefaultDocEditor } from './utils/setup-playground';
|
||||
import { prepareTestApp } from './utils/test';
|
||||
|
||||
registerStoreSpecs();
|
||||
blocksEffects();
|
||||
presetsEffects();
|
||||
itEffects();
|
||||
const storeManager = getTestStoreManager();
|
||||
commentEffects();
|
||||
|
||||
async function main() {
|
||||
@@ -34,7 +34,7 @@ async function main() {
|
||||
const params = new URLSearchParams(location.search);
|
||||
const room = params.get('room') ?? Math.random().toString(16).slice(2, 8);
|
||||
const isE2E = room.startsWith('playwright');
|
||||
const collection = createStarterDocCollection();
|
||||
const collection = createStarterDocCollection(storeManager);
|
||||
|
||||
if (isE2E) {
|
||||
Object.defineProperty(window, '$blocksuite', {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { StoreExtensionManager } from '@blocksuite/affine/ext-loader';
|
||||
import { AffineSchemas } from '@blocksuite/affine/schemas';
|
||||
import { SpecProvider } from '@blocksuite/affine/shared/utils';
|
||||
import { nanoid, Schema, Transformer } from '@blocksuite/affine/store';
|
||||
import {
|
||||
createAutoIncrementIdGenerator,
|
||||
@@ -23,7 +23,9 @@ const room = params.get('room');
|
||||
const isE2E = room?.startsWith('playwright');
|
||||
const blobSourceArgs = (params.get('blobSource') ?? '').split(',');
|
||||
|
||||
export function createStarterDocCollection() {
|
||||
export function createStarterDocCollection(
|
||||
storeExtensionManager: StoreExtensionManager
|
||||
) {
|
||||
const collectionId = room ?? 'starter';
|
||||
const schema = new Schema();
|
||||
schema.register(AffineSchemas);
|
||||
@@ -56,7 +58,7 @@ export function createStarterDocCollection() {
|
||||
blobSources,
|
||||
};
|
||||
const collection = new TestWorkspace(options);
|
||||
collection.storeExtensions = SpecProvider._.getSpec('store').value;
|
||||
collection.storeExtensions = storeExtensionManager.get('store');
|
||||
collection.start();
|
||||
|
||||
// debug info
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import {
|
||||
EdgelessEditorBlockSpecs,
|
||||
PageEditorBlockSpecs,
|
||||
} from '@blocksuite/affine/extensions';
|
||||
import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
||||
import {
|
||||
CommunityCanvasTextFonts,
|
||||
@@ -13,6 +9,7 @@ import {
|
||||
} from '@blocksuite/affine/shared/services';
|
||||
import type { ExtensionType, Store, Workspace } from '@blocksuite/affine/store';
|
||||
import { type TestAffineEditorContainer } from '@blocksuite/integration-test';
|
||||
import { getTestViewManager } from '@blocksuite/integration-test/view';
|
||||
|
||||
import {
|
||||
mockDocModeService,
|
||||
@@ -20,6 +17,8 @@ import {
|
||||
mockParseDocUrlService,
|
||||
} from '../../_common/mock-services';
|
||||
|
||||
const viewManager = getTestViewManager();
|
||||
|
||||
export function getTestCommonExtensions(
|
||||
editor: TestAffineEditorContainer
|
||||
): ExtensionType[] {
|
||||
@@ -48,8 +47,8 @@ export function createTestEditor(store: Store, workspace: Workspace) {
|
||||
editor.doc = store;
|
||||
|
||||
const defaultExtensions = getTestCommonExtensions(editor);
|
||||
editor.pageSpecs = [...PageEditorBlockSpecs, ...defaultExtensions];
|
||||
editor.edgelessSpecs = [...EdgelessEditorBlockSpecs, ...defaultExtensions];
|
||||
editor.pageSpecs = [...viewManager.get('page'), ...defaultExtensions];
|
||||
editor.edgelessSpecs = [...viewManager.get('edgeless'), ...defaultExtensions];
|
||||
|
||||
editor.std
|
||||
.get(RefNodeSlotsProvider)
|
||||
|
||||
Reference in New Issue
Block a user