# `StatifierBlocks.Editor.Declarations`
[🔗](https://github.com/riddler/statifier_blocks/blob/v0.44.1/lib/statifier_blocks/editor/declarations.ex#L2)

The declarations panel: the document's own `datamodel` roots, added,
edited and reordered in the drawer (ADR-0005's 2026-09-01 amendment,
clauses 2i-2m; the key itself is ADR-0001 decision 11).

ADR-0001's 11i named this surface and declined to design it - "A host
may now carry roots in the tree the author edits rather than in the
publish call, which is what makes an editor able to show and edit them
one day. **No editor surface is proposed here**; that is ADR-0005's,
when taken." This is that surface.

## Why it is a drawer tab

1A's admission test is two words, tabular and document-level, and a
declaration list passes both without an argument: it is a grid of rows -
a name, an initial value, a description - and it is about the envelope,
which is the whole document rather than any block in it. 3A keeps it out
of the inspector for the same reason it kept Datamodel and Fixtures out:
those tabs were never about the selected block.

It fills **no** reserved place. 1A reserved two - "fixture runs and the
datamodel view" (ADR-0005's Note of 2026-09-02, "the last reserved
place, filled") - and this tab is neither: it arrives through 11i's own
door, admitted on 1A's two-word test like any tab that came after the
reservations were spent.

It is easy to mistake for the reserved one, and the mistake is worth
naming. The reserved sentence described a read-only report over every
declared path, which under the 11k union would mean three sources at
once - the host's datamodel, the compile call's `:declare` roots and
this key. What ships here is the one source an author can actually
change. That report shipped separately, as the drawer's read-only
Datamodel tab, and it is the view that took the last reserved place -
which `StatifierBlocks.Editor.Drawer`'s moduledoc records in those
words. This section reserves nothing behind it.

## What a row is, and what it is not

Three fields, because ADR-0001 11b gives an entry three: a required `id`,
an optional `expr` the root starts with, and an optional `description`
that is prose for a reader and never reaches the chart. No `type`, no
`label`, no `one_of`, no `sensitive?` - 11b refuses all four in the
model, and offering a box for one here would grow the second, thinner
datamodel vocabulary beside ADR-0006's that both records exist to
prevent.

## Reorder is buttons

Decision 7 ships exactly one JavaScript hook, on the canvas's cards, and
a second drag surface would be a second hook or a widening of the first.
Neither is bought by a list of three rows. Up and down are native
buttons, and decision 8's rule that every drop target is reachable
without dragging is met here by construction rather than by a parallel
path: there is no gap, no slot and no geometry, so the button is not the
fallback - it is the gesture.

Order is load-bearing all the same. It is the emission order of the
document's `<data>` elements (ADR-0001 11a), which is why moving a row is
a document edit on the undo stack and not a display preference.

## Every field is a form, and a refusal is shown here

Editing sends `phx-change`, which is `ConfigForm`'s shape and for
`ConfigForm`'s reason. A refused change is held as a draft and the
sentence saying why is rendered in this panel: decision 11's anchors name
a block, a slot or a config key, and none of them can name a declaration
entry, so a refusal here is not a finding and never enters the findings
pipeline. `StatifierBlocks.Declarations.refusal/1` is the one place a
refusal becomes a sentence.

## The accepted events

Below the roots sits a second row: the document's `accepts` list, the
names of the external events the document declares it accepts (ADR-0014
decision 6). It is authored under the same rules as the roots - reorder
by buttons, a gesture that lands on what the document holds commits
nothing, a refused edit is held as a draft with its sentence drawn above
it - and written through its own command, `{:set_accepts, names}`. A name
is one field, so a row is one input. The row is an authoring surface
only: whether each name is one the chart can take is a host's publish
check, and nothing here draws its answer.

# `declarations`

The declarations table: one row per declared root, plus the Add control,
then the accepted-events table: one row per accepted event name, plus its
own Add control.

## Attributes

* `entries` (`:list`) (required) - The entries to draw: the document's `datamodel`, or the draft list an
  author is mid-edit on. The panel never reads the document itself -
  which list is showing is the editor's decision, made once.

* `refusal` (`:string`) - the sentence for a refused change, or `nil` when the document holds what is drawn. Defaults to `nil`.
* `read_only` (`:boolean`) - Whether this mount edits. A read-only panel draws the same three
  columns as values and no Order column, and it draws no Add control:
  order is load-bearing but it is a document edit, and a mount that
  cannot make one has nothing to move (ADR-0005's 2026-09-07 profile
  amendment - `read_only?` renders the document without offering any way
  to change it, and clause 3's reasoning about a disabled control
  applies to a row of them as much as to one field).

  Defaults to `false`.
* `accepted` (`:list`) - The accepted event names to draw: the document's `accepts`, or the draft
  list an author is mid-edit on - chosen by the editor, as `entries` is.

  Defaults to `[]`.
* `accepted_refusal` (`:string`) - the sentence for a refused accepted-event change, or `nil`. Defaults to `nil`.
* `target` (`:any`) (required)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
