React / foldkit-react-codegen
What compiles
| Foldkit | React |
|---|---|
h.div(attributes, children), any HTML/SVG/MathML tag | <div …>…</div> |
h.keyed('li')(key, attributes, children) | <li key={key} …> |
h.empty | null |
h.submodel({ model, view, toParentMessage, viewInputs? }) | view(model, viewInputs?, m => dispatch(toParentMessage(m))) |
Submodel.defineView<Model, Message>((model, h) => …) | the compiled function, with Model on its parameter |
const slot = createLazy(), slot(view, [a, h]) | view(a, dispatch); the slot is removed |
createKeyedLazy() slots, slot(key, view, args) | view(...args) |
const el = spec.withMessage(h), el([el.Color(c), el.OnColorChanged(f)], []) | <color-picker color={c} oncolor-changed={(event: CustomEvent) => dispatch(f(event.detail))} /> |
Class, Id, Key, For, Tabindex, Readonly, … | className, id, key, htmlFor, tabIndex, readOnly, … |
AriaLabelledBy(x) and every Aria* | aria-labelledby={x} |
Attribute('k', v), DataAttribute('k', v) | k={v}, data-k={v} |
Style({ 'background-color': c }) | style={{ backgroundColor: c }} |
OnClick(message), OnFocus, OnBlur, mouse enter/leave/over/out/down/up/move, OnDoubleClick | onClick={() => dispatch(message)} |
OnInput(f) | onChange={event => dispatch(f(event.currentTarget.value))} |
OnKeyDown(f), OnKeyUp(f) | onKeyDown={event => dispatch(f(event.key, { shiftKey, ctrlKey, altKey, metaKey }))} |
OnKeyDownSelf(f) | the same, guarded by event.target === event.currentTarget |
OnSubmit(message) | onSubmit={event => { event.preventDefault(); dispatch(message) }} |
Custom elements work because React 19 writes a prop as a DOM property when the
element has that property, and listens for exactly the event name after on.
Define the element before React renders it, as Foldkit also needs; otherwise
React falls back to an attribute. A spec used only in compiled views is
removed; an exported one is kept for other modules. For the output to
type-check, the compiler appends a declare module 'react' entry typing each
tag's props as Record<string, unknown>; a hand-written declaration for the
same tag must use that type.
OnInput becomes React's onChange on purpose. On a text control, React's
onChange fires on every native input event, and pairing it with value
keeps the input controlled without a warning.