# `MishkaCmsCore.Runtime.PageBuilder.Visibility`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core/runtime/page_builder/visibility.ex#L5)

An element kept in the page but shown to nobody: hidden from visitors, the way a line of code is
commented out.

## The marker is markup

A hidden element carries the bare attribute `data-pb-hidden`. Node ids are minted per parse and
never written to the template (see `MishkaCmsCore.Runtime.PageBuilder.Tree`), so the state has to
live in the markup itself; there it survives every save, duplicate, copy, paste, draft, snapshot
and revert with nothing to anchor. Presence is what counts, as with every switch the Inspector
reads; a value someone types is ignored.

## Kept in the source, gone from the output

Every compiler — page, layout, component, error page — and
`MishkaCmsCore.Runtime.Compilers.LiveViewCompiler.render_template/2` compile `strip/1` of the
template rather than the template: each hidden element and everything inside it is removed, so a
visitor's HTML carries no trace of it. A template that holds no marker is compiled exactly as
stored, without being parsed. The checks that run when a template is saved compile it as stored,
so a hidden element must still be valid markup and showing it again cannot break the page.

## Not the eye

The layers rail's eye folds an element away on the canvas for the editing session only; it is
view state and is never saved. Hiding from visitors is document state: it is saved, published, and
shown on every surface of the editor.

## Nested

An element inside a hidden one is hidden with it, and is shown by showing its container. One hidden
on its own before its container was stays hidden when the container is shown again.

# `attribute`

```elixir
@spec attribute() :: String.t()
```

The attribute a hidden element carries: `"data-pb-hidden"`.

# `hidden?`

```elixir
@spec hidden?(MishkaCmsCore.Runtime.PageBuilder.Tree.Node.t() | nil) :: boolean()
```

Whether `node` is hidden from visitors itself, whatever its ancestors are.

# `hidden_by`

```elixir
@spec hidden_by(MishkaCmsCore.Runtime.PageBuilder.Tree.t(), String.t() | nil) ::
  MishkaCmsCore.Runtime.PageBuilder.Tree.Node.t() | nil
```

What hides the node `id` from visitors: the node itself when it is hidden, else its nearest hidden
ancestor; `nil` when it is on the page.

# `hidden_roots`

```elixir
@spec hidden_roots(MishkaCmsCore.Runtime.PageBuilder.Tree.t()) :: [
  MishkaCmsCore.Runtime.PageBuilder.Tree.Node.t()
]
```

The hidden nodes no hidden ancestor already covers, in document order.

# `hideable?`

```elixir
@spec hideable?(MishkaCmsCore.Runtime.PageBuilder.Tree.Node.t() | nil) :: boolean()
```

Whether `node` can be hidden: an element, a component or a slot — what carries attributes — but
never a document's root, a layout's `<body>`. A run of text or an expression is hidden by hiding
the element around it.

# `prune`

```elixir
@spec prune(MishkaCmsCore.Runtime.PageBuilder.Tree.t()) ::
  MishkaCmsCore.Runtime.PageBuilder.Tree.t()
```

`tree` without its hidden elements and everything inside them.

# `strip`

```elixir
@spec strip(term()) :: term()
```

The template a compiler compiles: `template` without its hidden elements. One that holds no
marker is returned as it is, unparsed. One that cannot be parsed is returned as it is, logged:
a compile never fails because of this step.

# `toggle_op`

```elixir
@spec toggle_op(MishkaCmsCore.Runtime.PageBuilder.Tree.t(), String.t()) ::
  {:ok, map()} | {:error, String.t()}
```

The edit that hides the node `id` from visitors, or shows it again: one bare attribute set or
removed, the shape every Inspector switch writes, so it takes the editor's one funnel — undo, the
history, the lock, the plugin hooks. Refused for a node that cannot be hidden, and for one hidden
only because its container is, which is shown by showing the container.

---

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