One config field, dispatching on the closed field-type set (ADR-0005 decision 9, ADR-0002 decision 7).
The set is closed precisely so this renderer can be total, and the mapping is the record's, unchanged:
| Field type | Rendering |
|---|---|
:string | single-line text input |
:integer | number input, step 1 |
:boolean | checkbox |
{:select, choices} | select, choices in declared order |
:expression | single-line source input |
:duration | structured value/unit control emitting an ISO-8601 string |
{:list, t} | repeatable rows of t's renderer, with add and remove |
:duration emits a string rather than a number because ADR-0001
decision 6 forbids floats in config and "1.5 hours" has to be PT1H30M.
The control exists so the author does not have to know that. A stored
duration this module cannot parse is not discarded: it falls back to
a plain text input carrying the original string, on the same principle
as decision 12 - the editor never loses data it did not author.
:expression renders as a plain source input here. Predicator source is
statifier-ui's subject (sui-bob, sui-ADR-0006), and decision 9 records a
richer affordance as a deferral, so this component accepts an
expression_component override for exactly that seam.
This module is a renderer, not a gate. Nothing here decides whether a
value is acceptable: validate_config/1 does, through
StatifierBlocks.Edit.check_config/3, which is why an unparseable
integer reaches the draft config as the string the author typed rather
than being silently coerced or dropped.
Summary
Functions
Decodes one field's slice of a form's params back into a config value, dispatching on the same closed type set the renderer does.
One field: its label, its control, and its own findings (decision 11).
An ISO-8601 duration from a whole number of one unit. The inverse of
parse_duration/1 on everything parse_duration/1 accepts.
The DOM id for a field's control. Part of decision 7's DOM contract.
The form param name a field's control posts under.
An ISO-8601 duration as {count, unit} in the largest unit that divides
it evenly, or nil for anything this control cannot represent - a value
with a month or year component, a fractional one, or a string that is
not a duration at all. nil is what routes the value to the raw text
fallback rather than to the structured control, which is how a duration
the editor did not author survives being rendered.
The unit names the :duration control offers, largest last.
Functions
@spec decode(StatifierBlocks.BlockType.field_type(), term()) :: StatifierBlocks.Block.json()
Decodes one field's slice of a form's params back into a config value, dispatching on the same closed type set the renderer does.
Total, and deliberately non-coercing at the edges: an integer field
whose input does not parse yields the string the author typed, so
validate_config/1 reports it and decision 9's gate keeps it out of
the document. Coercing to zero here would silently discard the author's
intent and commit a value they never asked for.
One field: its label, its control, and its own findings (decision 11).
Attributes
field(StatifierBlocks.ViewModel.Field) (required)target(:any) (required)class(:string) - Defaults tonil.expression_component(:any) - Override for:expression, per ADR-0005 decision 9's seam. Receives the same assigns. Defaults tonil.
@spec format_duration(non_neg_integer(), String.t()) :: String.t()
An ISO-8601 duration from a whole number of one unit. The inverse of
parse_duration/1 on everything parse_duration/1 accepts.
@spec input_id(StatifierBlocks.ViewModel.Field.t()) :: String.t()
The DOM id for a field's control. Part of decision 7's DOM contract.
@spec input_name(StatifierBlocks.ViewModel.Field.t()) :: String.t()
The form param name a field's control posts under.
@spec parse_duration(term()) :: {non_neg_integer(), String.t()} | nil
An ISO-8601 duration as {count, unit} in the largest unit that divides
it evenly, or nil for anything this control cannot represent - a value
with a month or year component, a fractional one, or a string that is
not a duration at all. nil is what routes the value to the raw text
fallback rather than to the structured control, which is how a duration
the editor did not author survives being rendered.
@spec units() :: [String.t()]
The unit names the :duration control offers, largest last.