From 435b79e7ed4a40c9b75fbbdbc221d83015242cff Mon Sep 17 00:00:00 2001 From: Teo | Nexcore Date: Wed, 23 Sep 2026 04:17:05 +0300 Subject: [PATCH] fix(canvas): apply region limits to snap resize --- .../features/workspace/CanvasRegionCard.tsx | 6 +++--- .../src/features/workspace/canvasRegions.ts | 19 +++++++++++++++---- tests/canvas-regions.test.mjs | 12 ++++++++++++ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/renderer/src/features/workspace/CanvasRegionCard.tsx b/src/renderer/src/features/workspace/CanvasRegionCard.tsx index d15785d3..ba1b2943 100644 --- a/src/renderer/src/features/workspace/CanvasRegionCard.tsx +++ b/src/renderer/src/features/workspace/CanvasRegionCard.tsx @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from "react"; import type { CanvasRegion, Point, SessionBounds } from "../../../../shared/contracts"; -import { constrainCanvasRegionBounds } from "./canvasRegions"; -import { snapMove, snapResize, type ResizeDirection } from "./snap"; +import { constrainCanvasRegionBounds, snapCanvasRegionBounds } from "./canvasRegions"; +import { snapMove, type ResizeDirection } from "./snap"; interface CanvasRegionCardProps { region: CanvasRegion; @@ -132,7 +132,7 @@ export function CanvasRegionCard({ - (state.direction.includes("n") ? deltaY : 0) } }, state.direction); - applyBounds(snapEnabled ? snapResize(raw, state.direction, snapTargets) : raw); + applyBounds(snapEnabled ? snapCanvasRegionBounds(raw, state.direction, snapTargets) : raw); }; const endResize = (event: React.PointerEvent): void => { diff --git a/src/renderer/src/features/workspace/canvasRegions.ts b/src/renderer/src/features/workspace/canvasRegions.ts index ef75b494..653f8185 100644 --- a/src/renderer/src/features/workspace/canvasRegions.ts +++ b/src/renderer/src/features/workspace/canvasRegions.ts @@ -1,5 +1,5 @@ -import type { CanvasRegion, Point, SessionBounds } from "../../../../shared/contracts"; -import type { ResizeDirection } from "./snap"; +import type { CanvasRegion, Point, SessionBounds, Size } from "../../../../shared/contracts"; +import { snapResize, type ResizeDirection } from "./snap.ts"; export const DEFAULT_CANVAS_REGION_SIZE = { width: 960, height: 600 } as const; export const CANVAS_REGION_COLORS = [ @@ -11,8 +11,8 @@ export const CANVAS_REGION_COLORS = [ "#D9A69A" ] as const; -const MIN_REGION_SIZE = { width: 360, height: 240 }; -const MAX_REGION_SIZE = { width: 4_000, height: 3_000 }; +export const MIN_REGION_SIZE: Size = { width: 360, height: 240 }; +export const MAX_REGION_SIZE: Size = { width: 4_000, height: 3_000 }; export function canvasRegionAtPoint( title: string, @@ -61,6 +61,17 @@ export function constrainCanvasRegionBounds( }; } +export function snapCanvasRegionBounds( + bounds: SessionBounds, + direction: ResizeDirection, + targets: readonly SessionBounds[] +): SessionBounds { + return snapResize(bounds, direction, targets, { + min: MIN_REGION_SIZE, + max: MAX_REGION_SIZE + }); +} + function clamp(value: number, min: number, max: number): number { return Math.max(min, Math.min(max, value)); } diff --git a/tests/canvas-regions.test.mjs b/tests/canvas-regions.test.mjs index 81f77c3e..ea1bff27 100644 --- a/tests/canvas-regions.test.mjs +++ b/tests/canvas-regions.test.mjs @@ -4,6 +4,7 @@ import { boundsInsideRegion, canvasRegionAtPoint, constrainCanvasRegionBounds, + snapCanvasRegionBounds, translateBounds } from "../src/renderer/src/features/workspace/canvasRegions.ts"; @@ -54,3 +55,14 @@ test("region resize keeps the opposite edge while enforcing a usable minimum", ( size: { width: 360, height: 240 } }); }); + +test("region resize preserves 1900px and 380px widths with snapping on or off", () => { + const wide = { position: { x: 100, y: 100 }, size: { width: 1_900, height: 600 } }; + const west = { position: { x: 220, y: 100 }, size: { width: 380, height: 600 } }; + + assert.deepEqual(constrainCanvasRegionBounds(wide, "e"), wide); + assert.deepEqual(snapCanvasRegionBounds(wide, "e", []), wide); + assert.deepEqual(constrainCanvasRegionBounds(west, "w"), west); + assert.deepEqual(snapCanvasRegionBounds(west, "w", []), west); + assert.equal(west.position.x + west.size.width, 600); +});