Shared helpers for MishkaGervaz.Form.Web.State.
Two reasons these live outside the __using__ macro:
- Reuse across the macro and user overrides. A user module that
overrides
init/3(viause MishkaGervaz.Form.Web.State) can call any helper here without redefining it. The macro itself imports them asStateHelpers. - Smaller compiled bytecode per consumer. Helpers compile once in this module rather than being re-emitted into every macro expansion.
Two functional groups:
- Config getters (
get_layout_mode/1,get_uploads/1,get_submit/1, …) — pull a typed value out of the runtimeInfo.config(resource)map with sensible defaults. - Step helpers (
groups_for_step/3) and access (mode_allowed?/3,resolve_access/1) — the bits of logic the macro and external callers (e.g.Form.Web.Live) both need.
mode_allowed?/3 — :restricted semantics
The :restricted field on a source map (or a per-mode entry in
:access_rules) accepts two shapes with deliberately different
contracts:
restricted: true— applies the master gate. Mode is allowed iffstate.master_user?. Use this for the standard "admin-only" pattern.restricted: fn state -> boolean end— function is the final word. The master gate is not layered on top. Returningtruemeans "this user is restricted"; the mode is denied. Returningfalseallows the mode unconditionally.
The asymmetry is intentional: the boolean form is the common case where you just want master-only; the function form is the escape hatch for callers that need the full state (role, dirty?, current step, etc.) to decide and don't want master-gate sugar layered on. Reach for the boolean unless you specifically need to bypass it.
See MishkaGervaz.Form.Web.State,
MishkaGervaz.Form.Web.State.Access.Default, and
MishkaGervaz.Form.Web.Live.