mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 02:13:00 +08:00
feat(editor): command for ungroup and group (#11116)
This commit is contained in:
137
blocksuite/affine/gfx/group/src/command/group-api.ts
Normal file
137
blocksuite/affine/gfx/group/src/command/group-api.ts
Normal 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();
|
||||
};
|
||||
Reference in New Issue
Block a user