# `MishkaCmsCoreWeb.Live.Admin.Components.ContentComponentPicker`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core_web/live/admin/components/content_component_picker.ex#L5)

The server half of the content editor `MishkaCmsCoreWeb.UIAdapters.Admin.textarea/1` draws for a
`:textarea` field with `ui do extra %{content_editor: true} end`: the palette an author places
from, the settings of a placed component, and the answers the editor's hook asks for. See
`MishkaCmsCore.Runtime.ContentComponents` for the marker and how a page draws it.

The adapter mounts it inside the editor, so a resource adds nothing else to its form.

## The palette

Two tabs: **Blocks** — whole ready-made pieces, `MishkaCmsCore.Runtime.ContentBlocks.available/3`
— and **Components**, every component the site may place (`ContentComponents.palette/2`) under
its heading, text first (`ContentComponents.category/2`). One search box searches the tab that
is open; the headings filter the components. It is read in the background as the signed-in user
the first time it is opened. A master's record is on the site its Site field names, else the
site of the record being edited; a site user's is on their own (`site/1`).

## The settings

A component being placed or edited opens its settings in a drawer at the side of the page — its
attributes, the text and components inside it, and its slot entries, each of those with its own,
put in another order with their arrows or dragged there by their grips — through a portal, so the
drawer's form is a form of its own and not part of the record's. Every change is written straight
back into the component in the content, as the author types, and the drawer is closed with Done, a
click outside it, or Escape. A picture or a video is chosen from the site's media library, or
uploaded to it, in `MishkaCmsCoreWeb.Live.Admin.Components.ContentMediaChooser`, which opens over
the settings and leaves them as they were — scrolled to the field it was opened for, with the same
parts open.

## What the hook asks

The editor's surface carries this component's DOM id as `data-components`, and the hook pushes
these to it:

  * `"segments"`, `%{"html" => html}` — answered `%{segments: [...], styles: href | nil}`: `html` as
    `ContentComponents.segments/1` splits it, `%{type: "html", html: html}` and
    `%{type: "component", name: name, marker: marker}`.
  * `"build"`, `%{"name" => name, "attrs" => %{}, "inner" => html}` — answered
    `%{name: name, marker: marker}` for a component the palette lists, with only the attributes
    it declares and an empty entry for each slot it requires, and the palette closes; or
    `%{error: message}`, and the palette stays open and says why.
  * `"block"`, `%{"id" => id}` — a ready-made block's marker, answered as `"build"` is.
  * `"nest"`, `%{"marker" => marker, "name" => name}` or `%{"marker" => marker, "block" => id}`
    — the component `marker` names with the component `name`, or the ready-made block `id`,
    put inside it: beside its part `"beside"` (`"r-2"`), after it when `"after"` is `true`, or
    at the end of what it holds. Answered as `"build"` is; `%{error: message}` when `marker`
    holds nothing or either is not listed.
  * `"reorder"`, `%{"marker" => marker, "path" => path, "beside" => path, "after" => boolean}` —
    the component `marker` names with its part at `path` moved before, or after, its sibling at
    `beside`, answered as `"build"` is.
  * `"edit"`, `%{"marker" => marker, "serial" => n}` — opens the settings of the component
    `marker` names, filled in from it. Answered `%{ok: true}`, or `%{error: message}` when the
    palette does not list it. `n` comes back on what those settings write.
  * `"close"` — closes the palette, and `"settings_done"` the settings.

`"nest"` and `"reorder"` carry the `"serial"` of the settings open on that component, if they are:
the settings then take the change, answer `%{ok: true}` and write it back as `applied`.

And this pushes `"mishka:content_editor"` to the page, `%{id: editor_id, ...}` with:

  * `styles: href` — the stylesheet previews are drawn with, once it is built
    (`MishkaCmsCore.Runtime.ContentEditorStyles`); `"segments"` answers it too, when known.
  * `holders: [name]` — the components the palette lists that take others inside them, once the
    palette is read.
  * `previews: [%{marker: marker, preview: html}]` — a component's preview, drawn in the
    background after a marker is answered or written, each in a task of its own; it runs the
    component's own code. A component that raises as it is drawn is pushed as a notice saying
    so — the page would fail on it too. The parts it holds are marked in it (`marked/1`).
  * `applied: %{name: name, marker: marker}, serial: n` — the component being edited, as the
    settings now write it.
  * `done: true, serial: n` — the settings closed.

Every name is checked as a string: against the names the palette lists before a marker is
written, and against the components the site may draw (`ContentComponents.draw/2`) before a
preview is. No name a request carries is made into an atom.

# `site`

```elixir
@spec site(map() | nil) :: String.t() | nil
```

The site the record a Gervaz form `state` edits is on: for a master, the one its Site field names,
else the record's own; for a site user, their own. `nil` is the global components alone.

---

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