diff --git a/src/composables/alignHandler.spec.ts b/src/composables/alignHandler.spec.ts index 78bf7589..8e053f0d 100644 --- a/src/composables/alignHandler.spec.ts +++ b/src/composables/alignHandler.spec.ts @@ -1,5 +1,5 @@ import { describe, test, expect } from "vitest"; -import { getModifiedAlignRootIds, getNextAlignLayout, newAlignBoxHandler } from "./alignHandler"; +import { canAttendToAlignBox, getModifiedAlignRootIds, getNextAlignLayout, newAlignBoxHandler } from "./alignHandler"; import { createShape, getCommonStruct } from "../shapes"; import { AlignBoxShape } from "../shapes/align/alignBox"; import { RectangleShape } from "../shapes/rectangle"; @@ -260,3 +260,39 @@ describe("getModifiedAlignRootIds", () => { expect(getModifiedAlignRootIds(srcComposite, updatedComposite, patchInfo)).toEqual([box0.id]); }); }); + +describe("canAttendToAlignBox", () => { + test("should return true when a shape can attend to align box", () => { + const rect0 = createShape(getCommonStruct, "rectangle", { + id: "rect0", + }); + const line0 = createShape(getCommonStruct, "line", { + id: "line0", + }); + const label0 = createShape(getCommonStruct, "text", { + id: "label0", + parentId: line0.id, + }); + const group0 = createShape(getCommonStruct, "group", { + id: "group0", + }); + const child0 = createShape(getCommonStruct, "rectangle", { + id: "child0", + parentId: group0.id, + }); + const child1 = createShape(getCommonStruct, "rectangle", { + id: "child1", + parentId: "unknown", + }); + const shapeComposite = newShapeComposite({ + shapes: [rect0, line0, label0, group0, child0, child1], + getStruct: getCommonStruct, + }); + expect(canAttendToAlignBox(shapeComposite, rect0)).toBe(true); + expect(canAttendToAlignBox(shapeComposite, line0)).toBe(false); + expect(canAttendToAlignBox(shapeComposite, label0)).toBe(false); + expect(canAttendToAlignBox(shapeComposite, group0)).toBe(true); + expect(canAttendToAlignBox(shapeComposite, child0)).toBe(false); + expect(canAttendToAlignBox(shapeComposite, child1)).toBe(true); + }); +}); diff --git a/src/composables/alignHandler.ts b/src/composables/alignHandler.ts index c30fec68..dade1cd2 100644 --- a/src/composables/alignHandler.ts +++ b/src/composables/alignHandler.ts @@ -36,6 +36,8 @@ import { applyFillStyle } from "../utils/fillStyle"; import { renderArrowUnit, renderValueLabel } from "../utils/renderer"; import { COLORS } from "../utils/color"; import { getPaddingRect } from "../utils/boxPadding"; +import { isLineShape } from "../shapes/line"; +import { isGroupShape } from "../shapes/group"; export type AlignHitResult = { seg: ISegment; @@ -876,6 +878,15 @@ export function getModifiedAlignRootIds( return Array.from(targetRootIdSet).filter((id) => !deletedRootIdSet.has(id)); } +export function canAttendToAlignBox(shapeComposite: ShapeComposite, shape: Shape): boolean { + if (isLineShape(shape)) return false; + return ( + !shape.parentId || + !shapeComposite.shapeMap[shape.parentId] || + !isGroupShape(shapeComposite.shapeMap[shape.parentId]) + ); +} + export function generateAlignTemplate( ctx: Pick, ): { shapes: Shape[]; docMap: { [id: string]: DocOutput } } { diff --git a/src/composables/states/appCanvas/align/movingShapeInAlignState.ts b/src/composables/states/appCanvas/align/movingShapeInAlignState.ts index b77716ea..56e7de46 100644 --- a/src/composables/states/appCanvas/align/movingShapeInAlignState.ts +++ b/src/composables/states/appCanvas/align/movingShapeInAlignState.ts @@ -15,7 +15,7 @@ import { Shape } from "../../../../models"; import { BoundingBox } from "../../../boundingBox"; import { getPatchByLayouts } from "../../../shapeLayoutHandler"; import { generateKeyBetweenAllowSame } from "../../../../utils/findex"; -import { AlignHitResult, AlignHandler, newAlignHandler } from "../../../alignHandler"; +import { AlignHitResult, AlignHandler, newAlignHandler, canAttendToAlignBox } from "../../../alignHandler"; import { AlignBoxShape } from "../../../../shapes/align/alignBox"; interface Option { @@ -45,9 +45,13 @@ export function newMovingShapeInAlignState(option: Option): AppCanvasState { return { getLabel: () => "MovingShapeInAlign", onStart: (ctx) => { - const shapeMap = ctx.getShapeComposite().shapeMap; + const shapeComposite = ctx.getShapeComposite(); + const shapeMap = shapeComposite.shapeMap; const ids = Object.keys(ctx.getSelectedShapeIdMap()); - shapes = ids.map((id) => shapeMap[id]).sort(findexSortFn); + shapes = ids + .map((id) => shapeMap[id]) + .filter((s) => canAttendToAlignBox(shapeComposite, s)) + .sort(findexSortFn); initHandler(ctx); ctx.setTmpShapeMap({}); diff --git a/src/composables/states/appCanvas/movingShapeLayoutHandler.ts b/src/composables/states/appCanvas/movingShapeLayoutHandler.ts index 2ed85eb6..76475501 100644 --- a/src/composables/states/appCanvas/movingShapeLayoutHandler.ts +++ b/src/composables/states/appCanvas/movingShapeLayoutHandler.ts @@ -1,7 +1,7 @@ import { Shape } from "../../../models"; import { AlignBoxShape } from "../../../shapes/align/alignBox"; -import { isGroupShape } from "../../../shapes/group"; import { mapReduce } from "../../../utils/commons"; +import { canAttendToAlignBox } from "../../alignHandler"; import { BoundingBox } from "../../boundingBox"; import { findBetterShapeAt, getClosestShapeByType } from "../../shapeComposite"; import { getPatchByLayouts } from "../../shapeLayoutHandler"; @@ -52,10 +52,6 @@ export function getPatchByPointerUpOutsideLayout( function canAlign(ctx: AppCanvasStateContext) { const shapeComposite = ctx.getShapeComposite(); - const indexShape = shapeComposite.shapeMap[ctx.getLastSelectedShapeId()!]; - return ( - !indexShape.parentId || - !shapeComposite.shapeMap[indexShape.parentId] || - !isGroupShape(shapeComposite.shapeMap[indexShape.parentId]) - ); + const ids = Object.keys(ctx.getSelectedShapeIdMap()); + return ids.some((id) => canAttendToAlignBox(shapeComposite, shapeComposite.shapeMap[id])); }