/// import { Cell, cell, Default, handler, lift, recipe, str } from "commontools"; interface RenderTreeArgs { value: Default; step: Default; } interface AdjustContext { value: Cell; step: Cell; direction: Cell; } const adjustValue = handler( ( event: { amount?: number } | undefined, context: AdjustContext, ) => { const direction = context.direction.get() ?? 1; const stepValue = context.step.get(); const fallback = typeof stepValue === "number" && stepValue !== 0 ? stepValue : 1; const amount = typeof event?.amount === "number" ? event.amount : fallback; const current = context.value.get() ?? 0; context.value.set(current + direction * amount); }, ); const normalizeNumber = (input: number | undefined, fallback: number) => { return typeof input === "number" && Number.isFinite(input) ? input : fallback; }; export const counterWithRenderTree = recipe( "Counter With Render Tree", ({ value, step }) => { const safeStep = lift((raw: number | undefined) => normalizeNumber(raw, 1))( step, ); const safeValue = lift((raw: number | undefined) => normalizeNumber(raw, 0) )(value); const increment = adjustValue({ value, step: safeStep, direction: cell(1), }); const decrement = adjustValue({ value, step: safeStep, direction: cell(-1), }); const heading = str`Value ${safeValue}`; const description = str`Step size ${safeStep}`; const incrementLabel = str`Add ${safeStep}`; const decrementLabel = str`Subtract ${safeStep}`; const renderTree = { type: "counter-view", header: { text: heading }, body: { description, controls: { increase: { kind: "button", label: incrementLabel, onPress: increment, }, decrease: { kind: "button", label: decrementLabel, onPress: decrement, }, }, }, }; return { value, rawStep: step, step: safeStep, safeValue, heading, renderTree, }; }, );