[{"name":"JsonRender","comment":" A native, fail-closed Elm renderer for [json-render](https://github.com/vercel-labs/json-render)\nmanifests, pinned to `@json-render/core` v0.19.0.\n\nThis top module is the convenience entry point: validate a manifest fail-closed, and get\nan error stub for the failure path. The renderer itself (a small TEA component:\n`Model` / `Msg` / `Effect` / `update` / `view`) lives in\n[`JsonRender.Render`](JsonRender-Render); the typed spec model in\n[`JsonRender.Spec`](JsonRender-Spec); the expression dialect in\n[`JsonRender.Expr`](JsonRender-Expr).\n\nTypical host wiring:\n\n    case JsonRender.decodeValue manifestJson of\n        Ok spec ->\n            -- mount the renderer, feeding host-owned state\n            Html.map RendererMsg (JsonRender.Render.view spec hostState rendererModel)\n\n        Err message ->\n            JsonRender.errorStub message\n\nDecoding is the security gate: an off-catalog component type, a malformed prop, a\ndangling child key, or a missing root all produce `Err`, never a partial tree.\n\n\n# Validate a manifest\n\n@docs decodeValue, decodeString\n\n\n# Failure path\n\n@docs errorStub\n\n","unions":[],"aliases":[],"values":[{"name":"decodeString","comment":" Validate a raw JSON string into a [`Spec`](JsonRender-Spec#Spec), fail-closed.\n","type":"String.String -> Result.Result String.String JsonRender.Spec.Spec"},{"name":"decodeValue","comment":" Validate an already-parsed JSON `Value` into a [`Spec`](JsonRender-Spec#Spec),\nfail-closed. `Err` carries a human-readable diagnostic.\n","type":"Json.Decode.Value -> Result.Result String.String JsonRender.Spec.Spec"},{"name":"errorStub","comment":" The fail-closed failure view: a self-contained error stub the host renders instead of\na manifest that did not validate. Never a partial tree.\n","type":"String.String -> Html.Html msg"}],"binops":[]},{"name":"JsonRender.Expr","comment":" The json-render expression / binding dialect, scoped to this package's\nsupported set and pinned to `@json-render/core` v0.19.0 (see [`SUPPORT.md`](https://github.com/Juli4nG/elm-json-render/blob/main/SUPPORT.md)).\n\nEvery dynamic value in a manifest is a plain JSON object carrying a single\n`$`-prefixed discriminant key. This module decodes the supported forms into a typed\n[`Expr`](#Expr) and resolves them against a host-owned state `Value` plus an optional\n`repeat` scope, using RFC 6901 JSON Pointers throughout.\n\n**Fail-closed:** an object carrying an unsupported `$`-directive (e.g. `$cond`,\n`$computed`) **fails the decode**. json-render's own runtime is fail-open here; we are\nnot. The supported set is exactly the v1 subset.\n\n\n# Expressions\n\n@docs Expr\n@docs decoder\n\n\n# Resolution scope\n\n@docs Context\n@docs rootContext\n@docs childContext\n\n\n# JSON Pointers\n\n@docs getByPath\n\n\n# Resolving\n\n@docs resolve\n@docs resolveDisplay\n@docs resolveBool\n@docs writeBackPath\n@docs resolveParams\n@docs validatedParams\n\n","unions":[{"name":"Expr","comment":" A decoded json-render expression. The discriminant maps 1:1 to the pinned\n`$`-forms:\n\n  - `ELiteral v`: any value with no `$`-directive (scalar, array, or plain object).\n  - `EState ptr`: `{ \"$state\": \"/ptr\" }`, read global state.\n  - `EItem field`: `{ \"$item\": \"field\" }`, read the current repeat item (field `\"\"` = whole item).\n  - `EIndex`: `{ \"$index\": true }`, the current repeat index.\n  - `EBindState ptr`: `{ \"$bindState\": \"/ptr\" }`, two-way bind to global state.\n  - `EBindItem field`: `{ \"$bindItem\": \"field\" }`, two-way bind to a repeat-item field.\n  - `ETemplate tmpl`: `{ \"$template\": \"…${/ptr}…${bare}…\" }`, string interpolation.\n\n","args":[],"cases":[["ELiteral",["Json.Decode.Value"]],["EState",["String.String"]],["EItem",["String.String"]],["EIndex",[]],["EBindState",["String.String"]],["EBindItem",["String.String"]],["ETemplate",["String.String"]]]}],"aliases":[{"name":"Context","comment":" The resolution scope handed to every expression.\n\n  - `state`: the host-owned global state `Value` (the single source of truth).\n  - `item`: the current `repeat` item, if inside a repeat scope.\n  - `index`: the current `repeat` index, if inside a repeat scope.\n  - `basePath`: the repeat item's absolute JSON Pointer (`statePath ++ \"/\" ++ index`),\n    used to compute `$bindItem` / top-level `$item` write-back paths.\n\n","args":[],"type":"{ state : Json.Decode.Value, item : Maybe.Maybe Json.Decode.Value, index : Maybe.Maybe Basics.Int, basePath : Maybe.Maybe String.String }"}],"values":[{"name":"childContext","comment":" Derive a per-item scope for a `repeat` element. `statePath` is the pointer to the\nstate array; `index` and `item` identify the current row. `basePath` becomes\n`statePath ++ \"/\" ++ index` per the pinned reference.\n","type":"String.String -> Basics.Int -> Json.Decode.Value -> JsonRender.Expr.Context -> JsonRender.Expr.Context"},{"name":"decoder","comment":" Decode a prop value into an [`Expr`](#Expr).\n\nA non-object (string / number / bool / array / null) decodes to `ELiteral`. An object\nwith no `$`-prefixed key decodes to `ELiteral`. An object with exactly one supported\n`$`-directive decodes to that form. An object with an **unsupported** `$`-directive, or\nmore than one `$`-directive, **fails**. This is the fail-closed boundary.\n\n","type":"Json.Decode.Decoder JsonRender.Expr.Expr"},{"name":"getByPath","comment":" Resolve an RFC 6901 JSON Pointer against a `Value`. Returns `Nothing` if any token\nis missing. The empty pointer `\"\"` returns the whole value. Tokens are unescaped\n(`~1` → `/`, `~0` → `~`). A leading `/` is honored; a bare token (no leading `/`, as\nproduced by `$item` field lookups) is tolerated as a single step.\n","type":"String.String -> Json.Decode.Value -> Maybe.Maybe Json.Decode.Value"},{"name":"resolve","comment":" Resolve an expression to a JSON `Value`. A missing pointer / item field yields\n`null`. Two-way `$bindState` / `$bindItem` read exactly like their read-only siblings;\ntheir write-back path is exposed separately via [`writeBackPath`](#writeBackPath).\n","type":"JsonRender.Expr.Context -> JsonRender.Expr.Expr -> Json.Decode.Value"},{"name":"resolveBool","comment":" Resolve an expression to a boolean (for `Checkbox` `checked`). Only a JSON `true`\nis `True`; everything else (including missing) is `False`.\n","type":"JsonRender.Expr.Context -> JsonRender.Expr.Expr -> Basics.Bool"},{"name":"resolveDisplay","comment":" Resolve an expression to its display string (for `Text` / `Badge`). Scalars render\nas themselves; `null` / missing renders as `\"\"`; objects / arrays render as `\"\"`.\n","type":"JsonRender.Expr.Context -> JsonRender.Expr.Expr -> String.String"},{"name":"resolveParams","comment":" Resolve an action's `params` object per the pinned `resolveActionParam` semantics:\n\n  - A **top-level** `{ \"$item\": \"field\" }` resolves to the absolute state **path**\n    (`basePath ++ \"/\" ++ field`) so the host can target the row.\n  - A **top-level** `{ \"$index\": true }` resolves to the index **number**.\n  - Everything else (including `$item` **nested in an array**) resolves to the **value**\n    by deep recursion.\n\nSo `{ \"ids\": [ { \"$item\": \"id\" } ] }` yields `{ \"ids\": [\"<id>\"] }`: the literal id, never\na path.\n\n","type":"JsonRender.Expr.Context -> Json.Decode.Value -> Json.Decode.Value"},{"name":"rootContext","comment":" The top-level scope: global state only, no repeat item.\n","type":"Json.Decode.Value -> JsonRender.Expr.Context"},{"name":"validatedParams","comment":" A `Decoder` for an action's `params` that **validates fail-closed at decode time**:\nit returns the params `Value` unchanged, but fails if any nested object carrying a\n`$`-directive is not a supported, well-formed [`Expr`](#Expr) (e.g. an unsupported\n`$cond`, or a malformed `{ \"$item\": 123 }`). This closes the gap where params are stored\nraw and only resolved at dispatch: a bad directive is rejected with the rest of the\nmanifest, never emitted to the host.\n","type":"Json.Decode.Decoder Json.Decode.Value"},{"name":"writeBackPath","comment":" The absolute JSON Pointer a two-way binding writes back to, or `Nothing` for\nread-only expressions. `$bindState` writes its own pointer; `$bindItem` writes\n`basePath ++ \"/\" ++ field`.\n","type":"JsonRender.Expr.Context -> JsonRender.Expr.Expr -> Maybe.Maybe String.String"}],"binops":[]},{"name":"JsonRender.Render","comment":" Render a validated [`Spec`](JsonRender-Spec#Spec) to `Html`, driven by host-owned\nstate, with actions flowing back out as [`Effect`](#Effect) values.\n\nThis is a small TEA component. The host owns the json-render `state` and passes it to\n[`view`](#view) on every frame; the renderer reads it but never mutates it behind the\nhost's back. The only local state the renderer owns is the pending confirm dialog. User\nactions (button presses, checkbox toggles) surface to the host as `Effect`s the host\napplies, so the host stays the single source of truth.\n\nBecause the output is Elm `Html` (no `innerHTML`, no script escape hatch), the rendered\ntree is **XSS-safe by construction**.\n\n\n# State\n\n@docs Model, init\n\n\n# Messages\n\n@docs Msg, update\n\n\n# Effects (out to the host)\n\n@docs Effect\n\n\n# View\n\n@docs view\n\n","unions":[{"name":"Effect","comment":" What the renderer asks the host to do. The renderer never performs the side effect\nitself.\n\n  - `EmitAction { verb, params }`: a wired `on:press` fired (and any `confirm` was\n    accepted). `params` are already expression-resolved. The host re-checks the verb\n    against its allowlist and performs the side effect.\n  - `EmitStateChange { path, value }`: a two-way input (`$bindState` / `$bindItem`\n    checkbox) was toggled. The host treats this as the source of truth, writes it at the\n    given absolute JSON Pointer, and re-projects state.\n\n","args":[],"cases":[["EmitAction",["{ verb : String.String, params : Json.Decode.Value }"]],["EmitStateChange",["{ path : String.String, value : Json.Decode.Value }"]]]},{"name":"Model","comment":" Renderer-local UI state. Holds only the pending confirm dialog (if any); the\nhost owns everything else.\n","args":[],"cases":[]},{"name":"Msg","comment":" Renderer messages. Opaque to the host: the host maps `Html Msg` into its own message\ntype and feeds `Msg`s back through [`update`](#update), acting on the returned\n[`Effect`](#Effect).\n","args":[],"cases":[]}],"aliases":[],"values":[{"name":"init","comment":" The initial (empty) renderer state: no dialog open.\n","type":"JsonRender.Render.Model"},{"name":"update","comment":" Advance renderer-local state in response to a `Msg`, optionally yielding an `Effect`\nfor the host to apply.\n\n`confirm` is honored here: a press carrying a confirm opens the dialog and emits nothing;\nthe `EmitAction` only fires once the user accepts.\n\n","type":"JsonRender.Render.Msg -> JsonRender.Render.Model -> ( JsonRender.Render.Model, Maybe.Maybe JsonRender.Render.Effect )"},{"name":"view","comment":" Render the spec against the current host-owned `state`. The returned `Html Msg`\nincludes the confirm dialog overlay when one is pending.\n","type":"JsonRender.Spec.Spec -> Json.Decode.Value -> JsonRender.Render.Model -> Html.Html JsonRender.Render.Msg"}],"binops":[]},{"name":"JsonRender.Spec","comment":" The json-render flat `Spec` model and its fail-closed decoder, scoped to this\npackage's component set and pinned to `@json-render/core` v0.19.0.\n\nA `Spec` is the canonical flat form: `{ root, elements, state }` where `elements` is a\nmap keyed by id and children are referenced by string key (never nested inline).\n\n**Fail-closed.** The decoder rejects, rather than silently dropping:\n\n  - an **unknown / off-catalog** component `type` (json-render's renderer is fail-open\n    here; we are not);\n  - props that don't match the strict per-component shape;\n  - a **dangling** child key, a **missing** root, or a `repeat` element with no children\n    (the structural floor `validateSpec` enforces).\n\nA rejected manifest never produces a partial tree: the host shows an error stub.\n\n\n# Spec\n\n@docs Spec\n@docs decoder\n\n\n# Elements\n\n@docs UIElement\n@docs ComponentType\n@docs componentName\n\n\n# Props\n\n@docs Props\n@docs Direction\n@docs CardProps\n@docs StackProps\n@docs TextProps\n@docs BadgeProps\n@docs ButtonProps\n@docs CheckboxProps\n@docs GroupedTableProps\n\n\n# Actions & iteration\n\n@docs ActionBinding\n@docs Confirm\n@docs Repeat\n\n","unions":[{"name":"ComponentType","comment":" The allowlisted component types. Anything else fails the decode.\n","args":[],"cases":[["Card",[]],["Stack",[]],["Text",[]],["Badge",[]],["Button",[]],["Checkbox",[]],["GroupedTable",[]]]},{"name":"Direction","comment":" `Stack` layout direction.\n","args":[],"cases":[["Row",[]],["Col",[]]]},{"name":"Props","comment":" Strictly-decoded props, one variant per component type. The variant always agrees\nwith the element's [`ComponentType`](#ComponentType) (both come from a single read of\nthe `type` field).\n","args":[],"cases":[["CardP",["JsonRender.Spec.CardProps"]],["StackP",["JsonRender.Spec.StackProps"]],["TextP",["JsonRender.Spec.TextProps"]],["BadgeP",["JsonRender.Spec.BadgeProps"]],["ButtonP",["JsonRender.Spec.ButtonProps"]],["CheckboxP",["JsonRender.Spec.CheckboxProps"]],["GroupedTableP",["JsonRender.Spec.GroupedTableProps"]]]}],"aliases":[{"name":"ActionBinding","comment":" An event binding: a named verb, its (unresolved) params, and an optional confirm\ndialog. The key is `action`/`params` per the pinned format, never a URL.\n","args":[],"type":"{ action : String.String, params : Json.Decode.Value, confirm : Maybe.Maybe JsonRender.Spec.Confirm }"},{"name":"BadgeProps","comment":" `Badge` props: the `value` expression (e.g. a status string mapped to a tone).\n","args":[],"type":"{ value : JsonRender.Expr.Expr }"},{"name":"ButtonProps","comment":" `Button` props: the `label` expression.\n","args":[],"type":"{ label : JsonRender.Expr.Expr }"},{"name":"CardProps","comment":" `Card` props. `title` is optional and may be any expression.\n","args":[],"type":"{ title : Maybe.Maybe JsonRender.Expr.Expr }"},{"name":"CheckboxProps","comment":" `Checkbox` props: an optional `label` and an optional `checked` binding (typically a\ntwo-way `$bindState` / `$bindItem`).\n","args":[],"type":"{ label : Maybe.Maybe JsonRender.Expr.Expr, checked : Maybe.Maybe JsonRender.Expr.Expr }"},{"name":"Confirm","comment":" A confirm dialog shown by the renderer before an action emits. `title` and `message`\nmay be expressions (e.g. a `$template` interpolating a row field).\n","args":[],"type":"{ title : JsonRender.Expr.Expr, message : JsonRender.Expr.Expr, confirmLabel : Maybe.Maybe String.String, cancelLabel : Maybe.Maybe String.String, variant : String.String }"},{"name":"GroupedTableProps","comment":" `GroupedTable` props: the `bind` expression pointing at the array of rows to group\nand a `groupBy` field name. The table groups the array of records by that field and shows\ncounts.\n","args":[],"type":"{ bind : JsonRender.Expr.Expr, groupBy : String.String }"},{"name":"Repeat","comment":" Element-level iteration: `statePath` points at a state array, `key` is the optional\nstable-list item field.\n","args":[],"type":"{ statePath : String.String, key : Maybe.Maybe String.String }"},{"name":"Spec","comment":" A flat json-render spec: a root element key, a keyed map of elements, and the\nhost-owned initial state.\n","args":[],"type":"{ root : String.String, elements : Dict.Dict String.String JsonRender.Spec.UIElement, state : Json.Decode.Value }"},{"name":"StackProps","comment":" `Stack` props: a layout `direction` and a numeric `gap`.\n","args":[],"type":"{ direction : JsonRender.Spec.Direction, gap : Basics.Int }"},{"name":"TextProps","comment":" `Text` props: the displayed `value` expression.\n","args":[],"type":"{ value : JsonRender.Expr.Expr }"},{"name":"UIElement","comment":" One element: its (validated) component type, its strictly-decoded props, its child\nkeys, its event bindings, and an optional `repeat`. Mirrors json-render's `UIElement`\nshape (`type/props/children/on/repeat`), minus the `visible`/`watch` siblings this\nrenderer does not support.\n","args":[],"type":"{ componentType : JsonRender.Spec.ComponentType, props : JsonRender.Spec.Props, children : List.List String.String, on : Dict.Dict String.String (List.List JsonRender.Spec.ActionBinding), repeat : Maybe.Maybe JsonRender.Spec.Repeat }"}],"values":[{"name":"componentName","comment":" The component type's wire name, for diagnostics.\n","type":"JsonRender.Spec.ComponentType -> String.String"},{"name":"decoder","comment":" Decode a flat json-render `Spec`, fail-closed. See the module doc for what is\nrejected. On any structural or off-catalog error the decoder fails with a diagnostic\nmessage; the host renders an error stub rather than a partial tree.\n","type":"Json.Decode.Decoder JsonRender.Spec.Spec"}],"binops":[]}]