feat: add contextual layer inspector
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import type { Rect, Vec2D } from "@core/geometry";
|
||||
import type { Layer } from "@core/layer";
|
||||
import { applyTransformTargetBounds } from "./transform-document";
|
||||
import type { TransformHandle, TransformTarget } from "@editor/transform";
|
||||
import type { Command } from "./command";
|
||||
import { commandIds } from "./ids";
|
||||
import type { AppState } from "@editor/state";
|
||||
|
||||
export type TransformBeginPayload = {
|
||||
target: TransformTarget;
|
||||
@@ -21,6 +23,11 @@ export type TransformSetBoundsPayload = {
|
||||
bounds: Rect;
|
||||
};
|
||||
|
||||
export type TransformSetRotationPayload = {
|
||||
target: TransformTarget;
|
||||
rotation: number;
|
||||
};
|
||||
|
||||
export const transformBeginCommand: Command<TransformBeginPayload> = {
|
||||
id: commandIds.transformBegin,
|
||||
name: "Begin transform",
|
||||
@@ -70,6 +77,7 @@ export const transformSetBoundsCommand: Command<TransformSetBoundsPayload> = {
|
||||
id: commandIds.transformSetBounds,
|
||||
name: "Set transform bounds",
|
||||
execute({ state }, payload) {
|
||||
if (isTargetLocked(state, payload.target)) return state;
|
||||
return {
|
||||
...state,
|
||||
document: applyTransformTargetBounds(state.document, payload.target, normalizeRect(payload.bounds)),
|
||||
@@ -77,6 +85,42 @@ export const transformSetBoundsCommand: Command<TransformSetBoundsPayload> = {
|
||||
},
|
||||
};
|
||||
|
||||
export const transformSetRotationCommand: Command<TransformSetRotationPayload> = {
|
||||
id: commandIds.transformSetRotation,
|
||||
name: "Set transform rotation",
|
||||
execute({ state }, payload) {
|
||||
if (payload.target.type !== "layer" || !Number.isFinite(payload.rotation) || isTargetLocked(state, payload.target)) return state;
|
||||
const location = state.document.artboards.flatMap((artboard) => findLayerInTree(artboard.layers, payload.target.id)).find(Boolean);
|
||||
if (!location || location.type === "group") return state;
|
||||
const maskId = "layerMask" in location ? location.layerMask?.maskLayerId : undefined;
|
||||
const ids = new Set([payload.target.id, ...(maskId ? [maskId] : [])]);
|
||||
return {
|
||||
...state,
|
||||
document: {
|
||||
...state.document,
|
||||
artboards: state.document.artboards.map((artboard) => ({ ...artboard, layers: mapRotation(artboard.layers, ids, payload.rotation) })),
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
function isTargetLocked(state: AppState, target: TransformTarget) {
|
||||
if (target.type === "artboard") return state.document.artboards.find((artboard) => artboard.id === target.id)?.locked !== false;
|
||||
return state.document.artboards.flatMap((artboard) => findLayerInTree(artboard.layers, target.id)).find(Boolean)?.locked !== false;
|
||||
}
|
||||
|
||||
function findLayerInTree(layers: Layer[], id: string): Layer[] {
|
||||
return layers.flatMap((layer) => layer.id === id ? [layer] : layer.type === "group" ? findLayerInTree(layer.children, id) : []);
|
||||
}
|
||||
|
||||
function mapRotation(layers: Layer[], ids: ReadonlySet<string>, rotation: number): Layer[] {
|
||||
return layers.map((layer) => ({
|
||||
...layer,
|
||||
...(ids.has(layer.id) ? { transform: { ...layer.transform, rotation } } : {}),
|
||||
...(layer.type === "group" ? { children: mapRotation(layer.children, ids, rotation) } : {}),
|
||||
})) as Layer[];
|
||||
}
|
||||
|
||||
export const transformEndCommand: Command = {
|
||||
id: commandIds.transformEnd,
|
||||
name: "End transform",
|
||||
@@ -94,7 +138,7 @@ export const transformEndCommand: Command = {
|
||||
},
|
||||
};
|
||||
|
||||
export const transformCommands = [transformBeginCommand, transformUpdateCommand, transformSetBoundsCommand, transformEndCommand] satisfies Command<unknown>[];
|
||||
export const transformCommands = [transformBeginCommand, transformUpdateCommand, transformSetBoundsCommand, transformSetRotationCommand, transformEndCommand] satisfies Command<unknown>[];
|
||||
|
||||
function transformBounds(bounds: Rect, handle: TransformHandle, delta: Vec2D, constrained = false): Rect {
|
||||
if (handle === "body") {
|
||||
|
||||
Reference in New Issue
Block a user