feat(editor): command for ungroup and group (#11116)

This commit is contained in:
Saul-Mirone
2025-03-24 06:28:43 +00:00
parent 63762b75a1
commit ef1ed383cb
25 changed files with 321 additions and 147 deletions

View File

@@ -0,0 +1,137 @@
import { EdgelessCRUDIdentifier } from '@blocksuite/affine-block-surface';
import {
type GroupElementModel,
MindmapElementModel,
} from '@blocksuite/affine-model';
import type { Command } from '@blocksuite/block-std';
import {
GfxControllerIdentifier,
type GfxModel,
} from '@blocksuite/block-std/gfx';
export const createGroupCommand: Command<
{ elements: GfxModel[] | string[] },
{ groupId: string }
> = (ctx, next) => {
const { std, elements } = ctx;
const gfx = std.get(GfxControllerIdentifier);
const crud = std.get(EdgelessCRUDIdentifier);
const groups = gfx.layer.canvasElements.filter(
el => el.type === 'group'
) as GroupElementModel[];
const groupId = crud.addElement('group', {
children: elements.reduce(
(pre, el) => {
const id = typeof el === 'string' ? el : el.id;
pre[id] = true;
return pre;
},
{} as Record<string, true>
),
title: `Group ${groups.length + 1}`,
});
if (!groupId) {
return;
}
next({ groupId });
};
export const createGroupFromSelectedCommand: Command<
{},
{ groupId: string }
> = (ctx, next) => {
const { std } = ctx;
const gfx = std.get(GfxControllerIdentifier);
const { selection, surface } = gfx;
if (!surface) {
return;
}
if (
selection.selectedElements.length === 0 ||
!selection.selectedElements.every(
element =>
element.group === selection.firstElement.group &&
!(element.group instanceof MindmapElementModel)
)
) {
return;
}
const parent = selection.firstElement.group as GroupElementModel;
if (parent !== null) {
selection.selectedElements.forEach(element => {
// oxlint-disable-next-line unicorn/prefer-dom-node-remove
parent.removeChild(element);
});
}
const [_, result] = std.command.exec(createGroupCommand, {
elements: selection.selectedElements,
});
if (!result.groupId) {
return;
}
const group = surface.getElementById(result.groupId);
if (parent !== null && group) {
parent.addChild(group);
}
selection.set({
editing: false,
elements: [result.groupId],
});
next({ groupId: result.groupId });
};
export const ungroupCommand: Command<{ group: GroupElementModel }, {}> = (
ctx,
next
) => {
const { std, group } = ctx;
const gfx = std.get(GfxControllerIdentifier);
const { selection } = gfx;
const parent = group.group as GroupElementModel;
const elements = group.childElements;
if (group instanceof MindmapElementModel) {
return;
}
if (parent !== null) {
// oxlint-disable-next-line unicorn/prefer-dom-node-remove
parent.removeChild(group);
}
elements.forEach(element => {
// oxlint-disable-next-line unicorn/prefer-dom-node-remove
group.removeChild(element);
});
// keep relative index order of group children after ungroup
elements
.sort((a, b) => gfx.layer.compare(a, b))
.forEach(element => {
std.store.transact(() => {
element.index = gfx.layer.generateIndex();
});
});
if (parent !== null) {
elements.forEach(element => {
parent.addChild(element);
});
}
selection.set({
editing: false,
elements: elements.map(ele => ele.id),
});
next();
};