# `Kotoba.Features`
[🔗](https://github.com/hattoriai/kotoba/blob/v0.5.0/lib/kotoba/features.ex#L1)

The built-in features of the editor, and the check of a document against
the features of a field.

`Kotoba.Components.kotoba/1` takes a `features` list: the editor has
those features, and no other. With no list, it has every feature.

    <.kotoba field={@form[:comment]} features={~w(bold italic links lists mentions)} />

| Feature | What it is | Nodes and formats |
| ------- | ---------- | ----------------- |
| `bold` | bold text | the `bold` format |
| `italic` | italic text | the `italic` format |
| `underline` | underlined text | the `underline` format |
| `strikethrough` | struck text | the `strikethrough` format |
| `highlight` | highlighted text, and the color palette | the `highlight` format, a text color |
| `subscript` | subscript text (not in the default toolbar) | the `subscript` format |
| `superscript` | superscript text (not in the default toolbar) | the `superscript` format |
| `inline_code` | code in a line of text | the `code` format |
| `links` | links, autolinks, the link form | `link`, `autolink` |
| `headings` | headings | `heading` |
| `quotes` | block quotes | `quote` |
| `lists` | bulleted and numbered lists | `list`, `listitem` |
| `check_lists` | check lists (needs `lists`) | a `list` with `listType` `"check"` |
| `code_blocks` | code blocks and their language picker | `code`, `code-highlight` |
| `horizontal_rules` | horizontal rules | `horizontalrule` |
| `tables` | tables | `table`, `tablerow`, `tablecell` |
| `attachments` | file uploads and image galleries (with the `uploads` attribute) | `attachment`, `gallery` |
| `mentions` | prompts and mentions (with the `prompts` attribute) | `mention` |
| `images` | images from a URL, as Markdown has them | `image` |
| `footnotes` | footnotes and their references | `footnotedefinition`, `footnotereference` |

Paragraphs, line breaks, tabs, undo and redo are always there. The case
formats (`lowercase`, `uppercase`, `capitalize`) are not features: the
editor keeps them.

The keyboard shortcuts of the formats are Cmd (Ctrl on other systems)
with `B`, `I`, `U`, `Shift+H` (highlight), `,` (subscript) and `.`
(superscript). Subscript and superscript have no button in the default
toolbar: an app's toolbar (`Kotoba.Components.kotoba_toolbar/1`) can have
them.

A feature that is off has no node, no toolbar button, no Markdown shortcut
and no keyboard shortcut in the editor. A pasted table, heading or code
block comes in as paragraphs, and a pasted format that is off is dropped.
A stored node of a feature that is off loads as an unknown node: the
editor shows a placeholder and saves it with no change.

The [Editing features](features.md) guide has the shortcuts and the
toolbar of each feature.

The editor is not a check: a request can post any document. To refuse a
document with a feature that the field does not have, use
`Kotoba.Content.validate_features/3` in the changeset, or `check/2`.
App nodes and unknown nodes are not features, and `check/2` allows them.

# `feature`

```elixir
@type feature() ::
  :bold
  | :italic
  | :underline
  | :strikethrough
  | :highlight
  | :subscript
  | :superscript
  | :inline_code
  | :links
  | :headings
  | :quotes
  | :lists
  | :check_lists
  | :code_blocks
  | :horizontal_rules
  | :tables
  | :attachments
  | :mentions
  | :images
  | :footnotes
```

A built-in feature.

# `all`

```elixir
@spec all() :: [feature()]
```

Returns the features, in order.

## Examples

    iex> :tables in Kotoba.Features.all()
    true

# `check`

```elixir
@spec check(Kotoba.Document.t(), [atom() | String.t()]) :: :ok | {:error, [feature()]}
```

Checks that a document uses only the given features (a list for
`names!/1`). Returns `:ok`, or `{:error, features}` with the features
that it uses and does not have.

## Examples

    iex> {:ok, doc} =
    ...>   Kotoba.Document.parse(%{
    ...>     "kotoba" => 1,
    ...>     "lexical" => "0.51",
    ...>     "root" => %{"type" => "root", "children" => [%{"type" => "quote", "children" => []}]}
    ...>   })
    iex> Kotoba.Features.check(doc, [:bold])
    {:error, [:quotes]}
    iex> Kotoba.Features.check(doc, [:quotes])
    :ok

# `names!`

```elixir
@spec names!([atom() | String.t()]) :: [feature()]
```

Returns the features of a list of names (atoms or strings), in the order
of `all/0` and once each.

Raises `ArgumentError` for a name that is not a feature, or for a
feature without the one that it needs (`check_lists` needs `lists`).

## Examples

    iex> Kotoba.Features.names!(["lists", :bold, "lists"])
    [:bold, :lists]

# `used`

```elixir
@spec used(Kotoba.Document.t()) :: [feature()]
```

Returns the features that a document uses, in the order of `all/0`.

## Examples

    iex> {:ok, doc} =
    ...>   Kotoba.Document.parse(%{
    ...>     "kotoba" => 1,
    ...>     "lexical" => "0.51",
    ...>     "root" => %{
    ...>       "type" => "root",
    ...>       "children" => [
    ...>         %{"type" => "heading", "tag" => "h2", "children" => [%{"type" => "text", "text" => "Hi", "format" => 1}]}
    ...>       ]
    ...>     }
    ...>   })
    iex> Kotoba.Features.used(doc)
    [:bold, :headings]

---

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