feat(editor): add provider for base adapter (#11169)

This commit is contained in:
Saul-Mirone
2025-03-25 12:09:23 +00:00
parent df057b4c12
commit e84c60f53d
18 changed files with 50 additions and 55 deletions
@@ -7,7 +7,7 @@ import { createJob } from '../utils/create-job.js';
import { getProvider } from '../utils/get-provider.js';
import { nanoidReplacement } from '../utils/nanoid-replacement.js';
getProvider();
const provider = getProvider();
describe('notion-text to snapshot', () => {
test('basic', () => {
@@ -98,7 +98,7 @@ describe('notion-text to snapshot', () => {
pageId: '',
};
const ntAdapter = new NotionTextAdapter(createJob());
const ntAdapter = new NotionTextAdapter(createJob(), provider);
const target = ntAdapter.toSliceSnapshot({
file: notionText,
workspaceId: '',
@@ -165,5 +165,3 @@ export class PageClipboard extends ReadOnlyClipboard {
}
}
}
export { pasteMiddleware };
@@ -1,6 +1,7 @@
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
import {
AttachmentAdapter,
ClipboardAdapter,
copyMiddleware,
HtmlAdapter,
ImageAdapter,
@@ -16,8 +17,6 @@ import {
import type { BlockComponent, UIEventHandler } from '@blocksuite/block-std';
import { DisposableGroup } from '@blocksuite/global/disposable';
import { ClipboardAdapter } from './adapter.js';
/**
* ReadOnlyClipboard is a class that provides a read-only clipboard for the root block.
* It is supported to copy models in the root block.
@@ -19,6 +19,11 @@ import {
FrameBlockModel,
MAX_IMAGE_WIDTH,
} from '@blocksuite/affine-model';
import {
ClipboardAdapter,
decodeClipboardBlobs,
encodeClipboardBlobs,
} from '@blocksuite/affine-shared/adapters';
import {
CANVAS_EXPORT_IGNORE_TAGS,
EMBED_CARD_HEIGHT,
@@ -72,12 +77,7 @@ import {
import DOMPurify from 'dompurify';
import * as Y from 'yjs';
import { ClipboardAdapter } from '../../clipboard/adapter.js';
import { PageClipboard } from '../../clipboard/index.js';
import {
decodeClipboardBlobs,
encodeClipboardBlobs,
} from '../../clipboard/utils.js';
import { edgelessElementsBoundFromRawData } from '../utils/bound-utils.js';
import { createNewPresentationIndexes } from '../utils/clipboard-utils.js';
import {
@@ -131,8 +131,8 @@ export const AttachmentAdapterFactoryIdentifier =
export const AttachmentAdapterFactoryExtension: ExtensionType = {
setup: di => {
di.addImpl(AttachmentAdapterFactoryIdentifier, () => ({
get: (job: Transformer) => new AttachmentAdapter(job),
di.addImpl(AttachmentAdapterFactoryIdentifier, provider => ({
get: (job: Transformer) => new AttachmentAdapter(job, provider),
}));
},
};
@@ -15,6 +15,7 @@ import type {
} from '@blocksuite/store';
import { BaseAdapter } from '@blocksuite/store';
import { NotificationProvider } from '../../services/notification-service.js';
import { decodeClipboardBlobs, encodeClipboardBlobs } from './utils.js';
export type FileSnapshot = {
@@ -26,6 +27,13 @@ export type FileSnapshot = {
export class ClipboardAdapter extends BaseAdapter<string> {
static MIME = 'BLOCKSUITE/SNAPSHOT';
private readonly _onError = (message: string) => {
const notification = this.provider.getOptional(NotificationProvider);
if (!notification) return;
notification.toast(message);
};
override fromBlockSnapshot(
_payload: FromBlockSnapshotPayload
): Promise<FromBlockSnapshotResult<string>> {
@@ -56,7 +64,10 @@ export class ClipboardAdapter extends BaseAdapter<string> {
);
}
const map = assets.getAssets();
const blobs: Record<string, FileSnapshot> = await encodeClipboardBlobs(map);
const blobs: Record<string, FileSnapshot> = await encodeClipboardBlobs(
map,
this._onError
);
return {
file: JSON.stringify({
snapshot,
@@ -0,0 +1,2 @@
export * from './clipboard';
export * from './utils';
@@ -1,6 +1,4 @@
import { toast } from '@blocksuite/affine-components/toast';
import type { FileSnapshot } from './adapter.js';
import type { FileSnapshot } from './clipboard.js';
const chars =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
@@ -67,30 +65,21 @@ export const decode = (base64: string): ArrayBuffer => {
return arraybuffer;
};
export async function encodeClipboardBlobs(map: Map<string, Blob>) {
export async function encodeClipboardBlobs(
map: Map<string, Blob>,
onError?: (message: string) => void
) {
const blobs: Record<string, FileSnapshot> = {};
let sumSize = 0;
await Promise.all(
Array.from(map.entries()).map(async ([id, blob]) => {
if (blob.size > 4 * 1024 * 1024) {
const host = document.querySelector('editor-host');
if (!host) {
return;
}
toast(
host,
(blob as File).name ?? 'File' + ' is too large to be copied'
);
onError?.((blob as File).name ?? 'File' + ' is too large to be copied');
return;
}
sumSize += blob.size;
if (sumSize > 6 * 1024 * 1024) {
const host = document.querySelector('editor-host');
if (!host) {
return;
}
toast(
host,
onError?.(
(blob as File).name ??
'File' + ' cannot be copied due to the clipboard size limit'
);
@@ -174,11 +174,8 @@ export class HtmlAdapter extends BaseAdapter<Html> {
readonly blockMatchers: BlockHtmlAdapterMatcher[];
constructor(
job: Transformer,
readonly provider: ServiceProvider
) {
super(job);
constructor(job: Transformer, provider: ServiceProvider) {
super(job, provider);
const blockMatchers = Array.from(
provider.getAll(BlockHtmlAdapterMatcherIdentifier).values()
);
@@ -122,8 +122,8 @@ export const ImageAdapterFactoryIdentifier = AdapterFactoryIdentifier('Image');
export const ImageAdapterFactoryExtension: ExtensionType = {
setup: di => {
di.addImpl(ImageAdapterFactoryIdentifier, () => ({
get: (job: Transformer) => new ImageAdapter(job),
di.addImpl(ImageAdapterFactoryIdentifier, provider => ({
get: (job: Transformer) => new ImageAdapter(job, provider),
}));
},
};
@@ -1,4 +1,5 @@
export * from './attachment';
export * from './clipboard';
export {
BlockHtmlAdapterExtension,
type BlockHtmlAdapterMatcher,
@@ -170,11 +170,8 @@ export class MarkdownAdapter extends BaseAdapter<Markdown> {
readonly blockMatchers: BlockMarkdownAdapterMatcher[];
constructor(
job: Transformer,
readonly provider: ServiceProvider
) {
super(job);
constructor(job: Transformer, provider: ServiceProvider) {
super(job, provider);
const blockMatchers = Array.from(
provider.getAll(BlockMarkdownAdapterMatcherIdentifier).values()
);
@@ -38,7 +38,7 @@ export class MixTextAdapter extends BaseAdapter<MixText> {
private readonly _markdownAdapter: MarkdownAdapter;
constructor(job: Transformer, provider: ServiceProvider) {
super(job);
super(job, provider);
this._markdownAdapter = new MarkdownAdapter(job, provider);
}
@@ -116,7 +116,7 @@ export class NotionHtmlAdapter extends BaseAdapter<NotionHtml> {
readonly blockMatchers: BlockNotionHtmlAdapterMatcher[];
constructor(job: Transformer, provider: ServiceProvider) {
super(job);
super(job, provider);
const blockMatchers = Array.from(
provider.getAll(BlockNotionHtmlAdapterMatcherIdentifier).values()
);
@@ -163,8 +163,8 @@ export const NotionTextAdapterFactoryIdentifier =
export const NotionTextAdapterFactoryExtension: ExtensionType = {
setup: di => {
di.addImpl(NotionTextAdapterFactoryIdentifier, () => ({
get: (job: Transformer) => new NotionTextAdapter(job),
di.addImpl(NotionTextAdapterFactoryIdentifier, provider => ({
get: (job: Transformer) => new NotionTextAdapter(job, provider),
}));
},
};
@@ -49,11 +49,8 @@ export class PlainTextAdapter extends BaseAdapter<PlainText> {
readonly blockMatchers: BlockPlainTextAdapterMatcher[];
constructor(
job: Transformer,
readonly provider: ServiceProvider
) {
super(job);
constructor(job: Transformer, provider: ServiceProvider) {
super(job, provider);
const blockMatchers = Array.from(
provider.getAll(BlockPlainTextAdapterMatcherIdentifier).values()
);
@@ -1,3 +1,4 @@
import type { ServiceProvider } from '@blocksuite/global/di';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import {
@@ -73,7 +74,10 @@ export abstract class BaseAdapter<AdapterTarget = unknown> {
return this.job.adapterConfigs;
}
constructor(job: Transformer) {
constructor(
job: Transformer,
readonly provider: ServiceProvider
) {
this.job = job;
}
@@ -5,12 +5,12 @@ import {
TextSelection,
} from '@blocksuite/affine/block-std';
import { defaultImageProxyMiddleware } from '@blocksuite/affine/blocks/image';
import { pasteMiddleware } from '@blocksuite/affine/blocks/root';
import type { ServiceProvider } from '@blocksuite/affine/global/di';
import {
embedSyncedDocMiddleware,
MarkdownAdapter,
MixTextAdapter,
pasteMiddleware,
PlainTextAdapter,
titleMiddleware,
} from '@blocksuite/affine/shared/adapters';