feat(layers): add layer management panel
This commit is contained in:
95
input/layers-panel.ts
Normal file
95
input/layers-panel.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { commandIds } from "@commands/ids";
|
||||
import type { Dispatch } from "@commands/dispatcher";
|
||||
import type { ImageDocument } from "@core/document";
|
||||
import type { ArtboardId, LayerId } from "@core/id";
|
||||
import type { Layer } from "@core/layer";
|
||||
import type { SelectionState } from "@editor/state";
|
||||
import type { KeybindEvent } from "./keyboard";
|
||||
|
||||
export type LayerInfo = {
|
||||
artboardId: ArtboardId;
|
||||
parentGroupId?: LayerId;
|
||||
layer: Layer;
|
||||
};
|
||||
|
||||
export type LayerDropTarget = {
|
||||
artboardId: ArtboardId;
|
||||
layer: Layer;
|
||||
};
|
||||
|
||||
export function handleDeleteSelectionKey(options: { event: KeybindEvent; selection: SelectionState; dispatch: Dispatch }): boolean {
|
||||
if (options.event.altKey || options.event.ctrlKey || options.event.metaKey) return false;
|
||||
if (options.event.key !== "Backspace" && options.event.key !== "Delete") return false;
|
||||
|
||||
for (const layerId of options.selection.layerIds) options.dispatch(commandIds.documentRemoveLayer, { layerId });
|
||||
if (options.selection.layerIds.length === 0 && options.selection.artboardId) {
|
||||
options.dispatch(commandIds.documentRemoveArtboard, { id: options.selection.artboardId });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function resolveLayerDrop(options: {
|
||||
document: ImageDocument;
|
||||
sourceLayerId: LayerId;
|
||||
target: LayerDropTarget;
|
||||
verticalRatio: number;
|
||||
}): { layerId: LayerId; toArtboardId: ArtboardId; toParentGroupId?: LayerId; toIndex: number } | undefined {
|
||||
const targetInfo = findLayerInfoInDocument(options.document, options.target.layer.id);
|
||||
const sourceInfo = findLayerInfoInDocument(options.document, options.sourceLayerId);
|
||||
if (!targetInfo || !sourceInfo || options.sourceLayerId === options.target.layer.id) return undefined;
|
||||
|
||||
const verticalRatio = Math.max(0, Math.min(1, options.verticalRatio));
|
||||
const dropIntoGroup = options.target.layer.type === "group" && verticalRatio >= 0.33 && verticalRatio <= 0.66;
|
||||
if (dropIntoGroup) {
|
||||
return {
|
||||
layerId: options.sourceLayerId,
|
||||
toArtboardId: options.target.artboardId,
|
||||
toParentGroupId: options.target.layer.id,
|
||||
toIndex: options.target.layer.children.length,
|
||||
};
|
||||
}
|
||||
|
||||
const siblings = targetInfo.parentGroupId
|
||||
? findGroup(options.document, targetInfo.parentGroupId)?.children
|
||||
: options.document.artboards.find((artboard) => artboard.id === targetInfo.artboardId)?.layers;
|
||||
if (!siblings) return undefined;
|
||||
|
||||
const targetIndex = siblings.findIndex((layer) => layer.id === options.target.layer.id);
|
||||
const sourceIndex = sourceInfo.parentGroupId === targetInfo.parentGroupId && sourceInfo.artboardId === targetInfo.artboardId
|
||||
? siblings.findIndex((layer) => layer.id === options.sourceLayerId)
|
||||
: -1;
|
||||
const rawIndex = verticalRatio < 0.5 ? targetIndex : targetIndex + 1;
|
||||
const adjustedIndex = sourceIndex >= 0 && sourceIndex < rawIndex ? rawIndex - 1 : rawIndex;
|
||||
|
||||
return {
|
||||
layerId: options.sourceLayerId,
|
||||
toArtboardId: targetInfo.artboardId,
|
||||
toParentGroupId: targetInfo.parentGroupId,
|
||||
toIndex: adjustedIndex,
|
||||
};
|
||||
}
|
||||
|
||||
export function findLayerInfoInDocument(document: ImageDocument, layerId?: LayerId): LayerInfo | undefined {
|
||||
if (!layerId) return undefined;
|
||||
for (const artboard of document.artboards) {
|
||||
const found = findLayerInfo(artboard.layers, layerId, artboard.id);
|
||||
if (found) return found;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function findGroup(document: ImageDocument, groupId: LayerId): Extract<Layer, { type: "group" }> | undefined {
|
||||
const info = findLayerInfoInDocument(document, groupId);
|
||||
return info?.layer.type === "group" ? info.layer : undefined;
|
||||
}
|
||||
|
||||
function findLayerInfo(layers: Layer[], layerId: LayerId, artboardId: ArtboardId, parentGroupId?: LayerId): LayerInfo | undefined {
|
||||
for (const layer of layers) {
|
||||
if (layer.id === layerId) return { artboardId, parentGroupId, layer };
|
||||
if (layer.type === "group") {
|
||||
const found = findLayerInfo(layer.children, layerId, artboardId, layer.id);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
Reference in New Issue
Block a user