/// import { Cell, Default, handler, lift, recipe, str } from "commontools"; interface FormattingConfig { prefix?: string; suffix?: string; } interface SettingsConfig { label?: string; step?: number; formatting?: FormattingConfig; } interface HierarchicalDefaultsArgs { value: Default; settings: Default< SettingsConfig, { label: "Counter"; step: 1; formatting: { prefix: "Count"; suffix: "items" }; } >; } interface AdjustContext { value: Cell; step: Cell; } const adjustWithDefaults = handler( ( event: { amount?: number } | undefined, context: AdjustContext, ) => { const stepValue = context.step.get(); const base = typeof stepValue === "number" && Number.isFinite(stepValue) ? stepValue : 1; const amount = typeof event?.amount === "number" ? event.amount : base; const current = context.value.get() ?? 0; context.value.set(current + amount); }, ); const defaults = { label: "Counter", step: 1, formatting: { prefix: "Count", suffix: "items", }, }; const normalizeSettings = (input: SettingsConfig | undefined) => { if (!input) { return defaults; } const formatting = typeof input.formatting === "object" && input.formatting ? input.formatting : {}; return { label: typeof input.label === "string" && input.label.length > 0 ? input.label : defaults.label, step: typeof input.step === "number" && Number.isFinite(input.step) ? input.step : defaults.step, formatting: { prefix: typeof formatting.prefix === "string" && formatting.prefix.length > 0 ? formatting.prefix : defaults.formatting.prefix, suffix: typeof formatting.suffix === "string" && formatting.suffix.length > 0 ? formatting.suffix : defaults.formatting.suffix, }, }; }; export const counterWithHierarchicalDefaults = recipe( "Counter With Hierarchical Defaults", ({ value, settings }) => { const resolvedSettings = lift(normalizeSettings)(settings); const labelCell = resolvedSettings.key("label"); const stepCell = resolvedSettings.key("step"); const formattingCell = resolvedSettings.key("formatting"); const prefixCell = formattingCell.key("prefix"); const suffixCell = formattingCell.key("suffix"); const display = str`${prefixCell} ${value} ${suffixCell}`; const summary = str`${labelCell}: ${value}`; return { value, settings, resolvedSettings, effectiveStep: stepCell, label: labelCell, prefix: prefixCell, suffix: suffixCell, display, summary, controls: { adjust: adjustWithDefaults({ value, step: stepCell }), }, }; }, );