Composition / foldkit-builder

The inspector is a form

Each Block's props are edited through a foldkit-form form made from its props Schema, once per Block, at the first use, and the input of the action each of its events runs through one more, once per Block, event and action. A form edits a value as the Document stores it, so a prop drawn as an Option is chosen as an id or nothing, and checks each value against its whole Schema. The node owns its values; a form only holds what its fields show:

node props ─► fill ─► field drafts ─► Inspected(Changed) ─► the form decodes each key
   a key the Message changed that decodes, and the node lacks ─► setProp,
                                              or setAction with the input's other keys
   an optional key emptied ─► unsetProp, or setAction without it
   a key that does not decode ─► its error, no edit
  • A change that decodes is an edit, one setProp per key the Message changed, grouped in history like any other, so typing a word undoes as one. A field left alone is never written back, and typing back the value the node holds adds no undo step.
  • Text that does not decode ("abc" for a number) stays in its field with the form's error, and changes nothing. A required field emptied is such text; an optional one emptied takes the value away.
  • A value the node refuses, one that fits its field but not the Block (a check across props), is said in refused, and the form shows what the node holds again.
  • An action's input is written whole, with only the keys its Schema names, so one a stored input kept from an older Schema is dropped, not refused.
  • A node changed another way (an undo, the canvas, an agent) refills every field but one holding text that does not decode. Moving the selection drops what was held; the next node's fields fill from its props.
  • PageBuilder.inspecting(model) is the selected node's forms and their Models, for a view to draw: props, and on by event. A view sends Inspected({ id, form: form.key, message: form.settings.encodeMessage(message) }); one for a node no longer selected, or a form it no longer draws, is ignored. Each form's Model is held as JSON, so a saved Builder still is.
  • A prop is labelled with its Schema's title, else its key spaced (maxItems is "Max items"). A Block asks for a control where the Schema does not say, with Block.annotate(Builder.controls({ body: Input.multiline() })); Input.hidden() leaves a prop out.
  • A control of the application's own, backed by a Bundle (Input.bundle, a color picker), works as it does in any form, with no Builder code; send its Messages with settings.control(key, message). The Builder runs its forms as functions and starts nothing, so one with Subscriptions or Resources is refused where the Builder is made: every Block's form is made there.