/// import { type Cell, Default, derive, handler, lift, recipe, str, toSchema, } from "commontools"; interface DerivedMinMaxArgs { value: Default; history: Default; } const toInteger = (input: unknown, fallback = 0): number => { if (typeof input !== "number" || !Number.isFinite(input)) { return fallback; } return Math.trunc(input); }; const resolveAmount = (input: unknown): number => { if (typeof input !== "number" || !Number.isFinite(input)) { return 1; } return Math.trunc(input); }; const sanitizeHistory = (entries: number[] | undefined): number[] => { if (!Array.isArray(entries)) { return []; } const sanitized: number[] = []; for (const entry of entries) { sanitized.push(toInteger(entry)); } return sanitized; }; const minimumOf = (values: readonly number[]): number => { if (values.length === 0) { return 0; } let min = values[0]; for (const value of values) { if (value < min) { min = value; } } return min; }; const maximumOf = (values: readonly number[]): number => { if (values.length === 0) { return 0; } let max = values[0]; for (const value of values) { if (value > max) { max = value; } } return max; }; const adjustCounter = handler( ( event: { amount?: number } | undefined, context: { value: Cell; history: Cell }, ) => { const amount = resolveAmount(event?.amount); const current = toInteger(context.value.get()); const next = current + amount; context.value.set(next); context.history.push(next); }, ); const computeLimits = lift( toSchema<{ values: Cell; current: Cell }>(), toSchema<{ min: number; max: number }>(), ({ values, current }) => { const entries = sanitizeHistory(values.get()); const baseline = toInteger(current.get()); if (entries.length === 0) { return { min: baseline, max: baseline }; } return { min: minimumOf(entries), max: maximumOf(entries), }; }, ); export const counterWithDerivedMinMax = recipe( "Counter With Derived Min Max", ({ value, history }) => { const currentValue = lift((input: number | undefined) => toInteger(input))( value, ); const historyValues = lift(sanitizeHistory)(history); const limits = computeLimits({ values: historyValues, current: currentValue, }); const minValue = derive(limits, (snapshot) => snapshot.min); const maxValue = derive(limits, (snapshot) => snapshot.max); const label = str`Min: ${minValue}, Max: ${maxValue}`; return { value, history: historyValues, minValue, maxValue, label, adjust: adjustCounter({ value, history }), }; }, );