/// import { Cell, computed, Default, handler, NAME, pattern, UI, } from "commontools"; interface RecipeState { value: Default; } // In this case we do not have to type our event parameter because it is not used in the body. // By requesting a Cell we get a mutable handle when our handler is invoked. const increment = handler }>((_, state) => { state.value.set(state.value.get() + 1); }); // This can also be done with inline types + inference const decrement = handler((_, state: { value: Cell }) => { state.value.set(state.value.get() - 1); }); function previous(value: number) { return value - 1; } function nth(value: number) { if (value === 1) { return "1st"; } if (value === 2) { return "2nd"; } if (value === 3) { return "3rd"; } return `${value}th`; } export const Counter = pattern((state) => { return { // computed() is used to create reactive derived values [NAME]: computed(() => `Simple counter: ${state.value}`), [UI]: (
{ /* Even though we could end up passing extra data to decrement, our schema prevents that actually reaching the handler. In fact, we are passing `value` as an OpaqueRef here but it becomes a Cell at invocation time */ } dec to {previous(state.value)} {/* transforms pure functions (like nth) into the `derive(c, nth)` equivalent */} Counter is the {nth(state.value)} number inc to {state.value + 1}
), value: state.value, }; }); export default pattern((state) => { const counter = Counter({ value: state.value }); return { [NAME]: computed(() => `Counters: ${state.value}`), // These three methods are all functionally equivalent [UI]: (
{counter}
{/* ct-render will NOT usually appear in a recipe, rather, it's used within other ct- component internals */}
), value: state.value, }; });