MishkaCmsCore.Builder.FormRole (Mishka CMS Core v0.0.1)

Copy Markdown View Source

What part of a form a component plays, declared by whoever wrote it rather than guessed here.

"extra": {"form": {"role": "field", "field": "bind", "name": "input_name", "label": "caption"}}

role is the only required key and is one of wrapper, field, error, fieldset, submit. Every other key NAMES ONE OF THIS COMPONENT'S OWN ATTRIBUTES, so a kit that calls its Phoenix.HTML.FormField attribute bind says so, and the editor writes bind={f[:email]} without ever knowing the word "field".

field, name and value are attributes the editor WRITES; label is one it reads the author's own word out of (MishkaCmsCore.Runtime.PageBuilder.Fields.field_label/2). Every one of the four is an attribute, which is why a slot is not a candidate — see below.

A wrong role is worse than no role

Same doctrine and same failure mode as MishkaCmsCore.Builder.Furnishing: this is a third party's JSON, so anything unreadable answers :none and MishkaCmsCore.Runtime.PageBuilder.Fields infers instead — which is what every kit shipped before this key existed gets, and is right most of the time. A malformed declaration never costs the component, and a malformed component never costs the kit (MishkaCmsCore.UiKit.Contract).

A key that points at nothing is dropped

build/2 keeps only the keys whose value names an ATTRIBUTE the component actually declares. Writing bind={f[:x]} onto a component with no bind attribute is the one failure this module exists to prevent: the attribute is dropped on the way to the renderer, the field is called with neither a binding nor a name, and KeyError :name lands inside LiveView's diff.

A slot is not a candidate, and validating against attrs AND slots reopened the same failure from the other side: "field": "inner_block" named something the component really does declare, so the key survived, and the editor then wrote inner_block={f[:email]} — which is not an attribute the component accepts either. Every key here names something the editor writes into or reads out of an attribute, so an attribute is the only thing it can be.

Summary

Functions

This component's declared role, or :none.

A sample %MishkaCmsCore.Builder.FormRole{} populated from defaults + type-based fallbacks.

Every role a kit may declare, so it can be read rather than guessed.

Types

t()

@type t() :: %MishkaCmsCore.Builder.FormRole{bindings: map() | nil, role: String.t()}

Functions

build(declared, entry)

@spec build(term(), map()) :: {:ok, t()} | :none

This component's declared role, or :none.

:none is not a failure — most components declare nothing, and inference is the answer for them. It is also what a malformed declaration gets, for the reason in the moduledoc.

builder(attrs_or_input, error \\ false)

enforce_keys()

enforce_keys(field)

example()

A sample %MishkaCmsCore.Builder.FormRole{} populated from defaults + type-based fallbacks.

keys()

keys(field)

roles()

@spec roles() :: [String.t()]

Every role a kit may declare, so it can be read rather than guessed.