import type { BaseInputorContext, BaseInputorControllerOptions, BaseInputorSchema, InputorControllerInitializeHooks, } from "./base.ts" import { BaseInputorController } from "./base.ts" interface InternalNumberConstraints { min?: number | undefined max?: number | undefined step?: number | undefined } const internalConstrainNumber = (value: number, constraints: InternalNumberConstraints): number => { let constrainedValue = value if (constraints.step !== undefined) { constrainedValue = Math.round(constrainedValue / constraints.step) * constraints.step } if (constraints.min !== undefined) { constrainedValue = Math.max(constraints.min, constrainedValue) } if (constraints.max !== undefined) { constrainedValue = Math.min(constraints.max, constrainedValue) } return constrainedValue } export const NUMBER_INPUTOR_TYPE_NAME = "number" as const export type NumberInputorTypeName = typeof NUMBER_INPUTOR_TYPE_NAME export type NumberInputorExternalValue = number | undefined export type NumberInputorInternalValue = number | undefined export interface NumberInputorSchema extends BaseInputorSchema { inputorTypeName: NumberInputorTypeName min?: number | undefined max?: number | undefined step?: number | undefined } export interface NumberInputorContext extends BaseInputorContext< NumberInputorExternalValue, NumberInputorInternalValue > {} export interface NumberInputorControllerOptions extends BaseInputorControllerOptions< NumberInputorExternalValue, NumberInputorSchema > { min?: number | undefined max?: number | undefined step?: number | undefined } export class NumberInputorController extends BaseInputorController< NumberInputorExternalValue, NumberInputorInternalValue, NumberInputorSchema, NumberInputorContext > { declare schemaType: NumberInputorSchema declare optionsType: NumberInputorControllerOptions declare constructorType: typeof NumberInputorController static inputorTypeName: NumberInputorTypeName = NUMBER_INPUTOR_TYPE_NAME inputorTypeName: NumberInputorTypeName = NUMBER_INPUTOR_TYPE_NAME voidExternalValue = undefined voidInternalValue = undefined private min: number | undefined private max: number | undefined private step: number | undefined constructor(options: NumberInputorControllerOptions) { super(options) } protected override async initialize( options: NumberInputorControllerOptions, hooks?: InputorControllerInitializeHooks, ): Promise { await super.initialize(options, { ...hooks, onSchemaReady: async () => { this.min = options.min this.max = options.max this.step = options.step await hooks?.onSchemaReady?.() }, }) } override async getSchema(): Promise { return { ...(await super.getSchema()), min: this.min, max: this.max, step: this.step, } } override async constrainExternalValue( externalValue: NumberInputorExternalValue, ): Promise { if (externalValue === undefined) { return await Promise.resolve(undefined) } const constrainedValue = internalConstrainNumber(externalValue, { min: this.min, max: this.max, step: this.step, }) return await Promise.resolve(constrainedValue) } override async constrainInternalValue( internalValue: NumberInputorInternalValue, ): Promise { if (internalValue === undefined) { return await Promise.resolve(undefined) } const constrainedValue = internalConstrainNumber(internalValue, { min: this.min, max: this.max, step: this.step, }) return await Promise.resolve(constrainedValue) } }