bcardiff/elm-rad/1.0.0

Rad.Form

Layer 5 — Forms. Designed for import Rad.Form as Form.

Types

type alias Form fields =
Form fields

Opaque transaction boundary over a cells record.

type alias Member =
Member

Opaque membership record. Constructed by field / validatedField.

type alias State =
State

The persisted state of a form: snapshot blob + submit-lifecycle counters.

stateCodec : Codec State

Codec for State, useful at persistence boundaries and in tests.

Builder

withState : String -> CellBuilder (Cell State -> rest) -> CellBuilder rest

Allocate a Form's persisted state cell. Initial value { snapshot = null, submitSeq = 0, lastResolvedSubmitSeq = 0 }.

init =
    build Model
        |> with "name" "" stringCodec
        |> Form.withState "profile-form"

Use-site construction

over : Cell State -> fields -> List Member -> Form fields

Construct a Form fields value bundling state cell, fields, and members. Pure — call per render.

field : Cell a -> Member

Mark a plain Cell as a form field.

validatedField : ValidatedCell err a -> Member

Mark a ValidatedCell as a form field. Captures input/validation/ activation-seq ids and the member's validation reaction.

Behaviors

dirty : Form fields -> Source Bool

True iff any member's current registry value differs from the form's pristine reference (snapshot when non-null, otherwise each member's initial).

submit : Form fields -> Action model

Bumps submitSeq and dispatches validate to each ValidatedMember.

reset : Form fields -> Action model

Restores all members to pristine value (snapshot or initial), zeros each ValidatedMember's activation seq, sets validation slot to Dormant. Does NOT modify submitSeq / lastResolvedSubmitSeq.

Reactions

reactions : Form fields -> List (Reaction model)

One reaction per ValidatedMember; PlainMembers contribute nothing. Concatenate with the user's other reactions in AppDef.reactions.

Submit gating

Form fields
-> ValidatedGroup fields clean
-> (clean -> Request err r)
-> Cell (Remote err r)
-> Reaction model

A reaction that fires a Request when the form is submitted and all validators in the group are Valid. On success, advances the form's snapshot and lastResolvedSubmitSeq. The target cell is Cell (Remote err r).

Form fields
-> ValidatedGroup fields clean
-> (clean -> Action model)
-> Reaction model

Like onSubmit, but runs an Action instead of dispatching a Request. On each fire (when the gate passes), bumps lastResolvedSubmitSeq to submitSeq and advances the snapshot.

Status

type Status
= Pristine
| Editable
| HasErrors
| Validating
| Submitting

Bundled snapshot of the form's UI state. Suitable for rendering a submit button. See status for precedence.

status : Form fields -> Source Status

Bundled Status. Precedence: invalid → HasErrors; submitPending+checking → Validating; submitPending → Submitting; dirty → Editable; else Pristine.

canSubmit : Form fields -> Source Bool

dirty AND not invalid AND not checking AND not submitPending.

submitPending : Form fields -> Source Bool

True iff submitSeq > lastResolvedSubmitSeq.

invalid : Form fields -> Source Bool

True iff any ValidatedMember's validation slot decodes to Invalid.

checking : Form fields -> Source Bool

True iff any ValidatedMember's validation slot decodes to Checking.

Inspection

memberCount : Form fields -> Int

Number of members in the form. For tests.

ValidatedGroup

type alias ValidatedGroup fields clean =
ValidatedGroup fields clean

Typed bundle of validators in a form, used to gate submission.

validators1 : (fields -> ValidatedCell err a) -> ValidatedGroup fields a

Group with a single validator. clean is the input type of the field.

(fields -> ValidatedCell err1 a)
-> (fields -> ValidatedCell err2 b)
-> ValidatedGroup fields ( a, b )

Group with two validators. clean = (a, b).

(fields -> ValidatedCell err1 a)
-> (fields -> ValidatedCell err2 b)
-> (fields -> ValidatedCell err3 c)
-> ValidatedGroup fields ( a, b, c )

Group with three validators.

(a -> b -> c -> d -> clean)
-> (fields -> ValidatedCell err1 a)
-> (fields -> ValidatedCell err2 b)
-> (fields -> ValidatedCell err3 c)
-> (fields -> ValidatedCell err4 d)
-> ValidatedGroup fields clean

Group with four validators. The packer function receives the four clean values in order and returns the typed clean type (typically a record).

validators4 (\name email age role -> { name = name, email = email, age = age, role = role })
    .name
    .email
    .age
    .role
(a -> b -> c -> d -> e -> clean)
-> (fields -> ValidatedCell err1 a)
-> (fields -> ValidatedCell err2 b)
-> (fields -> ValidatedCell err3 c)
-> (fields -> ValidatedCell err4 d)
-> (fields -> ValidatedCell err5 e)
-> ValidatedGroup fields clean

Group with five validators. The packer function receives the five clean values in order and returns the typed clean type (typically a record).

validators5 (\name email age role active -> { name = name, email = email, age = age, role = role, active = active })
    .name
    .email
    .age
    .role
    .active
(a -> b -> c -> d -> e -> f -> clean)
-> (fields -> ValidatedCell err1 a)
-> (fields -> ValidatedCell err2 b)
-> (fields -> ValidatedCell err3 c)
-> (fields -> ValidatedCell err4 d)
-> (fields -> ValidatedCell err5 e)
-> (fields -> ValidatedCell err6 f)
-> ValidatedGroup fields clean

Group with six validators. The packer function receives the six clean values in order and returns the typed clean type (typically a record).

validators6 (\a b c d e f -> { fieldA = a, fieldB = b, fieldC = c, fieldD = d, fieldE = e, fieldF = f })
    .fieldA
    .fieldB
    .fieldC
    .fieldD
    .fieldE
    .fieldF
(a -> b -> c -> d -> e -> f -> g -> clean)
-> (fields -> ValidatedCell err1 a)
-> (fields -> ValidatedCell err2 b)
-> (fields -> ValidatedCell err3 c)
-> (fields -> ValidatedCell err4 d)
-> (fields -> ValidatedCell err5 e)
-> (fields -> ValidatedCell err6 f)
-> (fields -> ValidatedCell err7 g)
-> ValidatedGroup fields clean

Group with seven validators. The packer function receives the seven clean values in order and returns the typed clean type (typically a record).

validators7 (\a b c d e f g -> { fieldA = a, fieldB = b, fieldC = c, fieldD = d, fieldE = e, fieldF = f, fieldG = g })
    .fieldA
    .fieldB
    .fieldC
    .fieldD
    .fieldE
    .fieldF
    .fieldG
(a -> b -> c -> d -> e -> f -> g -> h -> clean)
-> (fields -> ValidatedCell err1 a)
-> (fields -> ValidatedCell err2 b)
-> (fields -> ValidatedCell err3 c)
-> (fields -> ValidatedCell err4 d)
-> (fields -> ValidatedCell err5 e)
-> (fields -> ValidatedCell err6 f)
-> (fields -> ValidatedCell err7 g)
-> (fields -> ValidatedCell err8 h)
-> ValidatedGroup fields clean

Group with eight validators. The packer function receives the eight clean values in order and returns the typed clean type (typically a record).

validators8 (\a b c d e f g h -> { fieldA = a, fieldB = b, fieldC = c, fieldD = d, fieldE = e, fieldF = f, fieldG = g, fieldH = h })
    .fieldA
    .fieldB
    .fieldC
    .fieldD
    .fieldE
    .fieldF
    .fieldG
    .fieldH
mapValidated : (a -> b) -> ValidatedGroup fields a -> ValidatedGroup fields b

Transform a group's clean type. Useful for packing tuples into records.

readGroup : ValidatedGroup fields clean -> fields -> Registry -> Maybe clean

Read a group's clean values from registry. Returns Just clean iff every validator is Valid. Mostly for tests.