summaryrefslogtreecommitdiff
path: root/apps/web/src/masks/snap.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-04-29 18:23:08 +0200
committerMaze Winther <mazewinther@gmail.com>2026-05-02 03:27:23 +0200
commit6ea5a156b6b7f609354a4563cfb2d00ec7f41811 (patch)
treee91a5e474867f5c37299cfe96a99ee24cc0a5866 /apps/web/src/masks/snap.ts
parent401cc35743aafc4c8bdfb8055501650390bde88b (diff)
downloadopencut-6ea5a156b6b7f609354a4563cfb2d00ec7f41811.tar.gz
refactor: split mask snap dispatch
Made-with: Cursor
Diffstat (limited to 'apps/web/src/masks/snap.ts')
-rw-r--r--apps/web/src/masks/snap.ts110
1 files changed, 75 insertions, 35 deletions
diff --git a/apps/web/src/masks/snap.ts b/apps/web/src/masks/snap.ts
index cff62ebb..67a0225d 100644
--- a/apps/web/src/masks/snap.ts
+++ b/apps/web/src/masks/snap.ts
@@ -6,23 +6,19 @@ import {
snapScale,
snapScaleAxes,
type ScaleEdgePreference,
- type SnapLine,
} from "@/preview/preview-snap";
-import type { RectangleMaskParams, SplitMaskParams } from "@/masks/types";
+import type {
+ MaskSnapArgs,
+ MaskSnapResult,
+ RectangleMaskParams,
+ SplitMaskParams,
+} from "@/masks/types";
import {
- isRectangleMaskParams,
getMaskSnapGeometry,
setMaskLocalCenter,
toGlobalMaskSnapLines,
} from "./geometry";
-type SharedMaskParams = SplitMaskParams | RectangleMaskParams;
-
-type MaskSnapResult<TParams extends SharedMaskParams> = {
- params: TParams;
- activeLines: SnapLine[];
-};
-
const CORNER_SIZE_HANDLES = new Set([
"top-left",
"top-right",
@@ -75,11 +71,33 @@ function snapMaskPosition({
canvasSize,
snapThreshold,
}: {
- proposedParams: SharedMaskParams;
+ proposedParams: RectangleMaskParams;
+ bounds: ElementBounds;
+ canvasSize: { width: number; height: number };
+ snapThreshold: { x: number; y: number };
+}): MaskSnapResult<RectangleMaskParams>;
+function snapMaskPosition({
+ proposedParams,
+ bounds,
+ canvasSize,
+ snapThreshold,
+}: {
+ proposedParams: SplitMaskParams;
bounds: ElementBounds;
canvasSize: { width: number; height: number };
snapThreshold: { x: number; y: number };
-}): MaskSnapResult<SharedMaskParams> {
+}): MaskSnapResult<SplitMaskParams>;
+function snapMaskPosition({
+ proposedParams,
+ bounds,
+ canvasSize,
+ snapThreshold,
+}: {
+ proposedParams: RectangleMaskParams | SplitMaskParams;
+ bounds: ElementBounds;
+ canvasSize: { width: number; height: number };
+ snapThreshold: { x: number; y: number };
+}): MaskSnapResult<RectangleMaskParams | SplitMaskParams> {
const geometry = getMaskSnapGeometry({
params: proposedParams,
bounds,
@@ -115,12 +133,18 @@ function snapMaskPosition({
function snapMaskRotation({
proposedParams,
}: {
- proposedParams: SharedMaskParams;
-}): MaskSnapResult<SharedMaskParams> {
- if (typeof proposedParams.rotation !== "number") {
- return { params: proposedParams, activeLines: [] };
- }
-
+ proposedParams: RectangleMaskParams;
+}): MaskSnapResult<RectangleMaskParams>;
+function snapMaskRotation({
+ proposedParams,
+}: {
+ proposedParams: SplitMaskParams;
+}): MaskSnapResult<SplitMaskParams>;
+function snapMaskRotation({
+ proposedParams,
+}: {
+ proposedParams: RectangleMaskParams | SplitMaskParams;
+}): MaskSnapResult<RectangleMaskParams | SplitMaskParams> {
const { snappedRotation } = snapRotation({
proposedRotation: proposedParams.rotation,
});
@@ -143,19 +167,12 @@ function snapBoxMaskSize({
snapThreshold,
}: {
handleId: string;
- startParams: SharedMaskParams;
- proposedParams: SharedMaskParams;
+ startParams: RectangleMaskParams;
+ proposedParams: RectangleMaskParams;
bounds: ElementBounds;
canvasSize: { width: number; height: number };
snapThreshold: { x: number; y: number };
-}): MaskSnapResult<SharedMaskParams> {
- if (
- !isRectangleMaskParams(startParams) ||
- !isRectangleMaskParams(proposedParams)
- ) {
- return { params: proposedParams, activeLines: [] };
- }
-
+}): MaskSnapResult<RectangleMaskParams> {
const geometry = getMaskSnapGeometry({
params: proposedParams,
bounds,
@@ -297,7 +314,7 @@ function snapBoxMaskSize({
return { params: proposedParams, activeLines: [] };
}
-export function snapMaskInteraction<TParams extends SharedMaskParams>({
+export function snapBoxMaskInteraction({
handleId,
startParams,
proposedParams,
@@ -306,23 +323,23 @@ export function snapMaskInteraction<TParams extends SharedMaskParams>({
snapThreshold,
}: {
handleId: string;
- startParams: TParams;
- proposedParams: TParams;
+ startParams: RectangleMaskParams;
+ proposedParams: RectangleMaskParams;
bounds: ElementBounds;
canvasSize: { width: number; height: number };
snapThreshold: { x: number; y: number };
-}): MaskSnapResult<TParams> {
+}): MaskSnapResult<RectangleMaskParams> {
if (handleId === "position") {
return snapMaskPosition({
proposedParams,
bounds,
canvasSize,
snapThreshold,
- }) as MaskSnapResult<TParams>;
+ });
}
if (handleId === "rotation") {
- return snapMaskRotation({ proposedParams }) as MaskSnapResult<TParams>;
+ return snapMaskRotation({ proposedParams });
}
return snapBoxMaskSize({
@@ -332,5 +349,28 @@ export function snapMaskInteraction<TParams extends SharedMaskParams>({
bounds,
canvasSize,
snapThreshold,
- }) as MaskSnapResult<TParams>;
+ });
+}
+
+export function snapSplitMaskInteraction({
+ handleId,
+ proposedParams,
+ bounds,
+ canvasSize,
+ snapThreshold,
+}: MaskSnapArgs<SplitMaskParams>): MaskSnapResult<SplitMaskParams> {
+ if (handleId === "position") {
+ return snapMaskPosition({
+ proposedParams,
+ bounds,
+ canvasSize,
+ snapThreshold,
+ });
+ }
+
+ if (handleId === "rotation") {
+ return snapMaskRotation({ proposedParams });
+ }
+
+ return { params: proposedParams, activeLines: [] };
}