# `PhiaUi.Components.Editor.RichEditor`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/editor/rich_editor.ex#L1)

Rich Editor Suite — 8 components for building rich text editing experiences
with Phoenix LiveView.

This module provides PhiaUI's native rich text editor integration using the
vanilla `PhiaEditor` engine (zero npm dependencies). All formatting is handled
via `document.execCommand`, the Selection API, and DOM manipulation.

## Architecture

- **JSON is canonical** — documents stored as typed JSON trees
- **Server-driven toolbar** — active marks/nodes pushed from client, toolbar
  state lives in LiveView assigns (not JS)
- **Form integration** — hidden input syncs content for standard form submission
- **Phoenix events** — `on_update` and `on_selection` event names for LiveView handlers

## Components

### Core
- `rich_editor/1`        — main editor with toolbar, content area, form integration (PhiaRichEditor)
- `rich_toolbar/1`       — server-driven toolbar rendered from active marks/nodes assigns
- `rich_content/1`       — read-only rendered content from editor JSON

### Floating UI
- `rich_bubble_menu/1`   — selection-aware floating toolbar (PhiaRichEditor)
- `rich_floating_menu/1` — empty-line insertion menu (PhiaRichEditor)
- `rich_slash_commands/1` — "/" command palette (PhiaRichEditor)
- `rich_mention/1`       — @ mention suggestions (PhiaRichEditor)

### Collaboration
- `collab_cursors/1`     — collaborative cursor indicators (PhiaCollab)

## Setup

    # In app.js (zero npm dependencies needed):
    import PhiaRichEditor from "./hooks/phia_rich_editor"
    let liveSocket = new LiveSocket("/live", Socket, { hooks: { PhiaRichEditor } })

# `collab_cursors`

Collaborative cursor indicators for the rich editor.

Renders colored cursor labels for connected users.

## Example

    <.collab_cursors
      id="cursors-1"
      editor_id="my-editor"
      cursors={@connected_users}
    />

Each cursor should be a map with `:name`, `:color`, and optionally `:avatar_url`.

## Attributes

* `id` (`:string`) (required)
* `editor_id` (`:string`) (required)
* `cursors` (`:list`) - Defaults to `[]`.
* `class` (`:string`) - Defaults to `nil`.

# `rich_bubble_menu`

Selection-aware floating toolbar for the rich editor.

Appears above text selection using the vanilla PhiaEditor positioning.

## Example

    <.rich_bubble_menu id="bubble-1" editor_id="my-editor">
      <button phx-click={...}>Bold</button>
    </.rich_bubble_menu>

## Attributes

* `id` (`:string`) (required)
* `editor_id` (`:string`) (required)
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `inner_block` (required)

# `rich_content`

Renders editor JSON content as read-only HTML.

Uses `EditorContent.content_to_html/1` for server-side JSON-to-HTML conversion.
Always sanitize content before display.

## Examples

    <%!-- From JSON map --%>
    <.rich_content content={@post.body_json} prose_size={:lg} />

    <%!-- From JSON string --%>
    <.rich_content content={Jason.decode!(@post.body)} />

## Attributes

* `content` (`:any`) - Defaults to `nil`.
* `prose_size` (`:atom`) - Defaults to `:base`. Must be one of `:sm`, `:base`, or `:lg`.
* `class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted.

# `rich_editor`

Main rich text editor with toolbar, content area, and form integration.

Uses the `PhiaRichEditor` hook which initializes the vanilla `PhiaEditor`
engine (execCommand-based, zero npm dependencies).

## Content Flow

    [Server: LiveView]
      assigns.content = JSON string
      push_event("editor:command:my-editor", %{command: "toggleBold"})
      |
    [Client: PhiaRichEditor hook]
      editor.getHTML() → pushEvent("editor:update", %{json, html, word_count})
      editor.isActive() → pushEvent("editor:selection", %{active_marks, ...})

## Examples

    <%!-- Standalone --%>
    <.rich_editor id="blog-editor" placeholder="Write..." min_height="400px" />

    <%!-- Form-integrated --%>
    <.form for={@form} phx-submit="publish">
      <.rich_editor id="post-editor" field={@form[:body]} />
    </.form>

    <%!-- With server-driven commands --%>
    def handle_event("make_bold", _, socket) do
      {:noreply, push_event(socket, "editor:command:post-editor", %{command: "toggleBold"})}
    end

## Attributes

* `id` (`:string`) (required)
* `field` (`Phoenix.HTML.FormField`) - Defaults to `nil`.
* `value` (`:string`) - Defaults to `nil`.
* `placeholder` (`:string`) - Defaults to `"Type '/' for commands, or start writing..."`.
* `min_height` (`:string`) - Defaults to `"300px"`.
* `extensions` (`:list`) - Defaults to `[:starter_kit, :placeholder]`.
* `on_update` (`:string`) - Defaults to `"editor:update"`.
* `on_selection` (`:string`) - Defaults to `"editor:selection"`.
* `toolbar_variant` (`:atom`) - Defaults to `:default`. Must be one of `:default`, `:floating`, or `:compact`.
* `show_word_count` (`:boolean`) - Defaults to `true`.
* `show_find_replace` (`:boolean`) - Defaults to `false`.
* `content_format` (`:atom`) - Defaults to `:json`. Must be one of `:json`, or `:html`.
* `collab_enabled` (`:boolean`) - Enable collaborative editing mode. Defaults to `false`.
* `collab_doc_id` (`:string`) - Document ID for collaboration channel. Defaults to `nil`.
* `collab_user` (`:map`) - Current user map with :id, :name, :color keys. Defaults to `nil`.
* `class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `toolbar_extra` - Extra toolbar content appended after default groups.

# `rich_floating_menu`

Empty-line insertion menu for the rich editor.

Appears at the cursor when the current block is empty.

## Example

    <.rich_floating_menu id="float-1" editor_id="my-editor">
      <button phx-click={...}>Heading</button>
      <button phx-click={...}>Image</button>
    </.rich_floating_menu>

## Attributes

* `id` (`:string`) (required)
* `editor_id` (`:string`) (required)
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `inner_block` (required)

# `rich_mention`

Mention suggestions dropdown for the rich editor.

Triggered by typing "@". Shows a server-driven list of suggestions.

## Example

    <.rich_mention
      id="mention-1"
      editor_id="my-editor"
      suggestions={@mention_suggestions}
    />

Each suggestion should be a map with `:id`, `:label`, and optionally `:avatar_url`.

## Attributes

* `id` (`:string`) (required)
* `editor_id` (`:string`) (required)
* `suggestions` (`:list`) - Defaults to `[]`.
* `class` (`:string`) - Defaults to `nil`.

# `rich_slash_commands`

Slash command palette for the rich editor.

Triggered by typing "/" at the start of a line.

## Example

    <.rich_slash_commands id="slash-1" editor_id="my-editor">
      <:command label="Heading 1" description="Large heading" action="setHeading" icon="heading" />
      <:command label="Bullet List" description="Unordered list" action="toggleBulletList" icon="list" />
    </.rich_slash_commands>

## Attributes

* `id` (`:string`) (required)
* `editor_id` (`:string`) (required)
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `command` - Accepts attributes:

  * `label` (`:string`) (required)
  * `description` (`:string`)
  * `icon` (`:string`)
  * `action` (`:string`) (required)

# `rich_toolbar`

Server-driven toolbar for the rich editor.

Active states are determined by assigns (pushed from client via selection
events), not by JavaScript DOM inspection.

## Example

    <.rich_toolbar
      editor_id="my-editor"
      active_marks={@editor_state.active_marks}
      active_nodes={@editor_state.active_nodes}
      heading_level={@editor_state.heading_level}
    />

## Attributes

* `variant` (`:atom`) - Defaults to `:default`. Must be one of `:default`, `:floating`, or `:compact`.
* `editor_id` (`:string`) (required)
* `active_marks` (`:list`) - Defaults to `[]`.
* `active_nodes` (`:list`) - Defaults to `[]`.
* `heading_level` (`:any`) - Defaults to `nil`.
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `extra` - Extra toolbar content appended after default groups.

---

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