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

Function components for the Kotoba editor and for rendered content.

    import Kotoba.Components

    <.form for={@form} phx-change="validate" phx-submit="save">
      <label id="post-body-label">Body</label>
      <.kotoba field={@form[:body]} id="post-body" label_id="post-body-label" />
    </.form>

    <.kotoba_content content={@post.body} />

The editor needs the `Kotoba` hook in the LiveSocket and the Kotoba CSS
(see the README). It pushes `kotoba:change` only with `change={true}`.

# `kotoba`

Renders the rich-text editor for a form field.

It renders:

  * a hidden input with the field's `name` and, as its value, the JSON of
    the field's value cast to `Kotoba.Content` (or of an empty document).
    The editor writes the document to it on every change, so a plain
    form submit posts it. It is outside the editor element, so a
    LiveView patch can update it;
  * the editor element, with `phx-hook="Kotoba"` and `phx-update="ignore"`.
    The hook builds the toolbar and the editable area in it;
  * the LiveView file input of `uploads`, visually hidden, when
    `uploads` is given. The toolbar's attach button, a drop and a paste
    of files hand the files to it.

The editor always has an accessible name: `aria-labelledby` with
`label_id` (the id of a visible label, the best choice), else
`aria-label` with `label`, else the field name in words.

Attributes that are not declared (`phx-target`, …) go on the editor
element. `aria-describedby` and `aria-invalid` go on the editable area
(the `textbox`), and follow the field: a new value in a later render
reaches it, and a value that goes away is removed. In a LiveComponent, give `phx-target={@myself}`,
so that the editor's events go to the component.

The form posts the document, so a LiveView needs no editor event for a
form. With `change`, the editor also pushes `kotoba:change` with
`%{"id", "doc", "v"}` on each change (debounced), for example to save a
draft; the LiveView must then handle it.

A change of `readonly` or `change` in a later render reaches the editor. To change
the document after the first render, use `Kotoba.Live.push_content/3`:
the editor reads the hidden input only when it mounts.

## Attributes

* `field` (`Phoenix.HTML.FormField`) (required) - the form field, for example `@form[:body]`.
* `id` (`:string`) - the id of the editor element. The default is the field's id with `_editor`. Defaults to `nil`.
* `label_id` (`:string`) - the id of the element that labels the editor (`aria-labelledby`). Without it, the editor gets `aria-label` from `label`. Defaults to `nil`.
* `label` (`:string`) - the accessible name when there is no `label_id` (`aria-label`). The default is the field name in words, for example "Body". Defaults to `nil`.
* `placeholder` (`:string`) - the text of an empty editor. Defaults to `nil`.
* `collab` (`:map`) - credentials from Kotoba.Collab.token/3; enables the optional collaboration bundle. Defaults to `nil`.
* `nodes` (`:list`) - app nodes: `{module, js_url}` tuples, or JavaScript module URLs. Defaults to `[]`.
* `features` (`:list`) - the built-in features of the editor, see `Kotoba.Features`; every feature by default. Defaults to `nil`.
* `extensions` (`:list`) - the URLs of the app's extension modules, see the Extensions guide; in the editor, after the features. Defaults to `[]`.
* `prompts` (`:list`) - the prompt list, see `Kotoba.Prompts`: a search callback, or options (`label`, `spaces`, `items`, `insert`...). Defaults to `[]`.
* `assist` (`:any`) - suggestions that the person asks for: a list of actions for the toolbar's Assist menu (`[rewrite: "Rewrite"]`), or `true` for no menu; the LiveView then handles `kotoba:assist` and `kotoba:suggestion`, see the Suggestions guide. Defaults to `nil`.
* `code_languages` (`:list`) - the ids of the languages of the code language picker, see `Kotoba.CodeLanguages`; every language by default. Defaults to `nil`.
* `uploads` (`Phoenix.LiveView.UploadConfig`) - an upload config, for example `@uploads.attachments`. Defaults to `nil`.
* `upload_label` (`:string`) - the label of the file input. Defaults to `"Attach files"`.
* `readonly` (`:boolean`) - when `true`, the editor shows the document and cannot change it; a change in a later render reaches the editor. Defaults to `false`.
* `blank_lines` (`:atom`) - `:keep` saves the blank lines a person types (empty paragraphs between blocks), as a word processor does; `:collapse` leaves them out of the saved document. Defaults to `:keep`. Must be one of `:keep`, or `:collapse`.
* `paste_markdown` (`:boolean`) - when `true`, pasted plain text that reads as Markdown becomes rich text, read on the server by `Kotoba.MarkdownPaste`, which the editor renders with no code of the app; `false` renders no LiveComponent, for a template that cannot have one. Defaults to `true`.
* `change` (`:boolean`) - when `true`, the editor pushes `kotoba:change` with the document on each change, and the LiveView (or the `phx-target` component) must handle it. Defaults to `false`.
* `debounce` (`:integer`) - milliseconds between `kotoba:change` pushes; 300 when not given. Defaults to `nil`.
* `selection_menu` (`:any`) - a menu over the selected text: `true` for the default commands (bold, italic, underline, strikethrough, code, highlight, link), or a list of commands, see `toolbar_commands/0`. The `selection` slot gives the app's own menu. Defaults to `false`.
* `class` (`:any`) - classes for the wrapper element. Defaults to `nil`.
* Global attributes are accepted. attributes for the editor element.
## Slots

* `selection` - the app's own selection menu, for example `<.kotoba_selection_menu>` with the app's icons.
* `toolbar` - a custom toolbar, for example `<.kotoba_toolbar>`; the default toolbar has the commands of the editor's features, but `subscript` and `superscript`.

# `kotoba_content`

Renders a `Kotoba.Content` as safe HTML.

The cached `:html` of the content is used when its cache version is the
current one (`Kotoba.Content.cache_version/0`), the policy is `:default`
and no extra `nodes` are given: this is the HTML that `Kotoba.Renderer`
made when the content was cast. In every other case, the document is
rendered again with `Kotoba.Renderer` (a document that no longer parses
renders as nothing). `nil` renders an empty wrapper.

## Attributes

* `content` (`:any`) (required) - a `Kotoba.Content`, or `nil`.
* `policy` (`:any`) - `:default` or `:untrusted`, see `Kotoba.Sanitizer`. Defaults to `:default`.
* `nodes` (`:list`) - extra node modules, `{module, js_url}` tuples, or JavaScript module URLs (the same list as `kotoba/1`; a URL has no module to render). Defaults to `[]`.
* `class` (`:any`) - classes for the wrapper, for example `"prose"`. Defaults to `nil`.
* Global attributes are accepted. attributes for the wrapper.

# `kotoba_selection_menu`

Renders the app's own selection menu: the menu that floats over the
selected text. Put it in the `selection` slot of `kotoba/1`:

    <.kotoba field={@form[:body]} id="post-body">
      <:selection>
        <.kotoba_selection_menu class="my-menu">
          <:button command="bold"><.icon name="hero-bold" /></:button>
          <:button command="italic"><.icon name="hero-italic" /></:button>
          <:button command="link" label="Add a link"><.icon name="hero-link" /></:button>
        </.kotoba_selection_menu>
      </:selection>
    </.kotoba>

With no `button` slots, it renders one text button for each of
`commands`. The commands, and what the editor does with the buttons, are
the ones of `kotoba_toolbar/1`. The editor shows the menu over a
selection of text, gives it the `kotoba-selection-menu` class and
`data-placement` (`"top"` or `"bottom"`), and moves the focus to it with
Alt+F10.

## Attributes

* `commands` (`:list`) - the commands, when there are no buttons. Defaults to `["bold", "italic", "underline", "strikethrough", "code", "highlight", "link"]`.
* `label` (`:string`) - the accessible name of the menu. Defaults to `"Selection formatting"`.
* `class` (`:any`) - classes for the menu element. Defaults to `nil`.
* Global attributes are accepted. attributes for the menu element.
## Slots

* `button` - Accepts attributes:

  * `command` (`:string`) (required)
  * `label` (`:string`)
  * `class` (`:any`)

# `kotoba_toolbar`

Renders a custom toolbar for an editor.

Inside the `toolbar` slot of `kotoba/1`, it needs no `for`. Elsewhere on
the page, give the editor's id as `for`: the toolbar then has
`phx-update="ignore"` (and the id `<for>-toolbar`), so that a LiveView
patch does not undo the state that the editor puts on its buttons.

With no `button` slots, it renders one text button for each of
`commands`. With `button` slots, it renders them, for example with the
app's own icons:

    <.kotoba_toolbar for="post-body">
      <:button command="bold"><.icon name="hero-bold" /></:button>
      <:button command="link" label="Add a link"><.icon name="hero-link" /></:button>
    </.kotoba_toolbar>

The editor adds `role="toolbar"`, the roving tabindex, `aria-pressed`
and `aria-disabled`. The commands are the ones of `toolbar_commands/0`;
or the command of an extension's control, `"<extension>:<command>"` (give
it a `label`); another command raises `ArgumentError`. The editor hides
the buttons of the features that it does not have (see
`Kotoba.Features`), and the buttons of the `table-*` commands (the ones that act on the table at the selection)
when the selection is not in a table, and the buttons of `gallery`,
`image-previous` and `image-next` (the ones that act on the selected
image) when no image is selected. `code-language` renders a
`<select>`, the code language picker: the editor fills its options, and
hides it when the selection is not in a code block. `highlight` opens the
color palette of the editor (`aria-haspopup="dialog"`).

## Attributes

* `for` (`:string`) - the id of the editor, when the toolbar is outside it. Defaults to `nil`.
* `commands` (`:list`) - the commands, when there are no buttons. Defaults to `["bold", "italic", "underline", "strikethrough", "highlight", "code", "subscript", "superscript", "link", "h1", "h2", "h3", "h4", "quote", "bullet", "number", "check", "code-block", "rule", "table", "upload", "assist", "code-language", "table-row-before", "table-row-after", "table-column-before", "table-column-after", "table-header-row", "table-header-column", "table-delete-row", "table-delete-column", "table-delete", "gallery", "image-previous", "image-next", "undo", "redo"]`.
* `label` (`:string`) - the accessible name of the toolbar. Defaults to `"Formatting"`.
* `class` (`:any`) - classes for the toolbar element. Defaults to `nil`.
* Global attributes are accepted. attributes for the toolbar element.
## Slots

* `button` - Accepts attributes:

  * `command` (`:string`) (required)
  * `label` (`:string`)
  * `class` (`:any`)

# `toolbar_commands`

```elixir
@spec toolbar_commands() :: [String.t()]
```

Returns the names of the toolbar commands, in toolbar order.

## Examples

    iex> "bold" in Kotoba.Components.toolbar_commands()
    true

---

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