summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-05-02 01:33:32 +0200
committerMaze Winther <mazewinther@gmail.com>2026-05-02 03:27:23 +0200
commit8b8d65b5091f4158af68fbad85cc74936302b07b (patch)
tree53c5bb4ee0ec60ed2b9d87585230014229008cea
parent23187b0b6a9f179bdb68578fc4bdaa8414b8316d (diff)
downloadopencut-8b8d65b5091f4158af68fbad85cc74936302b07b.tar.gz
refactor: collapse mask definition registry to a single keyed registry
The freeform mask was assembled on every getMaskDefinition("freeform") call, re-spreading params and injecting a wrong SquareIcon placeholder, with a type cast to suppress the structural mismatch. Root cause: MasksRegistry was keyed on BuiltinMaskType, so freeform had no entry. - Re-key MasksRegistry from BuiltinMaskType to MaskType - Register freeform alongside builtins in registerDefaultMasks, with PenToolAddIcon as its menu icon - getMaskDefinition and getMaskDefinitionsForMenu become plain registry lookups with no branching, no manual spreading, no cast - Rename RegisteredBuiltinMaskDefinition to RegisteredMaskDefinition and tighten computeParamUpdate return type to Partial<BaseMaskParams> Co-authored-by: Cursor <cursoragent@cursor.com>
-rw-r--r--apps/web/src/masks/builtin/definitions/index.ts18
-rw-r--r--apps/web/src/masks/index.ts36
-rw-r--r--apps/web/src/masks/registry.ts23
3 files changed, 30 insertions, 47 deletions
diff --git a/apps/web/src/masks/builtin/definitions/index.ts b/apps/web/src/masks/builtin/definitions/index.ts
index 9f722876..5deb4e3f 100644
--- a/apps/web/src/masks/builtin/definitions/index.ts
+++ b/apps/web/src/masks/builtin/definitions/index.ts
@@ -1,6 +1,6 @@
import {
- builtinMasksRegistry,
- type BuiltinMaskDefinitionForRegistration,
+ masksRegistry,
+ type MaskDefinitionForRegistration,
type MaskIconProps,
} from "../../registry";
import { cinematicBarsMaskDefinition } from "./cinematic-bars";
@@ -11,6 +11,7 @@ import { rectangleMaskDefinition } from "./rectangle";
import { splitMaskDefinition } from "./split";
import { starMaskDefinition } from "./star";
import { textMaskDefinition } from "./text";
+import { freeformMaskDefinition } from "../../freeform/definition";
import {
MinusSignIcon,
PanelRightDashedIcon,
@@ -20,23 +21,24 @@ import {
DiamondIcon,
StarsIcon,
TextFontIcon,
+ PenToolAddIcon,
} from "@hugeicons/core-free-icons";
function registerDefaultMask({
definition,
icon,
}: {
- definition: BuiltinMaskDefinitionForRegistration;
+ definition: MaskDefinitionForRegistration;
icon: MaskIconProps;
}) {
- if (builtinMasksRegistry.has(definition.type)) {
+ if (masksRegistry.has(definition.type)) {
return;
}
- builtinMasksRegistry.registerMask({ definition, icon });
+ masksRegistry.registerMask({ definition, icon });
}
-export function registerBuiltinMasks(): void {
+export function registerDefaultMasks(): void {
registerDefaultMask({
definition: splitMaskDefinition,
icon: { icon: PanelRightDashedIcon, strokeWidth: 1 },
@@ -69,4 +71,8 @@ export function registerBuiltinMasks(): void {
definition: textMaskDefinition,
icon: { icon: TextFontIcon },
});
+ registerDefaultMask({
+ definition: freeformMaskDefinition,
+ icon: { icon: PenToolAddIcon },
+ });
}
diff --git a/apps/web/src/masks/index.ts b/apps/web/src/masks/index.ts
index be5faef7..994f05f2 100644
--- a/apps/web/src/masks/index.ts
+++ b/apps/web/src/masks/index.ts
@@ -1,15 +1,9 @@
import type { Mask, MaskDefaultContext, MaskType } from "@/masks/types";
-import {
- BASE_MASK_PARAM_DEFINITIONS,
- builtinMasksRegistry,
- type RegisteredBuiltinMaskDefinition,
-} from "./registry";
-import { freeformMaskDefinition } from "./freeform/definition";
+import { masksRegistry } from "./registry";
import { generateUUID } from "@/utils/id";
-import { SquareIcon } from "@hugeicons/core-free-icons";
-export { builtinMasksRegistry } from "./registry";
-export { registerBuiltinMasks as registerDefaultMasks } from "./builtin/definitions";
+export { masksRegistry } from "./registry";
+export { registerDefaultMasks } from "./builtin/definitions";
type MaskWithoutId = Mask extends infer TMask
? TMask extends Mask
@@ -40,28 +34,12 @@ function withMaskId({ mask, id }: { mask: MaskWithoutId; id: string }): Mask {
}
}
-export function getMaskDefinition(maskType: MaskType): RegisteredBuiltinMaskDefinition {
- if (maskType === "freeform") {
- return {
- ...freeformMaskDefinition,
- params: [...freeformMaskDefinition.params, ...BASE_MASK_PARAM_DEFINITIONS],
- icon: { icon: SquareIcon },
- } as RegisteredBuiltinMaskDefinition;
- }
-
- return builtinMasksRegistry.get(maskType);
+export function getMaskDefinition(maskType: MaskType) {
+ return masksRegistry.get(maskType);
}
export function getMaskDefinitionsForMenu() {
- return [
- ...builtinMasksRegistry.getAll(),
- {
- ...freeformMaskDefinition,
- name: "Pen tool",
- params: [...freeformMaskDefinition.params, ...BASE_MASK_PARAM_DEFINITIONS],
- icon: { icon: SquareIcon },
- },
- ];
+ return masksRegistry.getAll();
}
export function buildDefaultMaskInstance({
@@ -71,7 +49,7 @@ export function buildDefaultMaskInstance({
maskType: MaskType;
elementSize?: { width: number; height: number };
}): Mask {
- const definition = getMaskDefinition(maskType);
+ const definition = masksRegistry.get(maskType);
const context: MaskDefaultContext = { elementSize };
return withMaskId({
mask: definition.buildDefault(context),
diff --git a/apps/web/src/masks/registry.ts b/apps/web/src/masks/registry.ts
index 77861926..35d215c6 100644
--- a/apps/web/src/masks/registry.ts
+++ b/apps/web/src/masks/registry.ts
@@ -2,7 +2,6 @@ import { MAX_FEATHER } from "@/masks/feather";
import type { ParamDefinition } from "@/params";
import type {
BaseMaskParams,
- BuiltinMaskType,
Mask,
MaskDefaultContext,
MaskDefinition,
@@ -24,9 +23,9 @@ type RegisteredMaskWithoutId = Mask extends infer TMask
: never
: never;
-export type BuiltinMaskDefinitionForRegistration = {
- [TType in BuiltinMaskType]: MaskDefinition<TType>;
-}[BuiltinMaskType];
+export type MaskDefinitionForRegistration = {
+ [TType in MaskType]: MaskDefinition<TType>;
+}[MaskType];
export const BASE_MASK_PARAM_DEFINITIONS: ParamDefinition<
keyof BaseMaskParams & string
@@ -58,7 +57,7 @@ export const BASE_MASK_PARAM_DEFINITIONS: ParamDefinition<
},
];
-export interface RegisteredBuiltinMaskDefinition {
+export interface RegisteredMaskDefinition {
type: MaskType;
name: string;
features: MaskDefinition["features"];
@@ -69,13 +68,13 @@ export interface RegisteredBuiltinMaskDefinition {
buildDefault(context: MaskDefaultContext): RegisteredMaskWithoutId;
computeParamUpdate(
args: MaskParamUpdateArgs<BaseMaskParams>,
- ): ReturnType<MaskDefinition["computeParamUpdate"]>;
+ ): Partial<BaseMaskParams>;
icon: MaskIconProps;
}
-export class BuiltinMasksRegistry extends DefinitionRegistry<
- BuiltinMaskType,
- RegisteredBuiltinMaskDefinition
+export class MasksRegistry extends DefinitionRegistry<
+ MaskType,
+ RegisteredMaskDefinition
> {
constructor() {
super("mask");
@@ -85,10 +84,10 @@ export class BuiltinMasksRegistry extends DefinitionRegistry<
definition,
icon,
}: {
- definition: BuiltinMaskDefinitionForRegistration;
+ definition: MaskDefinitionForRegistration;
icon: MaskIconProps;
}): void {
- const withBaseParams: RegisteredBuiltinMaskDefinition = {
+ const withBaseParams: RegisteredMaskDefinition = {
type: definition.type,
name: definition.name,
features: definition.features,
@@ -107,4 +106,4 @@ export class BuiltinMasksRegistry extends DefinitionRegistry<
}
}
-export const builtinMasksRegistry = new BuiltinMasksRegistry();
+export const masksRegistry = new MasksRegistry();