Skip to content

Interface: DomRenderContext

API / @xmachines/play-dom / DomRenderContext

Defined in: @xmachines/json-render-dom

Low-level render context passed to each DomComponentRenderer.

Properties

PropertyModifierTypeDescriptionDefined in
actionpublic(binding) => ActionHandleThe action handle of binding: the loading state of an action and a way to run it, as useAction(binding) of the framework renderers. execute() runs the binding as an on binding runs, with the repeat scope of the element, and its promise rejects to the caller when the binding fails. isLoading is true while a handler of the action runs in this tree, from any element. A dom component re-renders for no change of it: it calls subscribe and changes its own nodes. A subscription in the render belongs to the instance. Example const Save: ComponentFn<typeof catalog, "Save"> = ({ ctx }) => { const save = ctx.action({ action: "save" }); const button = document.createElement("button"); const show = () => { button.disabled = save.isLoading; button.textContent = save.isLoading ? "Saving…" : "Save"; }; show(); save.subscribe(show); button.addEventListener("click", () => void save.execute()); return button; };-
boundpublic<T>(prop) => BoundProp<T>The bound prop helper of prop, as useBoundProp(value, bindingPath) of the framework renderers. value is the resolved value of the prop in this render, path is the state path that $bindState or $bindItem binds to the prop, and set(value) writes to that path. set does nothing when the prop binds no path. The path is read at each access, so a handler writes to the item of now after a keyed move. Example const Input: ComponentFn<typeof catalog, "Input"> = ({ ctx }) => { const value = ctx.bound<string>("value"); const input = document.createElement("input"); input.value = value.value ?? ""; input.addEventListener("input", () => value.set(input.value)); return input; };-
confirmationreadonlyConfirmFlowThe confirm flow of the tree, as pendingConfirmation, confirm and cancel of useActions() of the framework renderers. Without an onConfirm hook, a binding with confirm waits as pending until a component calls confirm() or cancel(), or the user answers the default dialog. subscribe tells of each change. A subscription in the render belongs to the instance.-
directives?publicDirectiveRegistryCustom directive registry, converted from UIProviderOptions.directives (a DirectiveDefinition[]) once per render pass and forwarded to PropResolutionContext.directives. Components that resolve prop sub-values themselves (via resolvePropValue from @xmachines/json-render-core) should include this in their resolution context so custom $-prefixed dynamic values keep working inside those values. Mirrors the directives context from the framework renderers (useDirectives / DirectivesContextProvider / DIRECTIVES_KEY).-
effectpublic(run) => voidRun run as an effect of this render, after the commit point of the render. Call it in the render of the component. A dom component has no lifecycle, so an effect runs one time for each render that gives it, while that render is on the screen. An effect does not run when its instance went or failed, or when a later render of the instance replaced its render before the effects ran: for example a touch and then a store write of one handler, which show at one commit point. A component that must run an effect only for a change compares the values in the render with the values of the last effect that ran, gives the effect only for a change, and records the values in the effect. run can return a cleanup function. Any other value that run returns does nothing. The renderer runs the cleanups of a render before the first effect of a later render of the same instance. When the instance goes or fails, its cleanups run with the effects of the commit that took it out, and dispose runs every cleanup. So a timer or a listener that an effect starts lives as long as its instance. A cleanup that throws before an effect takes the element out, as an effect that throws does. A cleanup that throws when the instance goes reaches onUncaughtError. A renderSpec host gets the cleanups through onEffectCleanup, and it calls them when it discards the tree. The renderer runs the effects of a commit after the commit point of that commit, in the order of the tree: a child before its parent, and a sibling before the next one. They run before the checks of the watches of the commit. The end of a pass of the host (see ValidationRegistry.startPass) runs the effects of the incremental renderer that wait before it returns, also the effects of a render before the pass. A component of renderSpec runs its effects in a microtask, after the host placed the node. In the incremental renderer, an effect that throws takes its element out: the element shows nothing, its fields go, and onRenderError gets the error with the type of the element. No later effect of that element runs. In renderSpec, the host owns the node, so the renderer only gives the error to onRenderError. A chain of 52 nested effects, such as an effect that writes the store at each render of its component, stops in the same way, so a loop does not hang the page. A microtask or a promise that a component queues itself is no effect of the renderer: it runs in its own time, also after the end of a pass of the host.-
elementBindings?publicRecord<string, string>Pre-computed two-way binding paths for this element’s props.-
fieldpublic(path, config?) => FieldHandleThe field helper of path, as useFieldValidation(path, config) of the framework renderers: state, errors, isValid, validate, touch and clear. With a config, the element holds the field: the call registers it through DomRenderContext.validation. A read of state, errors or isValid in the render makes the element a reader of the field, so it renders again when the state changes. Example const Email: ComponentFn<typeof catalog, "Email"> = ({ bindings, ctx }) => { const field = ctx.field(bindings?.value ?? "", { checks: [{ type: "email", message: "Enter an email" }], }); const input = document.createElement("input"); input.setAttribute("aria-invalid", String(!field.isValid)); input.title = field.errors.join(", "); input.addEventListener("blur", () => void field.validate()); return input; };-
functions?publicRecord<string, ComputedFunction>Optional map of named compute functions, forwarded to PropResolutionContext. Enables { $computed: “funcName”, args: {…} } prop expressions to resolve. Mirrors the functions prop from framework renderer providers.-
handlerspublicRecord<string, ActionHandler>Map of json-render catalog action names → async ActionHandler functions.-
isVisiblepublic(condition) => booleanEvaluate a visibility condition, as useIsVisible(condition) of the framework renderers. undefined is visible. A call in the render makes the element a reader of each state path that the condition reads, so the element renders again when one of them changes. Inside a repeat, $item and $index read the repeat scope of the element. A call from a handler reads the state of now and makes the element a reader of nothing. Example const Hint: ComponentFn<typeof catalog, "Hint"> = ({ props, ctx }) => { const node = document.createElement("p"); node.hidden = !ctx.isVisible({ $state: "/showHints" }); node.textContent = props.text; return node; };-
loading?publicbooleanWhen true, indicates the spec is still streaming (e.g. from an AI provider). Component implementations can use this to show skeleton/loading states. When loading=true, missing-child warnings are suppressed. Mirrors the loading prop from framework renderer providers.-
navigate?public(path) => voidNavigation function forwarded from UIProviderOptions. Called when an action binding has onSuccess: { navigate: "/path" }. Mirrors the navigate prop in ActionProvider from framework renderers.-
onConfirm?publicConfirmHandlerConfirmation hook forwarded from UIProviderOptions.onConfirm. Consulted by emit() before executing an action binding that declares confirm. When absent, the binding waits as the pending confirmation of the tree (see DomRenderContext.confirmation).-
onRenderError?publicOnRenderErrorError handler forwarded from UIProviderOptions.onRenderError, or the handler of the registry: (error, name, info). Called by emit() when an action chain fails, with (error, actionName, { kind: "action", ... }), and by the renderer for each other failure that it catches (see UIProviderOptions.onRenderError). When absent, each failure gives one console.error line. Component implementations may call this directly via ctx.ctx.onRenderError to surface errors through the application’s central error channel. Give it an info, for example { kind: "element", type: element.type }, or call reportRenderError of core, which writes the console line when no handler is set.-
renderChildrenpublic(keys) => Node[]Render a list of child element keys into DOM nodes. In the incremental renderer, a node can be the node of an earlier render: a child whose subtree did not change keeps it. This occurs in a setSpec pass, and when the array of a repeat grows or shrinks. Do not add a listener or a child node to a returned node, because a kept node then receives it again. Put such decoration on a wrapper node.-
renderSlotpublic(slotName) => Node[]Render the children the element placed in a named slot (element.slots). Returns [] for a slot the element does not fill. Slot children render with the enclosing repeat scope, not once per item of this element’s own repeat. As for DomRenderContext.renderChildren, a returned node can be the node of an earlier render.-
repeatBasePath?publicstringAbsolute JSON Pointer path to the current repeat item (e.g. “/todos/0”). Mirrors repeatBasePath in PropResolutionContext.-
repeatIndex?publicnumberCurrent repeat array index when inside a repeat scope. Mirrors repeatIndex in PropResolutionContext.-
repeatItem?publicunknownCurrent repeat item when inside a repeat scope. Mirrors repeatItem in @xmachines/json-render-core’s PropResolutionContext.-
sendpublic(event) => voidDispatch an event (e.g. to an XState actor).-
specreadonlySpecThe full spec tree of now. In the pass it is the spec of the pass; a component that reads it later, when it reads its children late, gets the spec that those children render from.-
storepublicStateStoreLive state store bound to spec.state. renderSpec gives the store of the host. The incremental renderer gives a view of that store, and not the store object: a Proxy that gives each member of the store, runs a function member with the store as this, and tells the renderer the path of each read while the component renders. So ctx.store is not the store object of the host, and a compare with that object, or a key of a WeakMap on it, finds no match. The context gives no way to reach the store object itself. A component that needs it gets it from the host, for example from the scope in which the host defines the registry. A path that the component reads through the view while it renders is a dependency: a change of the value at that path renders the component again. A subscription through the view while the component renders belongs to the instance, and the renderer stops it when the instance renders again or goes. A subscription in an effect lives until the cleanup of the effect stops it.-
validationpublicValidationRegistryField-validation registry for this tree. Components register their field’s ValidationConfig here during render (registerField) and validate on change/blur (validate); the validateForm built-in validates every registered field. It does the job of the ValidationProvider of the framework renderers. The config is a part of the render: a holder renders one time at its mount, and a new config of its own field renders nothing again. When two holders give one path a config in one commit, the call that registered last holds. The state of a field belongs to the element that registers it: another element that takes over the path, or a new config from the only holder, starts the field fresh. A holder, and a component that read fieldStates, render again when the state that they read changes.-
validationFunctions?publicRecord<string, (value, args?) => boolean>Custom validation functions available to runValidation / runValidationCheck. Each function receives (value, args?) and returns a boolean. Mirrors customFunctions in ValidationProvider from framework renderers. Components that perform inline validation (e.g. form fields) should read this from ctx.ctx.validationFunctions and pass it as customFunctions to runValidationCheck / runValidation from @xmachines/json-render-core.-