diff options
Diffstat (limited to 'apps/web/src/masks/registry.ts')
| -rw-r--r-- | apps/web/src/masks/registry.ts | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/apps/web/src/masks/registry.ts b/apps/web/src/masks/registry.ts new file mode 100644 index 00000000..00b276c8 --- /dev/null +++ b/apps/web/src/masks/registry.ts @@ -0,0 +1,122 @@ +import { MAX_FEATHER } from "@/masks/feather"; +import type { ParamDefinition } from "@/params"; +import type { + BaseMaskParams, + MaskDefaultContext, + MaskDefinition, + MaskInteractionResult, + MaskSnapArgs, + MaskSnapResult, + MaskType, +} from "@/masks/types"; +import type { HugeiconsIconProps } from "@hugeicons/react"; +import { DefinitionRegistry } from "@/params/registry"; + +export type MaskIconProps = { + icon: HugeiconsIconProps["icon"]; + strokeWidth?: number; +}; + +const BASE_MASK_PARAM_DEFINITIONS: ParamDefinition< + keyof BaseMaskParams & string +>[] = [ + { + key: "feather", + label: "Feather", + type: "number", + default: 0, + min: 0, + max: MAX_FEATHER, + step: 1, + unit: "percent", + }, + { + key: "strokeWidth", + label: "Stroke width", + type: "number", + default: 0, + min: 0, + max: 100, + step: 1, + }, + { + key: "strokeColor", + label: "Stroke color", + type: "color", + default: "#ffffff", + }, +]; + +export interface RegisteredMaskDefinition { + type: MaskType; + name: string; + features: MaskDefinition<BaseMaskParams>["features"]; + params: ParamDefinition<string>[]; + renderer: MaskDefinition<BaseMaskParams>["renderer"]; + interaction: { + getInteraction(args: { + params: BaseMaskParams; + bounds: Parameters< + MaskDefinition<BaseMaskParams>["interaction"]["getInteraction"] + >[0]["bounds"]; + displayScale: number; + scaleX: number; + scaleY: number; + }): MaskInteractionResult; + snap?(args: MaskSnapArgs<BaseMaskParams>): MaskSnapResult<BaseMaskParams>; + }; + isActive?: (params: BaseMaskParams) => boolean; + buildDefault( + context: MaskDefaultContext, + ): ReturnType<MaskDefinition<BaseMaskParams>["buildDefault"]>; + computeParamUpdate( + args: Parameters<MaskDefinition<BaseMaskParams>["computeParamUpdate"]>[0], + ): ReturnType<MaskDefinition<BaseMaskParams>["computeParamUpdate"]>; + icon: MaskIconProps; +} + +export class MasksRegistry extends DefinitionRegistry< + MaskType, + RegisteredMaskDefinition +> { + constructor() { + super("mask"); + } + + registerMask<TParams extends BaseMaskParams>({ + definition, + icon, + }: { + definition: MaskDefinition<TParams>; + icon: MaskIconProps; + }): void { + const withBaseParams: RegisteredMaskDefinition = { + type: definition.type, + name: definition.name, + features: definition.features, + params: [...definition.params, ...BASE_MASK_PARAM_DEFINITIONS], + renderer: definition.renderer, + interaction: { + getInteraction(args) { + return definition.interaction.getInteraction(args as never); + }, + snap: definition.interaction.snap + ? (args) => definition.interaction.snap?.(args as never) as never + : undefined, + }, + isActive: definition.isActive + ? (params) => definition.isActive?.(params as TParams) ?? true + : undefined, + buildDefault(context) { + return definition.buildDefault(context); + }, + computeParamUpdate(args) { + return definition.computeParamUpdate(args as never); + }, + icon, + }; + this.register(definition.type, withBaseParams); + } +} + +export const masksRegistry = new MasksRegistry(); |
