import type { Command } from '@blockeditor/block-std'; import { assertExists } from '@blockeditor/global/utils'; import type { BlockModel } from '@blockeditor/store'; import { Slice } from '@blockeditor/store'; import { matchFlavours } from '../../../_common/utils/index.js'; export const copySelectedModelsCommand: Command<'selectedModels' | 'onCopy'> = ( ctx, next ) => { const models = ctx.selectedModels; assertExists( models, '`selectedModels` is required, you need to use `getSelectedModels` command before adding this command to the pipeline.' ); const traverse = (model: BlockModel) => { const isDatabase = matchFlavours(model, ['affine:database']); const children = isDatabase ? model.children : model.children.filter(child => { const idx = models.findIndex(m => m.id === child.id); return idx >= 0; }); children.forEach(child => { const idx = models.findIndex(m => m.id === child.id); if (idx >= 0) { models.splice(idx, 1); } traverse(child); }); // model.children = children; return; }; models.forEach(traverse); const slice = Slice.fromModels(ctx.std.page, models); ctx.std.clipboard .copy(slice) .then(() => ctx.onCopy?.()) .catch(console.error); return next(); }; declare global { namespace BlockEditor { interface CommandContext { onCopy?: () => void; } interface Commands { copySelectedModels: typeof copySelectedModelsCommand; } } }