mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-19 02:56:23 +08:00
refactor: move image proxy middleware and adapter extensions (#10345)
### TL;DR Moved image proxy middleware and adapter extensions to their respective packages and introduced a new spec provider for adapter registration. ### What changed? - Relocated `defaultImageProxyMiddleware` from blocks to `@blocksuite/affine-block-image` - Moved `PresentTool` from fragment-frame-panel to block-frame - Created new adapter extension specs for HTML, Markdown, and Notion HTML - Introduced a spec provider pattern for adapter registration - Removed direct transformer references from RootService - Updated imports across affected files to use new locations ### How to test? 1. Verify image proxy functionality works in exports and imports 2. Test HTML, Markdown, and Notion HTML adapters still function correctly 3. Confirm presentation mode works with the relocated PresentTool 4. Check that all file import/export operations continue to work as expected ### Why make this change? This reorganization improves code modularity by placing features in their logical packages and introduces a more maintainable pattern for adapter registration. The spec provider pattern makes it easier to manage and extend adapter functionality while reducing coupling between components.
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import { DatabaseBlockSchema } from '@blocksuite/affine-model';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
BlockNotionHtmlAdapterExtension,
|
||||
type BlockNotionHtmlAdapterMatcher,
|
||||
HastUtils,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { getTagColor } from '@blocksuite/data-view';
|
||||
import { type BlockSnapshot, nanoid } from '@blocksuite/store';
|
||||
@@ -219,7 +219,7 @@ export const databaseBlockNotionHtmlAdapterMatcher: BlockNotionHtmlAdapterMatche
|
||||
column.type = 'rich-text';
|
||||
row[column.id] = {
|
||||
columnId: column.id,
|
||||
value: TextUtils.createText(text),
|
||||
value: AdapterTextUtils.createText(text),
|
||||
};
|
||||
} else {
|
||||
row[column.id] = {
|
||||
@@ -235,11 +235,11 @@ export const databaseBlockNotionHtmlAdapterMatcher: BlockNotionHtmlAdapterMatche
|
||||
}
|
||||
if (
|
||||
column.type === 'rich-text' &&
|
||||
!TextUtils.isText(row[column.id].value)
|
||||
!AdapterTextUtils.isText(row[column.id].value)
|
||||
) {
|
||||
row[column.id] = {
|
||||
columnId: column.id,
|
||||
value: TextUtils.createText(row[column.id].value),
|
||||
value: AdapterTextUtils.createText(row[column.id].value),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -197,7 +197,7 @@ async function renderNoteContent(
|
||||
match: ids.map(id => ({ id, viewType: 'display' })),
|
||||
};
|
||||
const previewDoc = doc.doc.getStore({ query });
|
||||
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
||||
const previewSpec = SpecProvider.getInstance().getSpec('preview:page');
|
||||
const previewStd = new BlockStdScope({
|
||||
store: previewDoc,
|
||||
extensions: previewSpec.value,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
BlockHtmlAdapterExtension,
|
||||
type BlockHtmlAdapterMatcher,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
|
||||
export const embedLinkedDocBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
||||
@@ -18,7 +18,7 @@ export const embedLinkedDocBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
||||
return;
|
||||
}
|
||||
const title = configs.get('title:' + o.node.props.pageId) ?? 'untitled';
|
||||
const url = TextUtils.generateDocUrl(
|
||||
const url = AdapterTextUtils.generateDocUrl(
|
||||
configs.get('docLinkBaseUrl') ?? '',
|
||||
String(o.node.props.pageId),
|
||||
o.node.props.params ?? Object.create(null)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
BlockMarkdownAdapterExtension,
|
||||
type BlockMarkdownAdapterMatcher,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
|
||||
export const embedLinkedDocBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher =
|
||||
@@ -19,7 +19,7 @@ export const embedLinkedDocBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatc
|
||||
return;
|
||||
}
|
||||
const title = configs.get('title:' + o.node.props.pageId) ?? 'untitled';
|
||||
const url = TextUtils.generateDocUrl(
|
||||
const url = AdapterTextUtils.generateDocUrl(
|
||||
configs.get('docLinkBaseUrl') ?? '',
|
||||
String(o.node.props.pageId),
|
||||
o.node.props.params ?? Object.create(null)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { EmbedLinkedDocBlockSchema } from '@blocksuite/affine-model';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
BlockPlainTextAdapterExtension,
|
||||
type BlockPlainTextAdapterMatcher,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
|
||||
export const embedLinkedDocBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMatcher =
|
||||
@@ -19,7 +19,7 @@ export const embedLinkedDocBlockPlainTextAdapterMatcher: BlockPlainTextAdapterMa
|
||||
return;
|
||||
}
|
||||
const title = configs.get('title:' + o.node.props.pageId) ?? 'untitled';
|
||||
const url = TextUtils.generateDocUrl(
|
||||
const url = AdapterTextUtils.generateDocUrl(
|
||||
configs.get('docLinkBaseUrl') ?? '',
|
||||
String(o.node.props.pageId),
|
||||
o.node.props.params ?? Object.create(null)
|
||||
|
||||
+2
-2
@@ -70,7 +70,7 @@ export class EmbedEdgelessSyncedDocBlockComponent extends toEdgelessEmbedBlock(
|
||||
<div class="affine-page-viewport" data-theme=${appTheme}>
|
||||
${new BlockStdScope({
|
||||
store: syncedDoc,
|
||||
extensions: this._buildPreviewSpec('page:preview'),
|
||||
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('edgeless:preview'),
|
||||
extensions: this._buildPreviewSpec('preview:edgeless'),
|
||||
}).render()}
|
||||
</div>
|
||||
`,
|
||||
|
||||
@@ -116,7 +116,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
||||
],
|
||||
};
|
||||
|
||||
protected _buildPreviewSpec = (name: 'page:preview' | 'edgeless:preview') => {
|
||||
protected _buildPreviewSpec = (name: 'preview:page' | 'preview:edgeless') => {
|
||||
const nextDepth = this.depth + 1;
|
||||
const previewSpecBuilder = SpecProvider.getInstance().getSpec(name);
|
||||
const currentDisposables = this.disposables;
|
||||
@@ -203,7 +203,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
||||
<div class="affine-page-viewport" data-theme=${appTheme}>
|
||||
${new BlockStdScope({
|
||||
store: syncedDoc,
|
||||
extensions: this._buildPreviewSpec('page:preview'),
|
||||
extensions: this._buildPreviewSpec('preview:page'),
|
||||
}).render()}
|
||||
</div>
|
||||
`,
|
||||
@@ -214,7 +214,7 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
|
||||
<div class="affine-edgeless-viewport" data-theme=${edgelessTheme}>
|
||||
${new BlockStdScope({
|
||||
store: syncedDoc,
|
||||
extensions: this._buildPreviewSpec('edgeless:preview'),
|
||||
extensions: this._buildPreviewSpec('preview:edgeless'),
|
||||
}).render()}
|
||||
</div>
|
||||
`,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './frame-block.js';
|
||||
export * from './frame-manager.js';
|
||||
export * from './frame-spec.js';
|
||||
export * from './tool.js';
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
import type { NavigatorMode } from '@blocksuite/affine-block-frame';
|
||||
import { BaseTool } from '@blocksuite/block-std/gfx';
|
||||
|
||||
import type { NavigatorMode } from './frame-manager';
|
||||
|
||||
type PresentToolOption = {
|
||||
mode?: NavigatorMode;
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './html.js';
|
||||
export * from './markdown.js';
|
||||
export * from './middleware.js';
|
||||
export * from './notion-html.js';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ListBlockSchema } from '@blocksuite/affine-model';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
BlockHtmlAdapterExtension,
|
||||
type BlockHtmlAdapterMatcher,
|
||||
HastUtils,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { DeltaInsert } from '@blocksuite/inline';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
@@ -124,7 +124,7 @@ export const listBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
||||
Array.isArray(currentTNode.properties.className) &&
|
||||
currentTNode.properties.className.includes('todo-list')
|
||||
) ===
|
||||
TextUtils.isNullish(
|
||||
AdapterTextUtils.isNullish(
|
||||
o.node.props.type === 'todo'
|
||||
? (o.node.props.checked as boolean)
|
||||
: undefined
|
||||
@@ -177,7 +177,7 @@ export const listBlockHtmlAdapterMatcher: BlockHtmlAdapterMatcher = {
|
||||
Array.isArray(previousTNode.properties.className) &&
|
||||
previousTNode.properties.className.includes('todo-list')
|
||||
) ===
|
||||
TextUtils.isNullish(
|
||||
AdapterTextUtils.isNullish(
|
||||
o.node.props.type === 'todo'
|
||||
? (o.node.props.checked as boolean)
|
||||
: undefined
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ListBlockSchema } from '@blocksuite/affine-model';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
BlockMarkdownAdapterExtension,
|
||||
type BlockMarkdownAdapterMatcher,
|
||||
type MarkdownAST,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { DeltaInsert } from '@blocksuite/inline';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
@@ -75,8 +75,8 @@ export const listBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
||||
walkerContext.getNodeContext('affine:list:parent') === o.parent &&
|
||||
currentTNode.type === 'list' &&
|
||||
currentTNode.ordered === (o.node.props.type === 'numbered') &&
|
||||
TextUtils.isNullish(currentTNode.children[0].checked) ===
|
||||
TextUtils.isNullish(
|
||||
AdapterTextUtils.isNullish(currentTNode.children[0].checked) ===
|
||||
AdapterTextUtils.isNullish(
|
||||
o.node.props.type === 'todo'
|
||||
? (o.node.props.checked as boolean)
|
||||
: undefined
|
||||
@@ -129,8 +129,8 @@ export const listBlockMarkdownAdapterMatcher: BlockMarkdownAdapterMatcher = {
|
||||
currentTNode.type === 'listItem' &&
|
||||
previousTNode?.type === 'list' &&
|
||||
previousTNode.ordered === (o.node.props.type === 'numbered') &&
|
||||
TextUtils.isNullish(currentTNode.checked) ===
|
||||
TextUtils.isNullish(
|
||||
AdapterTextUtils.isNullish(currentTNode.checked) ===
|
||||
AdapterTextUtils.isNullish(
|
||||
o.node.props.type === 'todo'
|
||||
? (o.node.props.checked as boolean)
|
||||
: undefined
|
||||
|
||||
@@ -118,7 +118,7 @@ export class SurfaceRefNotePortal extends WithDisposable(ShadowlessElement) {
|
||||
query: this.query,
|
||||
readonly: true,
|
||||
});
|
||||
const previewSpec = SpecProvider.getInstance().getSpec('page:preview');
|
||||
const previewSpec = SpecProvider.getInstance().getSpec('preview:page');
|
||||
return new BlockStdScope({
|
||||
store: doc,
|
||||
extensions: previewSpec.value.slice(),
|
||||
|
||||
@@ -240,7 +240,7 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
|
||||
private _previewDoc: Store | null = null;
|
||||
|
||||
private readonly _previewSpec =
|
||||
SpecProvider.getInstance().getSpec('edgeless:preview');
|
||||
SpecProvider.getInstance().getSpec('preview:edgeless');
|
||||
|
||||
private _referencedModel: GfxModel | null = null;
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ import type {
|
||||
TableColumn,
|
||||
TableRow,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { HastUtils, TextUtils } from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
HastUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { generateFractionalIndexingKeyBetween } from '@blocksuite/affine-shared/utils';
|
||||
import type { DeltaInsert } from '@blocksuite/inline';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
@@ -155,7 +158,7 @@ export const createTableProps = (rowTextLists: string[][]) => {
|
||||
const cellId = `${row.rowId}:${column.columnId}`;
|
||||
const text = rowTextLists[i]?.[j];
|
||||
cells[cellId] = {
|
||||
text: TextUtils.createText(text ?? ''),
|
||||
text: AdapterTextUtils.createText(text ?? ''),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { InlineHtmlAST } from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
InlineDeltaToHtmlAdapterExtension,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { ThemeProvider } from '@blocksuite/affine-shared/services';
|
||||
|
||||
@@ -90,7 +90,7 @@ export const referenceDeltaToHtmlAdapterMatcher =
|
||||
|
||||
const { configs } = context;
|
||||
const title = configs.get(`title:${reference.pageId}`);
|
||||
const url = TextUtils.generateDocUrl(
|
||||
const url = AdapterTextUtils.generateDocUrl(
|
||||
configs.get('docLinkBaseUrl') ?? '',
|
||||
String(reference.pageId),
|
||||
reference.params ?? Object.create(null)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
FOOTNOTE_DEFINITION_PREFIX,
|
||||
InlineDeltaToMarkdownAdapterExtension,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { PhrasingContent } from 'mdast';
|
||||
import type RemarkMath from 'remark-math';
|
||||
@@ -74,7 +74,7 @@ export const referenceDeltaToMarkdownAdapterMatcher =
|
||||
const { configs } = context;
|
||||
const title = configs.get(`title:${reference.pageId}`);
|
||||
const params = reference.params ?? {};
|
||||
const url = TextUtils.generateDocUrl(
|
||||
const url = AdapterTextUtils.generateDocUrl(
|
||||
configs.get('docLinkBaseUrl') ?? '',
|
||||
String(reference.pageId),
|
||||
params
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
AdapterTextUtils,
|
||||
InlineDeltaToPlainTextAdapterExtension,
|
||||
type TextBuffer,
|
||||
TextUtils,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
@@ -20,7 +20,7 @@ export const referenceDeltaMarkdownAdapterMatch =
|
||||
|
||||
const { configs } = context;
|
||||
const title = configs.get(`title:${reference.pageId}`) ?? '';
|
||||
const url = TextUtils.generateDocUrl(
|
||||
const url = AdapterTextUtils.generateDocUrl(
|
||||
configs.get('docLinkBaseUrl') ?? '',
|
||||
String(reference.pageId),
|
||||
reference.params ?? Object.create(null)
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './frame-panel';
|
||||
export * from './tool';
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import type { GfxModel } from '@blocksuite/block-std/gfx';
|
||||
|
||||
import type {
|
||||
BrushElementModel,
|
||||
ConnectorElementModel,
|
||||
GroupElementModel,
|
||||
} from '../elements';
|
||||
|
||||
export type EmbedCardStyle =
|
||||
| 'horizontal'
|
||||
| 'horizontalThin'
|
||||
@@ -17,3 +25,8 @@ export type LinkPreviewData = {
|
||||
image: string | null;
|
||||
title: string | null;
|
||||
};
|
||||
|
||||
export type Connectable = Exclude<
|
||||
GfxModel,
|
||||
ConnectorElementModel | BrushElementModel | GroupElementModel
|
||||
>;
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
type InlineDeltaMatcher,
|
||||
} from '../types/adapter.js';
|
||||
import type { HtmlAST, InlineHtmlAST } from '../types/hast.js';
|
||||
import { TextUtils } from '../utils/text.js';
|
||||
import { AdapterTextUtils } from '../utils/text.js';
|
||||
|
||||
export type InlineDeltaToHtmlAdapterMatcher = InlineDeltaMatcher<InlineHtmlAST>;
|
||||
|
||||
@@ -119,7 +119,7 @@ export class HtmlDeltaConverter extends DeltaASTConverter<
|
||||
options: DeltaASTConverterOptions = Object.create(null)
|
||||
): DeltaInsert<AffineTextAttributes>[] {
|
||||
return this._spreadAstToDelta(ast, options).reduce((acc, cur) => {
|
||||
return TextUtils.mergeDeltas(acc, cur);
|
||||
return AdapterTextUtils.mergeDeltas(acc, cur);
|
||||
}, [] as DeltaInsert<AffineTextAttributes>[]);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import type { TransformerMiddleware } from '@blocksuite/store';
|
||||
|
||||
const customDocLinkBaseUrlMiddleware = (
|
||||
baseUrl: string,
|
||||
collectionId: string
|
||||
): TransformerMiddleware => {
|
||||
return ({ adapterConfigs }) => {
|
||||
const docLinkBaseUrl = baseUrl
|
||||
? `${baseUrl}/workspace/${collectionId}`
|
||||
: '';
|
||||
adapterConfigs.set('docLinkBaseUrl', docLinkBaseUrl);
|
||||
};
|
||||
};
|
||||
|
||||
export const docLinkBaseURLMiddlewareBuilder = (
|
||||
baseUrl: string,
|
||||
collectionId: string
|
||||
) => {
|
||||
let middleware = customDocLinkBaseUrlMiddleware(baseUrl, collectionId);
|
||||
return {
|
||||
get: () => middleware,
|
||||
set: (url: string) => {
|
||||
middleware = customDocLinkBaseUrlMiddleware(url, collectionId);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const defaultDocLinkBaseURLMiddlewareBuilder = (collectionId: string) =>
|
||||
docLinkBaseURLMiddlewareBuilder(
|
||||
typeof window !== 'undefined' ? window.location.origin : '.',
|
||||
collectionId
|
||||
);
|
||||
|
||||
export const docLinkBaseURLMiddleware = (collectionId: string) =>
|
||||
defaultDocLinkBaseURLMiddlewareBuilder(collectionId).get();
|
||||
|
||||
export const setDocLinkBaseURLMiddleware = (collectionId: string) =>
|
||||
defaultDocLinkBaseURLMiddlewareBuilder(collectionId).set;
|
||||
|
||||
export const embedSyncedDocMiddleware =
|
||||
(type: 'content'): TransformerMiddleware =>
|
||||
({ adapterConfigs }) => {
|
||||
adapterConfigs.set('embedSyncedDocExportType', type);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { TransformerMiddleware } from '@blocksuite/store';
|
||||
|
||||
export const fileNameMiddleware =
|
||||
(fileName?: string): TransformerMiddleware =>
|
||||
({ slots }) => {
|
||||
slots.beforeImport.on(payload => {
|
||||
if (payload.type !== 'page') {
|
||||
return;
|
||||
}
|
||||
if (!fileName) {
|
||||
return;
|
||||
}
|
||||
payload.snapshot.meta.title = fileName;
|
||||
payload.snapshot.blocks.props.title = {
|
||||
'$blocksuite:internal:text$': true,
|
||||
delta: [
|
||||
{
|
||||
insert: fileName,
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -1,4 +1,8 @@
|
||||
export * from './code';
|
||||
export * from './copy';
|
||||
export * from './doc-link';
|
||||
export * from './file-name';
|
||||
export * from './paste';
|
||||
export * from './replace-id';
|
||||
export * from './surface-ref-to-embed';
|
||||
export * from './title';
|
||||
|
||||
+1
-106
@@ -6,13 +6,8 @@ import type {
|
||||
ParagraphBlockModel,
|
||||
SurfaceRefBlockModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { DEFAULT_IMAGE_PROXY_ENDPOINT } from '@blocksuite/affine-shared/consts';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type {
|
||||
DeltaOperation,
|
||||
DocMeta,
|
||||
TransformerMiddleware,
|
||||
} from '@blocksuite/store';
|
||||
import type { DeltaOperation, TransformerMiddleware } from '@blocksuite/store';
|
||||
|
||||
export const replaceIdMiddleware =
|
||||
(idGenerator: () => string): TransformerMiddleware =>
|
||||
@@ -203,103 +198,3 @@ export const replaceIdMiddleware =
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const customImageProxyMiddleware = (
|
||||
imageProxyURL: string
|
||||
): TransformerMiddleware => {
|
||||
return ({ adapterConfigs }) => {
|
||||
adapterConfigs.set('imageProxy', imageProxyURL);
|
||||
};
|
||||
};
|
||||
|
||||
const customDocLinkBaseUrlMiddleware = (
|
||||
baseUrl: string,
|
||||
collectionId: string
|
||||
): TransformerMiddleware => {
|
||||
return ({ adapterConfigs }) => {
|
||||
const docLinkBaseUrl = baseUrl
|
||||
? `${baseUrl}/workspace/${collectionId}`
|
||||
: '';
|
||||
adapterConfigs.set('docLinkBaseUrl', docLinkBaseUrl);
|
||||
};
|
||||
};
|
||||
|
||||
export const titleMiddleware =
|
||||
(metas: DocMeta[]): TransformerMiddleware =>
|
||||
({ slots, adapterConfigs }) => {
|
||||
slots.beforeExport.on(() => {
|
||||
for (const meta of metas) {
|
||||
adapterConfigs.set('title:' + meta.id, meta.title);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const docLinkBaseURLMiddlewareBuilder = (
|
||||
baseUrl: string,
|
||||
collectionId: string
|
||||
) => {
|
||||
let middleware = customDocLinkBaseUrlMiddleware(baseUrl, collectionId);
|
||||
return {
|
||||
get: () => middleware,
|
||||
set: (url: string) => {
|
||||
middleware = customDocLinkBaseUrlMiddleware(url, collectionId);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const defaultDocLinkBaseURLMiddlewareBuilder = (collectionId: string) =>
|
||||
docLinkBaseURLMiddlewareBuilder(
|
||||
typeof window !== 'undefined' ? window.location.origin : '.',
|
||||
collectionId
|
||||
);
|
||||
|
||||
export const docLinkBaseURLMiddleware = (collectionId: string) =>
|
||||
defaultDocLinkBaseURLMiddlewareBuilder(collectionId).get();
|
||||
|
||||
export const setDocLinkBaseURLMiddleware = (collectionId: string) =>
|
||||
defaultDocLinkBaseURLMiddlewareBuilder(collectionId).set;
|
||||
|
||||
const imageProxyMiddlewareBuilder = () => {
|
||||
let middleware = customImageProxyMiddleware(DEFAULT_IMAGE_PROXY_ENDPOINT);
|
||||
return {
|
||||
get: () => middleware,
|
||||
set: (url: string) => {
|
||||
middleware = customImageProxyMiddleware(url);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const defaultImageProxyMiddlewarBuilder = imageProxyMiddlewareBuilder();
|
||||
|
||||
export const setImageProxyMiddlewareURL = defaultImageProxyMiddlewarBuilder.set;
|
||||
|
||||
export const defaultImageProxyMiddleware =
|
||||
defaultImageProxyMiddlewarBuilder.get();
|
||||
|
||||
export const embedSyncedDocMiddleware =
|
||||
(type: 'content'): TransformerMiddleware =>
|
||||
({ adapterConfigs }) => {
|
||||
adapterConfigs.set('embedSyncedDocExportType', type);
|
||||
};
|
||||
|
||||
export const fileNameMiddleware =
|
||||
(fileName?: string): TransformerMiddleware =>
|
||||
({ slots }) => {
|
||||
slots.beforeImport.on(payload => {
|
||||
if (payload.type !== 'page') {
|
||||
return;
|
||||
}
|
||||
if (!fileName) {
|
||||
return;
|
||||
}
|
||||
payload.snapshot.meta.title = fileName;
|
||||
payload.snapshot.blocks.props.title = {
|
||||
'$blocksuite:internal:text$': true,
|
||||
delta: [
|
||||
{
|
||||
insert: fileName,
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { DocMeta, TransformerMiddleware } from '@blocksuite/store';
|
||||
|
||||
export const titleMiddleware =
|
||||
(metas: DocMeta[]): TransformerMiddleware =>
|
||||
({ slots, adapterConfigs }) => {
|
||||
slots.beforeExport.on(() => {
|
||||
for (const meta of metas) {
|
||||
adapterConfigs.set('title:' + meta.id, meta.title);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -86,7 +86,7 @@ function generateDocUrl(
|
||||
return url;
|
||||
}
|
||||
|
||||
export const TextUtils = {
|
||||
export const AdapterTextUtils = {
|
||||
mergeDeltas,
|
||||
isNullish,
|
||||
createText,
|
||||
|
||||
@@ -3,10 +3,17 @@ import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import { SpecBuilder } from './spec-builder.js';
|
||||
|
||||
type SpecId =
|
||||
| 'store'
|
||||
| 'page'
|
||||
| 'edgeless'
|
||||
| 'preview:page'
|
||||
| 'preview:edgeless';
|
||||
|
||||
export class SpecProvider {
|
||||
static instance: SpecProvider;
|
||||
|
||||
private readonly specMap = new Map<string, ExtensionType[]>();
|
||||
private readonly specMap = new Map<SpecId, ExtensionType[]>();
|
||||
|
||||
private constructor() {}
|
||||
|
||||
@@ -17,17 +24,17 @@ export class SpecProvider {
|
||||
return SpecProvider.instance;
|
||||
}
|
||||
|
||||
addSpec(id: string, spec: ExtensionType[]) {
|
||||
addSpec(id: SpecId, spec: ExtensionType[]) {
|
||||
if (!this.specMap.has(id)) {
|
||||
this.specMap.set(id, spec);
|
||||
}
|
||||
}
|
||||
|
||||
clearSpec(id: string) {
|
||||
clearSpec(id: SpecId) {
|
||||
this.specMap.delete(id);
|
||||
}
|
||||
|
||||
extendSpec(id: string, newSpec: ExtensionType[]) {
|
||||
extendSpec(id: SpecId, newSpec: ExtensionType[]) {
|
||||
const existingSpec = this.specMap.get(id);
|
||||
if (!existingSpec) {
|
||||
console.error(`Spec not found for ${id}`);
|
||||
@@ -36,26 +43,17 @@ export class SpecProvider {
|
||||
this.specMap.set(id, [...existingSpec, ...newSpec]);
|
||||
}
|
||||
|
||||
getSpec(id: string) {
|
||||
getSpec(id: SpecId) {
|
||||
const spec = this.specMap.get(id);
|
||||
assertExists(spec, `Spec not found for ${id}`);
|
||||
return new SpecBuilder(spec);
|
||||
}
|
||||
|
||||
hasSpec(id: string) {
|
||||
hasSpec(id: SpecId) {
|
||||
return this.specMap.has(id);
|
||||
}
|
||||
|
||||
cloneSpec(id: string, targetId: string) {
|
||||
const existingSpec = this.specMap.get(id);
|
||||
if (!existingSpec) {
|
||||
console.error(`Spec not found for ${id}`);
|
||||
return;
|
||||
}
|
||||
this.specMap.set(targetId, [...existingSpec]);
|
||||
}
|
||||
|
||||
omitSpec(id: string, targetSpec: ExtensionType) {
|
||||
omitSpec(id: SpecId, targetSpec: ExtensionType) {
|
||||
const existingSpec = this.specMap.get(id);
|
||||
if (!existingSpec) {
|
||||
console.error(`Spec not found for ${id}`);
|
||||
@@ -68,7 +66,7 @@ export class SpecProvider {
|
||||
);
|
||||
}
|
||||
|
||||
replaceSpec(id: string, targetSpec: ExtensionType, newSpec: ExtensionType) {
|
||||
replaceSpec(id: SpecId, targetSpec: ExtensionType, newSpec: ExtensionType) {
|
||||
const existingSpec = this.specMap.get(id);
|
||||
if (!existingSpec) {
|
||||
console.error(`Spec not found for ${id}`);
|
||||
|
||||
@@ -103,7 +103,7 @@ export class PreviewHelper {
|
||||
const query = this._calculateQuery(blockIds as string[], mode);
|
||||
const store = widget.doc.doc.getStore({ query });
|
||||
const previewSpec = SpecProvider.getInstance().getSpec(
|
||||
isEdgeless ? 'edgeless:preview' : 'page:preview'
|
||||
isEdgeless ? 'preview:edgeless' : 'preview:page'
|
||||
);
|
||||
const settingSignal = signal({ ...editorSetting });
|
||||
const extensions = [
|
||||
|
||||
@@ -3,7 +3,10 @@ import {
|
||||
InlineDeltaToHtmlAdapterExtensions,
|
||||
} from '@blocksuite/affine-components/rich-text';
|
||||
import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model';
|
||||
import { HtmlAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
embedSyncedDocMiddleware,
|
||||
HtmlAdapter,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import type {
|
||||
BlockSnapshot,
|
||||
@@ -14,7 +17,6 @@ import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { defaultBlockHtmlAdapterMatchers } from '../../_common/adapters/html/block-matcher.js';
|
||||
import { embedSyncedDocMiddleware } from '../../_common/transformers/middlewares.js';
|
||||
import { createJob } from '../utils/create-job.js';
|
||||
import { nanoidReplacement } from '../utils/nanoid-replacement.js';
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ import {
|
||||
NoteDisplayMode,
|
||||
TableModelFlavour,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { MarkdownAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
embedSyncedDocMiddleware,
|
||||
MarkdownAdapter,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import type {
|
||||
BlockSnapshot,
|
||||
@@ -19,7 +22,6 @@ import { AssetsManager, MemoryBlobCRUD } from '@blocksuite/store';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { defaultBlockMarkdownAdapterMatchers } from '../../_common/adapters/markdown/block-matcher.js';
|
||||
import { embedSyncedDocMiddleware } from '../../_common/transformers/middlewares.js';
|
||||
import { createJob } from '../utils/create-job.js';
|
||||
import { nanoidReplacement } from '../utils/nanoid-replacement.js';
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { InlineDeltaToPlainTextAdapterExtensions } from '@blocksuite/affine-components/rich-text';
|
||||
import { DefaultTheme, NoteDisplayMode } from '@blocksuite/affine-model';
|
||||
import { PlainTextAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
embedSyncedDocMiddleware,
|
||||
PlainTextAdapter,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import type {
|
||||
BlockSnapshot,
|
||||
@@ -10,7 +13,6 @@ import type {
|
||||
import { describe, expect, test } from 'vitest';
|
||||
|
||||
import { defaultBlockPlainTextAdapterMatchers } from '../../_common/adapters/plain-text/block-matcher.js';
|
||||
import { embedSyncedDocMiddleware } from '../../_common/transformers/middlewares.js';
|
||||
import { createJob } from '../utils/create-job.js';
|
||||
|
||||
const container = new Container();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
|
||||
import { FeatureFlagService } from '@blocksuite/affine-shared/services';
|
||||
import {
|
||||
Schema,
|
||||
@@ -6,7 +7,6 @@ import {
|
||||
} from '@blocksuite/store';
|
||||
import { TestWorkspace } from '@blocksuite/store/test';
|
||||
|
||||
import { defaultImageProxyMiddleware } from '../../_common/transformers/middlewares.js';
|
||||
import { AffineSchemas } from '../../schemas.js';
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
export { HtmlTransformer } from './html.js';
|
||||
export { MarkdownTransformer } from './markdown.js';
|
||||
export {
|
||||
customImageProxyMiddleware,
|
||||
defaultImageProxyMiddleware,
|
||||
docLinkBaseURLMiddleware,
|
||||
docLinkBaseURLMiddlewareBuilder,
|
||||
embedSyncedDocMiddleware,
|
||||
replaceIdMiddleware,
|
||||
setImageProxyMiddlewareURL,
|
||||
titleMiddleware,
|
||||
} from './middlewares.js';
|
||||
export { NotionHtmlTransformer } from './notion-html.js';
|
||||
export { createAssetsArchive, download } from './utils.js';
|
||||
export { ZipTransformer } from './zip.js';
|
||||
@@ -1,11 +0,0 @@
|
||||
import type {
|
||||
BrushElementModel,
|
||||
ConnectorElementModel,
|
||||
GroupElementModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import type { GfxModel } from '@blocksuite/block-std/gfx';
|
||||
|
||||
export type Connectable = Exclude<
|
||||
GfxModel,
|
||||
ConnectorElementModel | BrushElementModel | GroupElementModel
|
||||
>;
|
||||
@@ -56,6 +56,11 @@ import {
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import { AdapterFactoryExtensions } from '../_common/adapters/extension.js';
|
||||
import {
|
||||
HtmlAdapterExtension,
|
||||
MarkdownAdapterExtension,
|
||||
NotionHtmlAdapterExtension,
|
||||
} from './preset/adapters.js';
|
||||
|
||||
export const CommonBlockSpecs: ExtensionType[] = [
|
||||
DocDisplayMetaService,
|
||||
@@ -110,4 +115,8 @@ export const StoreExtensions: ExtensionType[] = [
|
||||
LinkPreviewerService,
|
||||
FileSizeLimitService,
|
||||
ImageStoreSpec,
|
||||
|
||||
HtmlAdapterExtension,
|
||||
MarkdownAdapterExtension,
|
||||
NotionHtmlAdapterExtension,
|
||||
].flat();
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import {
|
||||
HtmlInlineToDeltaAdapterExtensions,
|
||||
InlineDeltaToHtmlAdapterExtensions,
|
||||
InlineDeltaToMarkdownAdapterExtensions,
|
||||
MarkdownInlineToDeltaAdapterExtensions,
|
||||
NotionHtmlInlineToDeltaAdapterExtensions,
|
||||
} from '@blocksuite/affine-components/rich-text';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import {
|
||||
defaultBlockHtmlAdapterMatchers,
|
||||
defaultBlockMarkdownAdapterMatchers,
|
||||
defaultBlockNotionHtmlAdapterMatchers,
|
||||
} from '../../_common/adapters';
|
||||
|
||||
export const HtmlAdapterExtension: ExtensionType[] = [
|
||||
...HtmlInlineToDeltaAdapterExtensions,
|
||||
...defaultBlockHtmlAdapterMatchers,
|
||||
...InlineDeltaToHtmlAdapterExtensions,
|
||||
];
|
||||
|
||||
export const MarkdownAdapterExtension: ExtensionType[] = [
|
||||
...MarkdownInlineToDeltaAdapterExtensions,
|
||||
...defaultBlockMarkdownAdapterMatchers,
|
||||
...InlineDeltaToMarkdownAdapterExtensions,
|
||||
];
|
||||
|
||||
export const NotionHtmlAdapterExtension: ExtensionType[] = [
|
||||
...NotionHtmlInlineToDeltaAdapterExtensions,
|
||||
...defaultBlockNotionHtmlAdapterMatchers,
|
||||
];
|
||||
@@ -1,9 +1,9 @@
|
||||
import {
|
||||
EdgelessFrameManager,
|
||||
FrameOverlay,
|
||||
PresentTool,
|
||||
} from '@blocksuite/affine-block-frame';
|
||||
import { ConnectionOverlay } from '@blocksuite/affine-block-surface';
|
||||
import { PresentTool } from '@blocksuite/affine-fragment-frame-panel';
|
||||
import type { ExtensionType } from '@blocksuite/store';
|
||||
|
||||
import { EdgelessRootBlockSpec } from '../../root-block/edgeless/edgeless-root-spec.js';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
|
||||
import { CommonBlockSpecs, StoreExtensions } from './common.js';
|
||||
import { StoreExtensions } from './common.js';
|
||||
import { EdgelessEditorBlockSpecs } from './preset/edgeless-specs.js';
|
||||
import { PageEditorBlockSpecs } from './preset/page-specs.js';
|
||||
import {
|
||||
@@ -10,15 +10,14 @@ import {
|
||||
|
||||
export function registerSpecs() {
|
||||
SpecProvider.getInstance().addSpec('store', StoreExtensions);
|
||||
SpecProvider.getInstance().addSpec('common', CommonBlockSpecs);
|
||||
SpecProvider.getInstance().addSpec('page', PageEditorBlockSpecs);
|
||||
SpecProvider.getInstance().addSpec('edgeless', EdgelessEditorBlockSpecs);
|
||||
SpecProvider.getInstance().addSpec(
|
||||
'page:preview',
|
||||
'preview:page',
|
||||
PreviewPageEditorBlockSpecs
|
||||
);
|
||||
SpecProvider.getInstance().addSpec(
|
||||
'edgeless:preview',
|
||||
'preview:edgeless',
|
||||
PreviewEdgelessEditorBlockSpecs
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { splitElements } from './root-block/edgeless/utils/clipboard-utils.js';
|
||||
import { isCanvasElement } from './root-block/edgeless/utils/query.js';
|
||||
|
||||
export * from './_common/adapters/index.js';
|
||||
export * from './_common/transformers/index.js';
|
||||
export * from './_specs/index.js';
|
||||
export { EdgelessTemplatePanel } from './root-block/edgeless/components/toolbar/template/template-panel.js';
|
||||
export type {
|
||||
@@ -93,31 +92,7 @@ export {
|
||||
export * from '@blocksuite/affine-fragment-frame-panel';
|
||||
export * from '@blocksuite/affine-fragment-outline';
|
||||
export * from '@blocksuite/affine-model';
|
||||
export {
|
||||
AttachmentAdapter,
|
||||
AttachmentAdapterFactoryExtension,
|
||||
AttachmentAdapterFactoryIdentifier,
|
||||
codeBlockWrapMiddleware,
|
||||
FetchUtils,
|
||||
HtmlAdapter,
|
||||
HtmlAdapterFactoryExtension,
|
||||
HtmlAdapterFactoryIdentifier,
|
||||
ImageAdapter,
|
||||
ImageAdapterFactoryExtension,
|
||||
ImageAdapterFactoryIdentifier,
|
||||
MarkdownAdapter,
|
||||
MarkdownAdapterFactoryExtension,
|
||||
MarkdownAdapterFactoryIdentifier,
|
||||
MixTextAdapter,
|
||||
MixTextAdapterFactoryExtension,
|
||||
MixTextAdapterFactoryIdentifier,
|
||||
NotionTextAdapter,
|
||||
NotionTextAdapterFactoryExtension,
|
||||
NotionTextAdapterFactoryIdentifier,
|
||||
PlainTextAdapter,
|
||||
PlainTextAdapterFactoryExtension,
|
||||
PlainTextAdapterFactoryIdentifier,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
export * from '@blocksuite/affine-shared/adapters';
|
||||
export * from '@blocksuite/affine-shared/commands';
|
||||
export { HighlightSelection } from '@blocksuite/affine-shared/selection';
|
||||
export * from '@blocksuite/affine-shared/services';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { deleteTextCommand } from '@blocksuite/affine-components/rich-text';
|
||||
import {
|
||||
pasteMiddleware,
|
||||
replaceIdMiddleware,
|
||||
surfaceRefToEmbed,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
@@ -17,7 +18,6 @@ import type { UIEventHandler } from '@blocksuite/block-std';
|
||||
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||
import type { BlockSnapshot, Store } from '@blocksuite/store';
|
||||
|
||||
import { replaceIdMiddleware } from '../../_common/transformers/middlewares';
|
||||
import { ReadOnlyClipboard } from './readonly-clipboard';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
|
||||
import {
|
||||
AttachmentAdapter,
|
||||
copyMiddleware,
|
||||
@@ -5,6 +6,7 @@ import {
|
||||
ImageAdapter,
|
||||
MixTextAdapter,
|
||||
NotionTextAdapter,
|
||||
titleMiddleware,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import {
|
||||
copySelectedModelsCommand,
|
||||
@@ -14,10 +16,6 @@ import {
|
||||
import type { BlockComponent, UIEventHandler } from '@blocksuite/block-std';
|
||||
import { DisposableGroup } from '@blocksuite/global/utils';
|
||||
|
||||
import {
|
||||
defaultImageProxyMiddleware,
|
||||
titleMiddleware,
|
||||
} from '../../_common/transformers/middlewares.js';
|
||||
import { ClipboardAdapter } from './adapter.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -81,7 +81,7 @@ export class FramePreview extends WithDisposable(ShadowlessElement) {
|
||||
private _previewDoc: Store | null = null;
|
||||
|
||||
private readonly _previewSpec =
|
||||
SpecProvider.getInstance().getSpec('edgeless:preview');
|
||||
SpecProvider.getInstance().getSpec('preview:edgeless');
|
||||
|
||||
private readonly _updateFrameViewportWH = () => {
|
||||
const [, , w, h] = deserializeXYWH(this.frame.xywh);
|
||||
|
||||
@@ -31,11 +31,6 @@ import {
|
||||
import { IS_MAC } from '@blocksuite/global/env';
|
||||
import { Bound, getCommonBound } from '@blocksuite/global/utils';
|
||||
|
||||
import {
|
||||
getNearestTranslation,
|
||||
isElementOutsideViewport,
|
||||
isSingleMindMapNode,
|
||||
} from '../../_common/edgeless/mindmap/index.js';
|
||||
import { PageKeyboardManager } from '../keyboard/keyboard-manager.js';
|
||||
import type { EdgelessRootBlockComponent } from './edgeless-root-block.js';
|
||||
import { CopilotTool } from './gfx-tool/copilot-tool.js';
|
||||
@@ -48,6 +43,11 @@ import {
|
||||
} from './utils/consts.js';
|
||||
import { deleteElements } from './utils/crud.js';
|
||||
import { getNextShapeType } from './utils/hotkey-utils.js';
|
||||
import {
|
||||
getNearestTranslation,
|
||||
isElementOutsideViewport,
|
||||
isSingleMindMapNode,
|
||||
} from './utils/mindmap.js';
|
||||
import { isCanvasElement } from './utils/query.js';
|
||||
import {
|
||||
mountConnectorLabelEditor,
|
||||
|
||||
@@ -45,12 +45,12 @@ import { css, html } from 'lit';
|
||||
import { query } from 'lit/decorators.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
|
||||
import { isSingleMindMapNode } from '../../_common/edgeless/mindmap/index.js';
|
||||
import type { EdgelessRootBlockWidgetName } from '../types.js';
|
||||
import { EdgelessClipboardController } from './clipboard/clipboard.js';
|
||||
import type { EdgelessSelectedRectWidget } from './components/rects/edgeless-selected-rect.js';
|
||||
import { EdgelessPageKeyboardManager } from './edgeless-keyboard.js';
|
||||
import type { EdgelessRootService } from './edgeless-root-service.js';
|
||||
import { isSingleMindMapNode } from './utils/mindmap.js';
|
||||
import { isCanvasElement } from './utils/query.js';
|
||||
import { mountShapeTextEditor } from './utils/text.js';
|
||||
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import {
|
||||
} from '@blocksuite/block-std/gfx';
|
||||
import type { Bound, IVec } from '@blocksuite/global/utils';
|
||||
|
||||
import { isSingleMindMapNode } from '../../../../../_common/edgeless/mindmap/index.js';
|
||||
import { isSingleMindMapNode } from '../../../utils/mindmap.js';
|
||||
import { isMindmapNode } from '../../../utils/query.js';
|
||||
import { DefaultModeDragType, DefaultToolExt, type DragState } from '../ext.js';
|
||||
import { calculateResponseArea } from './drag-utils.js';
|
||||
|
||||
@@ -53,9 +53,9 @@ import {
|
||||
} from '@blocksuite/global/utils';
|
||||
import { effect } from '@preact/signals-core';
|
||||
|
||||
import { isSingleMindMapNode } from '../../../_common/edgeless/mindmap/index.js';
|
||||
import type { EdgelessRootBlockComponent } from '../edgeless-root-block.js';
|
||||
import { prepareCloneData } from '../utils/clone-utils.js';
|
||||
import { isSingleMindMapNode } from '../utils/mindmap.js';
|
||||
import { calPanDelta } from '../utils/panning-utils.js';
|
||||
import { isCanvasElement, isEdgelessTextBlock } from '../utils/query.js';
|
||||
import type { EdgelessSnapManager } from '../utils/snap-manager.js';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isNoteBlock } from '@blocksuite/affine-block-surface';
|
||||
import type { Connectable } from '@blocksuite/affine-model';
|
||||
import type { GfxModel } from '@blocksuite/block-std/gfx';
|
||||
|
||||
import type { Connectable } from '../../../_common/types.js';
|
||||
import type { EdgelessRootBlockComponent } from '../index.js';
|
||||
import { isConnectable } from './query.js';
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { CanvasElementWithText } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
type AttachmentBlockModel,
|
||||
type BookmarkBlockModel,
|
||||
type Connectable,
|
||||
ConnectorElementModel,
|
||||
type EdgelessTextBlockModel,
|
||||
type EmbedBlockModel,
|
||||
@@ -32,8 +33,6 @@ import type { PointLocation } from '@blocksuite/global/utils';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
import type { BlockModel } from '@blocksuite/store';
|
||||
|
||||
import type { Connectable } from '../../../_common/types';
|
||||
|
||||
export function isMindmapNode(element: GfxBlockElementModel | GfxModel | null) {
|
||||
return element?.group instanceof MindmapElementModel;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export * from './page/page-root-spec.js';
|
||||
export * from './preview/preview-root-block.js';
|
||||
export * from './root-config.js';
|
||||
export { RootService } from './root-service.js';
|
||||
export * from './transformers/index.js';
|
||||
export * from './types.js';
|
||||
export * from './utils/index.js';
|
||||
export * from './widgets/index.js';
|
||||
|
||||
@@ -8,22 +8,11 @@ import {
|
||||
import type { BlockComponent } from '@blocksuite/block-std';
|
||||
import { BlockService } from '@blocksuite/block-std';
|
||||
|
||||
import {
|
||||
HtmlTransformer,
|
||||
MarkdownTransformer,
|
||||
ZipTransformer,
|
||||
} from '../_common/transformers/index.js';
|
||||
import type { RootBlockComponent } from './types.js';
|
||||
|
||||
export abstract class RootService extends BlockService {
|
||||
static override readonly flavour = RootBlockSchema.model.flavour;
|
||||
|
||||
transformers = {
|
||||
markdown: MarkdownTransformer,
|
||||
html: HtmlTransformer,
|
||||
zip: ZipTransformer,
|
||||
};
|
||||
|
||||
get selectedBlocks() {
|
||||
let result: BlockComponent[] = [];
|
||||
this.std.command
|
||||
|
||||
+18
-21
@@ -1,20 +1,16 @@
|
||||
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
|
||||
import {
|
||||
HtmlInlineToDeltaAdapterExtensions,
|
||||
InlineDeltaToHtmlAdapterExtensions,
|
||||
} from '@blocksuite/affine-components/rich-text';
|
||||
import { HtmlAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
docLinkBaseURLMiddleware,
|
||||
fileNameMiddleware,
|
||||
HtmlAdapter,
|
||||
titleMiddleware,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import { sha } from '@blocksuite/global/utils';
|
||||
import type { Store, Workspace } from '@blocksuite/store';
|
||||
import { extMimeMap, Transformer } from '@blocksuite/store';
|
||||
|
||||
import { defaultBlockHtmlAdapterMatchers } from '../adapters/html/block-matcher.js';
|
||||
import {
|
||||
defaultImageProxyMiddleware,
|
||||
docLinkBaseURLMiddleware,
|
||||
fileNameMiddleware,
|
||||
titleMiddleware,
|
||||
} from './middlewares.js';
|
||||
import { createAssetsArchive, download, Unzip } from './utils.js';
|
||||
|
||||
type ImportHTMLToDocOptions = {
|
||||
@@ -28,16 +24,14 @@ type ImportHTMLZipOptions = {
|
||||
imported: Blob;
|
||||
};
|
||||
|
||||
const container = new Container();
|
||||
[
|
||||
...HtmlInlineToDeltaAdapterExtensions,
|
||||
...defaultBlockHtmlAdapterMatchers,
|
||||
...InlineDeltaToHtmlAdapterExtensions,
|
||||
].forEach(ext => {
|
||||
ext.setup(container);
|
||||
});
|
||||
|
||||
const provider = container.provider();
|
||||
function getProvider() {
|
||||
const container = new Container();
|
||||
const exts = SpecProvider.getInstance().getSpec('store').value;
|
||||
exts.forEach(ext => {
|
||||
ext.setup(container);
|
||||
});
|
||||
return container.provider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a doc to HTML format.
|
||||
@@ -46,6 +40,7 @@ const provider = container.provider();
|
||||
* @returns A Promise that resolves when the export is complete.
|
||||
*/
|
||||
async function exportDoc(doc: Store) {
|
||||
const provider = getProvider();
|
||||
const job = new Transformer({
|
||||
schema: doc.schema,
|
||||
blobCRUD: doc.blobSync,
|
||||
@@ -101,6 +96,7 @@ async function importHTMLToDoc({
|
||||
html,
|
||||
fileName,
|
||||
}: ImportHTMLToDocOptions) {
|
||||
const provider = getProvider();
|
||||
const job = new Transformer({
|
||||
schema: collection.schema,
|
||||
blobCRUD: collection.blobSync,
|
||||
@@ -135,6 +131,7 @@ async function importHTMLToDoc({
|
||||
* @returns A Promise that resolves to an array of IDs of the newly created docs.
|
||||
*/
|
||||
async function importHTMLZip({ collection, imported }: ImportHTMLZipOptions) {
|
||||
const provider = getProvider();
|
||||
const unzip = new Unzip();
|
||||
await unzip.load(imported);
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export { HtmlTransformer } from './html.js';
|
||||
export { MarkdownTransformer } from './markdown.js';
|
||||
export { NotionHtmlTransformer } from './notion-html.js';
|
||||
export { createAssetsArchive, download } from './utils.js';
|
||||
export { ZipTransformer } from './zip.js';
|
||||
+19
-21
@@ -1,33 +1,27 @@
|
||||
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
|
||||
import {
|
||||
InlineDeltaToMarkdownAdapterExtensions,
|
||||
MarkdownInlineToDeltaAdapterExtensions,
|
||||
} from '@blocksuite/affine-components/rich-text';
|
||||
import { MarkdownAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
docLinkBaseURLMiddleware,
|
||||
fileNameMiddleware,
|
||||
MarkdownAdapter,
|
||||
titleMiddleware,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||
import { assertExists, sha } from '@blocksuite/global/utils';
|
||||
import type { Store, Workspace } from '@blocksuite/store';
|
||||
import { extMimeMap, Transformer } from '@blocksuite/store';
|
||||
|
||||
import { defaultBlockMarkdownAdapterMatchers } from '../adapters/index.js';
|
||||
import {
|
||||
defaultImageProxyMiddleware,
|
||||
docLinkBaseURLMiddleware,
|
||||
fileNameMiddleware,
|
||||
titleMiddleware,
|
||||
} from './middlewares.js';
|
||||
import { createAssetsArchive, download, Unzip } from './utils.js';
|
||||
|
||||
const container = new Container();
|
||||
[
|
||||
...MarkdownInlineToDeltaAdapterExtensions,
|
||||
...defaultBlockMarkdownAdapterMatchers,
|
||||
...InlineDeltaToMarkdownAdapterExtensions,
|
||||
].forEach(ext => {
|
||||
ext.setup(container);
|
||||
});
|
||||
|
||||
const provider = container.provider();
|
||||
function getProvider() {
|
||||
const container = new Container();
|
||||
const exts = SpecProvider.getInstance().getSpec('store').value;
|
||||
exts.forEach(ext => {
|
||||
ext.setup(container);
|
||||
});
|
||||
return container.provider();
|
||||
}
|
||||
|
||||
type ImportMarkdownToBlockOptions = {
|
||||
doc: Store;
|
||||
@@ -52,6 +46,7 @@ type ImportMarkdownZipOptions = {
|
||||
* @returns A Promise that resolves when the export is complete
|
||||
*/
|
||||
async function exportDoc(doc: Store) {
|
||||
const provider = getProvider();
|
||||
const job = new Transformer({
|
||||
schema: doc.schema,
|
||||
blobCRUD: doc.blobSync,
|
||||
@@ -111,6 +106,7 @@ async function importMarkdownToBlock({
|
||||
markdown,
|
||||
blockId,
|
||||
}: ImportMarkdownToBlockOptions) {
|
||||
const provider = getProvider();
|
||||
const job = new Transformer({
|
||||
schema: doc.schema,
|
||||
blobCRUD: doc.blobSync,
|
||||
@@ -156,6 +152,7 @@ async function importMarkdownToDoc({
|
||||
markdown,
|
||||
fileName,
|
||||
}: ImportMarkdownToDocOptions) {
|
||||
const provider = getProvider();
|
||||
const job = new Transformer({
|
||||
schema: collection.schema,
|
||||
blobCRUD: collection.blobSync,
|
||||
@@ -192,6 +189,7 @@ async function importMarkdownZip({
|
||||
collection,
|
||||
imported,
|
||||
}: ImportMarkdownZipOptions) {
|
||||
const provider = getProvider();
|
||||
const unzip = new Unzip();
|
||||
await unzip.load(imported);
|
||||
|
||||
+11
-12
@@ -1,11 +1,10 @@
|
||||
import { NotionHtmlInlineToDeltaAdapterExtensions } from '@blocksuite/affine-components/rich-text';
|
||||
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
|
||||
import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters';
|
||||
import { SpecProvider } from '@blocksuite/affine-shared/utils';
|
||||
import { Container } from '@blocksuite/global/di';
|
||||
import { sha } from '@blocksuite/global/utils';
|
||||
import { extMimeMap, Transformer, type Workspace } from '@blocksuite/store';
|
||||
|
||||
import { defaultBlockNotionHtmlAdapterMatchers } from '../adapters/notion-html/block-matcher.js';
|
||||
import { defaultImageProxyMiddleware } from './middlewares.js';
|
||||
import { Unzip } from './utils.js';
|
||||
|
||||
type ImportNotionZipOptions = {
|
||||
@@ -13,15 +12,14 @@ type ImportNotionZipOptions = {
|
||||
imported: Blob;
|
||||
};
|
||||
|
||||
const container = new Container();
|
||||
[
|
||||
...NotionHtmlInlineToDeltaAdapterExtensions,
|
||||
...defaultBlockNotionHtmlAdapterMatchers,
|
||||
].forEach(ext => {
|
||||
ext.setup(container);
|
||||
});
|
||||
|
||||
const provider = container.provider();
|
||||
function getProvider() {
|
||||
const container = new Container();
|
||||
const exts = SpecProvider.getInstance().getSpec('store').value;
|
||||
exts.forEach(ext => {
|
||||
ext.setup(container);
|
||||
});
|
||||
return container.provider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a Notion zip file into the BlockSuite collection.
|
||||
@@ -40,6 +38,7 @@ async function importNotionZip({
|
||||
collection,
|
||||
imported,
|
||||
}: ImportNotionZipOptions) {
|
||||
const provider = getProvider();
|
||||
const pageIds: string[] = [];
|
||||
let isWorkspaceFile = false;
|
||||
let hasMarkdown = false;
|
||||
+4
-1
@@ -1,9 +1,12 @@
|
||||
import {
|
||||
replaceIdMiddleware,
|
||||
titleMiddleware,
|
||||
} from '@blocksuite/affine-shared/adapters';
|
||||
import { sha } from '@blocksuite/global/utils';
|
||||
import type { DocSnapshot, Store, Workspace } from '@blocksuite/store';
|
||||
import { extMimeMap, getAssetName, Transformer } from '@blocksuite/store';
|
||||
|
||||
import { download, Unzip, Zip } from '../transformers/utils.js';
|
||||
import { replaceIdMiddleware, titleMiddleware } from './middlewares.js';
|
||||
|
||||
async function exportDocs(collection: Workspace, docs: Store[]) {
|
||||
const zip = new Zip();
|
||||
@@ -12,9 +12,9 @@ import type { Workspace } from '@blocksuite/store';
|
||||
import { html, LitElement, type PropertyValues } from 'lit';
|
||||
import { query, state } from 'lit/decorators.js';
|
||||
|
||||
import { HtmlTransformer } from '../../../../_common/transformers/html.js';
|
||||
import { MarkdownTransformer } from '../../../../_common/transformers/markdown.js';
|
||||
import { NotionHtmlTransformer } from '../../../../_common/transformers/notion-html.js';
|
||||
import { HtmlTransformer } from '../../../transformers/html.js';
|
||||
import { MarkdownTransformer } from '../../../transformers/markdown.js';
|
||||
import { NotionHtmlTransformer } from '../../../transformers/notion-html.js';
|
||||
import { styles } from './styles.js';
|
||||
|
||||
export type OnSuccessHandler = (
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { BlockServiceIdentifier } from '@blocksuite/block-std';
|
||||
import type { PageRootService, SurfaceBlockModel } from '@blocksuite/blocks';
|
||||
import { type SurfaceBlockModel, ZipTransformer } from '@blocksuite/blocks';
|
||||
import type { PointLocation } from '@blocksuite/global/utils';
|
||||
import { beforeEach, expect, test } from 'vitest';
|
||||
|
||||
@@ -25,13 +24,7 @@ const fieldChecker: Record<string, (value: any) => boolean> = {
|
||||
const skipFields = new Set(['_lastXYWH']);
|
||||
|
||||
const snapshotTest = async (snapshotUrl: string, elementsCount: number) => {
|
||||
const pageService = window.editor.host!.std.getOptional(
|
||||
BlockServiceIdentifier('affine:page')
|
||||
) as PageRootService;
|
||||
if (!pageService) {
|
||||
throw new Error('page service not found');
|
||||
}
|
||||
const transformer = pageService.transformers.zip;
|
||||
const transformer = ZipTransformer;
|
||||
|
||||
const snapshotFile = await fetch(snapshotUrl)
|
||||
.then(res => res.blob())
|
||||
|
||||
@@ -209,7 +209,7 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
|
||||
${new BlockStdScope({
|
||||
store: this._doc,
|
||||
extensions:
|
||||
SpecProvider.getInstance().getSpec('edgeless:preview').value,
|
||||
SpecProvider.getInstance().getSpec('preview:edgeless').value,
|
||||
}).render()}
|
||||
</div>
|
||||
<div class="mask"></div>
|
||||
|
||||
+2
-2
@@ -245,10 +245,10 @@ export const extendEdgelessPreviewSpec = (function () {
|
||||
return _extension;
|
||||
} else {
|
||||
_extension &&
|
||||
SpecProvider.getInstance().omitSpec('edgeless:preview', _extension);
|
||||
SpecProvider.getInstance().omitSpec('preview:edgeless', _extension);
|
||||
_extension = getThemeExtension(framework);
|
||||
_framework = framework;
|
||||
SpecProvider.getInstance().extendSpec('edgeless:preview', [_extension]);
|
||||
SpecProvider.getInstance().extendSpec('preview:edgeless', [_extension]);
|
||||
return _extension;
|
||||
}
|
||||
};
|
||||
|
||||
+6
-3
@@ -29,14 +29,17 @@ const CustomSpecs: ExtensionType[] = [
|
||||
getFontConfigExtension(),
|
||||
].flat();
|
||||
|
||||
function patchPreviewSpec(id: string, specs: ExtensionType[]) {
|
||||
function patchPreviewSpec(
|
||||
id: 'preview:edgeless' | 'preview:page',
|
||||
specs: ExtensionType[]
|
||||
) {
|
||||
const specProvider = SpecProvider.getInstance();
|
||||
specProvider.extendSpec(id, specs);
|
||||
}
|
||||
|
||||
export function effects() {
|
||||
// Patch edgeless preview spec for blocksuite surface-ref and embed-synced-doc
|
||||
patchPreviewSpec('edgeless:preview', CustomSpecs);
|
||||
patchPreviewSpec('preview:edgeless', CustomSpecs);
|
||||
}
|
||||
|
||||
export function getPagePreviewThemeExtension(framework: FrameworkProvider) {
|
||||
@@ -98,7 +101,7 @@ export function createPageModePreviewSpecs(
|
||||
framework: FrameworkProvider
|
||||
): SpecBuilder {
|
||||
const specProvider = SpecProvider.getInstance();
|
||||
const pagePreviewSpec = specProvider.getSpec('page:preview');
|
||||
const pagePreviewSpec = specProvider.getSpec('preview:page');
|
||||
// Enable theme extension, doc display meta extension and peek view service
|
||||
const peekViewService = framework.get(PeekViewService);
|
||||
pagePreviewSpec.extend([
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ export const EdgelessSnapshot = (props: Props) => {
|
||||
const editorHost = new BlockStdScope({
|
||||
store: doc,
|
||||
extensions: [
|
||||
...SpecProvider.getInstance().getSpec('edgeless:preview').value,
|
||||
...SpecProvider.getInstance().getSpec('preview:edgeless').value,
|
||||
getThemeExtension(framework),
|
||||
],
|
||||
}).render();
|
||||
|
||||
Reference in New Issue
Block a user