mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 14:27:02 +08:00
98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
import { isFrameBlock } from '@blocksuite/affine-block-frame';
|
|
import {
|
|
getSurfaceComponent,
|
|
isNoteBlock,
|
|
} from '@blocksuite/affine-block-surface';
|
|
import type {
|
|
EdgelessTextBlockModel,
|
|
EmbedSyncedDocModel,
|
|
FrameBlockModel,
|
|
ImageBlockModel,
|
|
NoteBlockModel,
|
|
ShapeElementModel,
|
|
} from '@blocksuite/affine-model';
|
|
import { getElementsWithoutGroup } from '@blocksuite/affine-shared/utils';
|
|
import { getCommonBoundWithRotation } from '@blocksuite/global/gfx';
|
|
import type { BlockComponent } from '@blocksuite/std';
|
|
import { GfxControllerIdentifier, type GfxModel } from '@blocksuite/std/gfx';
|
|
import groupBy from 'lodash-es/groupBy';
|
|
|
|
import { createElementsFromClipboardDataCommand } from '../clipboard/command.js';
|
|
import { getSortedCloneElements, prepareCloneData } from './clone-utils.js';
|
|
import {
|
|
isEdgelessTextBlock,
|
|
isEmbedSyncedDocBlock,
|
|
isImageBlock,
|
|
} from './query.js';
|
|
|
|
const offset = 10;
|
|
export async function duplicate(
|
|
edgeless: BlockComponent,
|
|
elements: GfxModel[],
|
|
select = true
|
|
) {
|
|
const gfx = edgeless.std.get(GfxControllerIdentifier);
|
|
|
|
const surface = getSurfaceComponent(edgeless.std);
|
|
if (!surface) return;
|
|
|
|
const copyElements = getSortedCloneElements(elements);
|
|
const totalBound = getCommonBoundWithRotation(copyElements);
|
|
totalBound.x += totalBound.w + offset;
|
|
|
|
const snapshot = prepareCloneData(copyElements, edgeless.std);
|
|
const [_, { createdElementsPromise }] = edgeless.std.command.exec(
|
|
createElementsFromClipboardDataCommand,
|
|
{
|
|
elementsRawData: snapshot,
|
|
pasteCenter: totalBound.center,
|
|
}
|
|
);
|
|
if (!createdElementsPromise) return;
|
|
const { canvasElements, blockModels } = await createdElementsPromise;
|
|
|
|
const newElements = [...canvasElements, ...blockModels];
|
|
|
|
surface.fitToViewport(totalBound);
|
|
|
|
if (select) {
|
|
gfx.selection.set({
|
|
elements: newElements.map(e => e.id),
|
|
editing: false,
|
|
});
|
|
}
|
|
}
|
|
export const splitElements = (elements: GfxModel[]) => {
|
|
const { notes, frames, shapes, images, edgelessTexts, embedSyncedDocs } =
|
|
groupBy(getElementsWithoutGroup(elements), element => {
|
|
if (isNoteBlock(element)) {
|
|
return 'notes';
|
|
} else if (isFrameBlock(element)) {
|
|
return 'frames';
|
|
} else if (isImageBlock(element)) {
|
|
return 'images';
|
|
} else if (isEdgelessTextBlock(element)) {
|
|
return 'edgelessTexts';
|
|
} else if (isEmbedSyncedDocBlock(element)) {
|
|
return 'embedSyncedDocs';
|
|
}
|
|
return 'shapes';
|
|
}) as {
|
|
notes: NoteBlockModel[];
|
|
shapes: ShapeElementModel[];
|
|
frames: FrameBlockModel[];
|
|
images: ImageBlockModel[];
|
|
edgelessTexts: EdgelessTextBlockModel[];
|
|
embedSyncedDocs: EmbedSyncedDocModel[];
|
|
};
|
|
|
|
return {
|
|
notes: notes ?? [],
|
|
shapes: shapes ?? [],
|
|
frames: frames ?? [],
|
|
images: images ?? [],
|
|
edgelessTexts: edgelessTexts ?? [],
|
|
embedSyncedDocs: embedSyncedDocs ?? [],
|
|
};
|
|
};
|