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>
This commit is contained in:
parent
23187b0b6a
commit
8b8d65b509
|
|
@ -1,6 +1,6 @@
|
||||||
import {
|
import {
|
||||||
builtinMasksRegistry,
|
masksRegistry,
|
||||||
type BuiltinMaskDefinitionForRegistration,
|
type MaskDefinitionForRegistration,
|
||||||
type MaskIconProps,
|
type MaskIconProps,
|
||||||
} from "../../registry";
|
} from "../../registry";
|
||||||
import { cinematicBarsMaskDefinition } from "./cinematic-bars";
|
import { cinematicBarsMaskDefinition } from "./cinematic-bars";
|
||||||
|
|
@ -11,6 +11,7 @@ import { rectangleMaskDefinition } from "./rectangle";
|
||||||
import { splitMaskDefinition } from "./split";
|
import { splitMaskDefinition } from "./split";
|
||||||
import { starMaskDefinition } from "./star";
|
import { starMaskDefinition } from "./star";
|
||||||
import { textMaskDefinition } from "./text";
|
import { textMaskDefinition } from "./text";
|
||||||
|
import { freeformMaskDefinition } from "../../freeform/definition";
|
||||||
import {
|
import {
|
||||||
MinusSignIcon,
|
MinusSignIcon,
|
||||||
PanelRightDashedIcon,
|
PanelRightDashedIcon,
|
||||||
|
|
@ -20,23 +21,24 @@ import {
|
||||||
DiamondIcon,
|
DiamondIcon,
|
||||||
StarsIcon,
|
StarsIcon,
|
||||||
TextFontIcon,
|
TextFontIcon,
|
||||||
|
PenToolAddIcon,
|
||||||
} from "@hugeicons/core-free-icons";
|
} from "@hugeicons/core-free-icons";
|
||||||
|
|
||||||
function registerDefaultMask({
|
function registerDefaultMask({
|
||||||
definition,
|
definition,
|
||||||
icon,
|
icon,
|
||||||
}: {
|
}: {
|
||||||
definition: BuiltinMaskDefinitionForRegistration;
|
definition: MaskDefinitionForRegistration;
|
||||||
icon: MaskIconProps;
|
icon: MaskIconProps;
|
||||||
}) {
|
}) {
|
||||||
if (builtinMasksRegistry.has(definition.type)) {
|
if (masksRegistry.has(definition.type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
builtinMasksRegistry.registerMask({ definition, icon });
|
masksRegistry.registerMask({ definition, icon });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerBuiltinMasks(): void {
|
export function registerDefaultMasks(): void {
|
||||||
registerDefaultMask({
|
registerDefaultMask({
|
||||||
definition: splitMaskDefinition,
|
definition: splitMaskDefinition,
|
||||||
icon: { icon: PanelRightDashedIcon, strokeWidth: 1 },
|
icon: { icon: PanelRightDashedIcon, strokeWidth: 1 },
|
||||||
|
|
@ -69,4 +71,8 @@ export function registerBuiltinMasks(): void {
|
||||||
definition: textMaskDefinition,
|
definition: textMaskDefinition,
|
||||||
icon: { icon: TextFontIcon },
|
icon: { icon: TextFontIcon },
|
||||||
});
|
});
|
||||||
|
registerDefaultMask({
|
||||||
|
definition: freeformMaskDefinition,
|
||||||
|
icon: { icon: PenToolAddIcon },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,9 @@
|
||||||
import type { Mask, MaskDefaultContext, MaskType } from "@/masks/types";
|
import type { Mask, MaskDefaultContext, MaskType } from "@/masks/types";
|
||||||
import {
|
import { masksRegistry } from "./registry";
|
||||||
BASE_MASK_PARAM_DEFINITIONS,
|
|
||||||
builtinMasksRegistry,
|
|
||||||
type RegisteredBuiltinMaskDefinition,
|
|
||||||
} from "./registry";
|
|
||||||
import { freeformMaskDefinition } from "./freeform/definition";
|
|
||||||
import { generateUUID } from "@/utils/id";
|
import { generateUUID } from "@/utils/id";
|
||||||
import { SquareIcon } from "@hugeicons/core-free-icons";
|
|
||||||
|
|
||||||
export { builtinMasksRegistry } from "./registry";
|
export { masksRegistry } from "./registry";
|
||||||
export { registerBuiltinMasks as registerDefaultMasks } from "./builtin/definitions";
|
export { registerDefaultMasks } from "./builtin/definitions";
|
||||||
|
|
||||||
type MaskWithoutId = Mask extends infer TMask
|
type MaskWithoutId = Mask extends infer TMask
|
||||||
? TMask extends Mask
|
? TMask extends Mask
|
||||||
|
|
@ -40,28 +34,12 @@ function withMaskId({ mask, id }: { mask: MaskWithoutId; id: string }): Mask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMaskDefinition(maskType: MaskType): RegisteredBuiltinMaskDefinition {
|
export function getMaskDefinition(maskType: MaskType) {
|
||||||
if (maskType === "freeform") {
|
return masksRegistry.get(maskType);
|
||||||
return {
|
|
||||||
...freeformMaskDefinition,
|
|
||||||
params: [...freeformMaskDefinition.params, ...BASE_MASK_PARAM_DEFINITIONS],
|
|
||||||
icon: { icon: SquareIcon },
|
|
||||||
} as RegisteredBuiltinMaskDefinition;
|
|
||||||
}
|
|
||||||
|
|
||||||
return builtinMasksRegistry.get(maskType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMaskDefinitionsForMenu() {
|
export function getMaskDefinitionsForMenu() {
|
||||||
return [
|
return masksRegistry.getAll();
|
||||||
...builtinMasksRegistry.getAll(),
|
|
||||||
{
|
|
||||||
...freeformMaskDefinition,
|
|
||||||
name: "Pen tool",
|
|
||||||
params: [...freeformMaskDefinition.params, ...BASE_MASK_PARAM_DEFINITIONS],
|
|
||||||
icon: { icon: SquareIcon },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildDefaultMaskInstance({
|
export function buildDefaultMaskInstance({
|
||||||
|
|
@ -71,7 +49,7 @@ export function buildDefaultMaskInstance({
|
||||||
maskType: MaskType;
|
maskType: MaskType;
|
||||||
elementSize?: { width: number; height: number };
|
elementSize?: { width: number; height: number };
|
||||||
}): Mask {
|
}): Mask {
|
||||||
const definition = getMaskDefinition(maskType);
|
const definition = masksRegistry.get(maskType);
|
||||||
const context: MaskDefaultContext = { elementSize };
|
const context: MaskDefaultContext = { elementSize };
|
||||||
return withMaskId({
|
return withMaskId({
|
||||||
mask: definition.buildDefault(context),
|
mask: definition.buildDefault(context),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import { MAX_FEATHER } from "@/masks/feather";
|
||||||
import type { ParamDefinition } from "@/params";
|
import type { ParamDefinition } from "@/params";
|
||||||
import type {
|
import type {
|
||||||
BaseMaskParams,
|
BaseMaskParams,
|
||||||
BuiltinMaskType,
|
|
||||||
Mask,
|
Mask,
|
||||||
MaskDefaultContext,
|
MaskDefaultContext,
|
||||||
MaskDefinition,
|
MaskDefinition,
|
||||||
|
|
@ -24,9 +23,9 @@ type RegisteredMaskWithoutId = Mask extends infer TMask
|
||||||
: never
|
: never
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
export type BuiltinMaskDefinitionForRegistration = {
|
export type MaskDefinitionForRegistration = {
|
||||||
[TType in BuiltinMaskType]: MaskDefinition<TType>;
|
[TType in MaskType]: MaskDefinition<TType>;
|
||||||
}[BuiltinMaskType];
|
}[MaskType];
|
||||||
|
|
||||||
export const BASE_MASK_PARAM_DEFINITIONS: ParamDefinition<
|
export const BASE_MASK_PARAM_DEFINITIONS: ParamDefinition<
|
||||||
keyof BaseMaskParams & string
|
keyof BaseMaskParams & string
|
||||||
|
|
@ -58,7 +57,7 @@ export const BASE_MASK_PARAM_DEFINITIONS: ParamDefinition<
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export interface RegisteredBuiltinMaskDefinition {
|
export interface RegisteredMaskDefinition {
|
||||||
type: MaskType;
|
type: MaskType;
|
||||||
name: string;
|
name: string;
|
||||||
features: MaskDefinition["features"];
|
features: MaskDefinition["features"];
|
||||||
|
|
@ -69,13 +68,13 @@ export interface RegisteredBuiltinMaskDefinition {
|
||||||
buildDefault(context: MaskDefaultContext): RegisteredMaskWithoutId;
|
buildDefault(context: MaskDefaultContext): RegisteredMaskWithoutId;
|
||||||
computeParamUpdate(
|
computeParamUpdate(
|
||||||
args: MaskParamUpdateArgs<BaseMaskParams>,
|
args: MaskParamUpdateArgs<BaseMaskParams>,
|
||||||
): ReturnType<MaskDefinition["computeParamUpdate"]>;
|
): Partial<BaseMaskParams>;
|
||||||
icon: MaskIconProps;
|
icon: MaskIconProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BuiltinMasksRegistry extends DefinitionRegistry<
|
export class MasksRegistry extends DefinitionRegistry<
|
||||||
BuiltinMaskType,
|
MaskType,
|
||||||
RegisteredBuiltinMaskDefinition
|
RegisteredMaskDefinition
|
||||||
> {
|
> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super("mask");
|
super("mask");
|
||||||
|
|
@ -85,10 +84,10 @@ export class BuiltinMasksRegistry extends DefinitionRegistry<
|
||||||
definition,
|
definition,
|
||||||
icon,
|
icon,
|
||||||
}: {
|
}: {
|
||||||
definition: BuiltinMaskDefinitionForRegistration;
|
definition: MaskDefinitionForRegistration;
|
||||||
icon: MaskIconProps;
|
icon: MaskIconProps;
|
||||||
}): void {
|
}): void {
|
||||||
const withBaseParams: RegisteredBuiltinMaskDefinition = {
|
const withBaseParams: RegisteredMaskDefinition = {
|
||||||
type: definition.type,
|
type: definition.type,
|
||||||
name: definition.name,
|
name: definition.name,
|
||||||
features: definition.features,
|
features: definition.features,
|
||||||
|
|
@ -107,4 +106,4 @@ export class BuiltinMasksRegistry extends DefinitionRegistry<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const builtinMasksRegistry = new BuiltinMasksRegistry();
|
export const masksRegistry = new MasksRegistry();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue