Specification and validation of a single node or mark attribute.
An attribute spec declares a default value, whether the attribute is required, and an optional validator. Validators are declarative terms rather than closures so that a schema stays inspectable and comparable.
Supported validators:
:string,:integer,:boolean— type checks{:one_of, list}— value must be a member oflist:safe_url— relative URL, or absolute URL with an allowed scheme{:nullable, validator}— acceptsnil, otherwise delegates- a
fun/1returning:okor{:error, message}— escape hatch
Turning a value into markup
:render_as says how the value reaches the DOM, and — being data rather
than a render function — it is applied by the server renderer and
exported to the browser, so the editor shows what the page will carry
without an application writing a hook.
{:style, property}—style="property:value"{:class, %{value => class}}— the class the value maps to
Alignment is the shipped example:
align: [
default: nil,
validate: {:nullable, {:one_of, ~w(left center right justify)}},
render_as: {:style, "text-align"}
]Swap that last line for a class map and the same attribute renders as a class an application's stylesheet can own — an inline style cannot be overridden by a rule:
render_as: {:class, %{"center" => "text-center", "right" => "text-right"}}Both forms are closed over the values they name, which is the point.
Coelho.Ecto.Type does not re-validate a stored document, so every
renderer is a security boundary: a row written under a looser schema is
rendered by today's renderer. A class map is its own allow list — a value
that is not a key contributes nothing. {:style, property} has no such
list of its own, so it is accepted only on an attribute whose validator is
a {:one_of, list} (nullable or not), and the value is checked against
that list again at render time.
An attribute with no :render_as is not rendered by itself; a node's
:render decides what to do with it, as before. A :render that is a
function builds the whole element, so it is the one form :render_as
cannot reach — the same rule a spec's :class follows.
Summary
Functions
The key a {:class, map} lookup uses for a value, as the browser sees it.
Builds an attribute spec from a keyword list.
The values a {:style, property} attribute may render, or nil.
Runs a validator against a value.
Types
Functions
The key a {:class, map} lookup uses for a value, as the browser sees it.
Exported alongside the classes so both halves agree on what a value is
called: JavaScript indexes an object by the string form of the key, and
null reaches it as "null".
Builds an attribute spec from a keyword list.
The values a {:style, property} attribute may render, or nil.
Read off the validator, which such an attribute is required to have, so the list exists in one place and the browser can be handed the same one.
Runs a validator against a value.