import type { Rect, Vec2D } from "@core/geometry"; import type { TransformHandle, TransformTarget } from "@editor/transform"; import type { Command } from "./command"; import { commandIds } from "./ids"; export type TransformBeginPayload = { target: TransformTarget; handle: TransformHandle; point: Vec2D; initialBounds: Rect; }; export type TransformUpdatePayload = { point: Vec2D; }; export const transformBeginCommand: Command = { id: commandIds.transformBegin, name: "Begin transform", execute({ state }, payload) { return { ...state, editor: { ...state.editor, transformSession: { target: payload.target, handle: payload.handle, startPoint: payload.point, initialBounds: payload.initialBounds, }, }, }; }, }; export const transformUpdateCommand: Command = { id: commandIds.transformUpdate, name: "Update transform", execute({ state }, payload) { const session = state.editor.transformSession; if (!session) return state; const nextBounds = transformBounds(session.initialBounds, session.handle, { x: payload.point.x - session.startPoint.x, y: payload.point.y - session.startPoint.y, }); if (session.target.type === "artboard") { return { ...state, document: { ...state.document, artboards: state.document.artboards.map((artboard) => artboard.id === session.target.id ? { ...artboard, bounds: nextBounds } : artboard, ), }, }; } return state; }, }; export const transformEndCommand: Command = { id: commandIds.transformEnd, name: "End transform", execute({ state }) { if (!state.editor.transformSession) return state; return { ...state, editor: { ...state.editor, transformSession: undefined, }, }; }, }; export const transformCommands = [transformBeginCommand, transformUpdateCommand, transformEndCommand] satisfies Command[]; function transformBounds(bounds: Rect, handle: TransformHandle, delta: Vec2D): Rect { if (handle === "body") return { ...bounds, x: bounds.x + delta.x, y: bounds.y + delta.y }; let x = bounds.x; let y = bounds.y; let w = bounds.w; let h = bounds.h; if (handle.includes("w")) { x = bounds.x + delta.x; w = bounds.w - delta.x; } if (handle.includes("e")) w = bounds.w + delta.x; if (handle.includes("n")) { y = bounds.y + delta.y; h = bounds.h - delta.y; } if (handle.includes("s")) h = bounds.h + delta.y; return normalizeRect({ x, y, w, h }); } function normalizeRect(rect: Rect): Rect { const minSize = 1; return { x: rect.w < minSize ? rect.x + rect.w - minSize : rect.x, y: rect.h < minSize ? rect.y + rect.h - minSize : rect.y, w: Math.max(minSize, rect.w), h: Math.max(minSize, rect.h), }; }