# `Coelho.Schema.Default`
[🔗](https://github.com/nseaSeb/coelho/blob/main/lib/coelho/schema/default.ex#L1)

The schema Coelho ships with.

It covers what an application typically needs out of the box — paragraphs,
headings, lists, quotes, code blocks, images and the usual inline marks —
and is meant to be copied and adapted rather than extended in place.

## What the `link` mark emits

An `href` and a `title`, and nothing else. In particular **no `target` and
no `rel`**: a document is not necessarily rendered into a page where
opening a new tab makes sense, and a `target="_blank"` without
`rel="noopener"` hands the opened page a handle on the opener. Rather than
guess, the shipped renderer emits neither.

An application that wants them says so per render, and must set both:

    Coelho.to_html(document,
      marks: %{
        link: fn mark, inner ->
          Coelho.Render.tag(
            "a",
            [
              {"href", Coelho.Render.safe_url(Coelho.Render.attr(mark, "href"))},
              {"target", "_blank"},
              {"rel", "noopener noreferrer"}
            ],
            inner
          )
        end
      }
    )

The `href` still goes through `Coelho.Render.safe_url/1` there, because a
stored document is not re-validated on the way out.

## Alignment

`paragraph`, `heading` and `list_item` carry an `align` attribute, one of
`left`, `center`, `right` or `justify`, rendered as a `text-align` style
and read back from either a `style` or an `align` attribute on import. It
is absent from the document when unset, and re-checked against the closed
list at render time.

*How* it renders is part of the attribute's declaration — `:render_as`,
see `Coelho.Schema.Attr` — rather than a render function, so the browser
applies the same answer and an application can change it without writing
any JavaScript. An inline style is what ships because it needs no
stylesheet: the HTML works in an email, a feed, an export. It is also what
a page's own CSS cannot override, so an application that would rather own
alignment in its stylesheet asks for a class map instead — once, for the
three blocks that carry the attribute:

    Coelho.Schema.Default.build(
      align: {:class, %{"center" => "text-center", "right" => "text-right"}}
    )

The schema is built once and kept in `:persistent_term`, since it is
immutable and read on every render.

# `build`

```elixir
@spec build(keyword()) :: Coelho.Schema.t()
```

Builds the default schema without consulting the cache.

## Options

  * `:align` — how the `align` attribute reaches the DOM, in the form
    `Coelho.Schema.Attr` takes for `:render_as`. Defaults to
    `{:style, "text-align"}`.

An inline style is unanswerable by a stylesheet, so an application that
would rather own alignment in CSS says so once, here, rather than
redeclaring the three blocks that carry the attribute:

    Coelho.Schema.Default.build(
      align: {:class, %{"center" => "text-center", "right" => "text-right"}}
    )

The result is not cached — `schema/0` caches the default one. Build yours
once at compile time, as an application with any custom schema already
does.

# `schema`

```elixir
@spec schema() :: Coelho.Schema.t()
```

Returns the default schema, building it on first use.

---

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