Files
AFFiNE-Mirror/blocksuite/blocks/src/attachment-block/attachment-service.ts
T
2024-12-20 16:48:10 +00:00

129 lines
4.0 KiB
TypeScript

import { AttachmentBlockSchema } from '@blocksuite/affine-model';
import {
DragHandleConfigExtension,
TelemetryProvider,
} from '@blocksuite/affine-shared/services';
import {
captureEventTarget,
convertDragPreviewDocToEdgeless,
convertDragPreviewEdgelessToDoc,
isInsideEdgelessEditor,
matchFlavours,
} from '@blocksuite/affine-shared/utils';
import { BlockService } from '@blocksuite/block-std';
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
import {
FileDropManager,
type FileDropOptions,
} from '../_common/components/file-drop-manager.js';
import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH } from '../_common/consts.js';
import { addAttachments } from '../root-block/edgeless/utils/common.js';
import type { AttachmentBlockComponent } from './attachment-block.js';
import { AttachmentEdgelessBlockComponent } from './attachment-edgeless-block.js';
import { addSiblingAttachmentBlocks } from './utils.js';
export class AttachmentBlockService extends BlockService {
static override readonly flavour = AttachmentBlockSchema.model.flavour;
private readonly _fileDropOptions: FileDropOptions = {
flavour: this.flavour,
onDrop: async ({ files, targetModel, place, point }) => {
if (!files.length) return false;
// generic attachment block for all files except images
const attachmentFiles = files.filter(
file => !file.type.startsWith('image/')
);
if (targetModel && !matchFlavours(targetModel, ['affine:surface'])) {
await addSiblingAttachmentBlocks(
this.host,
attachmentFiles,
this.maxFileSize,
targetModel,
place
);
} else if (isInsideEdgelessEditor(this.host)) {
const gfx = this.std.get(GfxControllerIdentifier);
point = gfx.viewport.toViewCoordFromClientCoord(point);
await addAttachments(this.std, attachmentFiles, point);
this.std.getOptional(TelemetryProvider)?.track('CanvasElementAdded', {
control: 'canvas:drop',
page: 'whiteboard editor',
module: 'toolbar',
segment: 'toolbar',
type: 'attachment',
});
}
return true;
},
};
fileDropManager!: FileDropManager;
maxFileSize = 10 * 1000 * 1000; // 10MB (default)
override mounted(): void {
super.mounted();
this.fileDropManager = new FileDropManager(this, this._fileDropOptions);
}
}
export const AttachmentDragHandleOption = DragHandleConfigExtension({
flavour: AttachmentBlockSchema.model.flavour,
edgeless: true,
onDragEnd: props => {
const { state, draggingElements, editorHost } = props;
if (
draggingElements.length !== 1 ||
!matchFlavours(draggingElements[0].model, [
AttachmentBlockSchema.model.flavour,
])
)
return false;
const blockComponent = draggingElements[0] as
| AttachmentBlockComponent
| AttachmentEdgelessBlockComponent;
const isInSurface =
blockComponent instanceof AttachmentEdgelessBlockComponent;
const target = captureEventTarget(state.raw.target);
const isTargetEdgelessContainer =
target?.classList.contains('edgeless-container');
if (isInSurface) {
const style = blockComponent.model.style;
const targetStyle = style === 'cubeThick' ? 'horizontalThin' : style;
return convertDragPreviewEdgelessToDoc({
blockComponent,
style: targetStyle,
...props,
});
} else if (isTargetEdgelessContainer) {
let style = blockComponent.model.style ?? 'cubeThick';
const embed = blockComponent.model.embed;
if (embed) {
style = 'cubeThick';
editorHost.doc.updateBlock(blockComponent.model, {
style,
embed: false,
});
}
return convertDragPreviewDocToEdgeless({
blockComponent,
cssSelector: '.affine-attachment-container',
width: EMBED_CARD_WIDTH[style],
height: EMBED_CARD_HEIGHT[style],
...props,
});
}
return false;
},
});