# `PhiaUi.Components.MentionInput`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/inputs/mention_input.ex#L1)

Mention input component for PhiaUI.

A textarea with `@mention` autocomplete support. When the user types `@`,
the `PhiaMentionInput` JS hook detects the trigger character and emits a
`push_event("mention_search", %{query: query})` to the server. The LiveView
filters the user list, reassigns suggestions, and re-renders the dropdown.
When a suggestion is selected, the hook inserts a styled chip into the
textarea and the mentioned user IDs are tracked in a hidden CSV input for
form submission.

## When to use

Use `MentionInput` anywhere users should be able to tag other users with
`@username`:

- Team collaboration comment threads (GitHub/Linear style)
- Task assignment descriptions
- Chat messages in a team messenger
- Document editor annotations
- Support ticket replies

## Anatomy

| Component          | Element    | Purpose                                             |
|--------------------|------------|-----------------------------------------------------|
| `mention_input/1`  | `div`      | Root wrapper (textarea + hook + hidden input + dropdown) |
| `mention_dropdown/1`| `ul`      | Suggestion listbox — hidden when `open: false`      |
| `mention_chip/1`   | `span`     | Inline `@name` highlight for server-rendered previews |

## How it works

1. User types `@` in the textarea
2. `PhiaMentionInput` hook fires `push_event("mention_search", %{query: ""})`
3. LiveView runs `handle_event("mention_search", ...)` → assigns suggestions
4. User types more → hook fires `push_event("mention_search", %{query: "ali"})`
5. LiveView filters and re-assigns suggestions; dropdown opens (`mention_open: true`)
6. User clicks / arrows to a suggestion → `phx-click="mention_select"`
7. LiveView appends the ID to `mentioned_ids`; hook inserts a chip into the textarea
8. On form submit, the hidden input `name_ids` carries the CSV of mentioned IDs

## Complete example

    defmodule MyAppWeb.CommentLive do
      use Phoenix.LiveView

      def mount(_params, _session, socket) do
        {:ok, assign(socket,
          mention_suggestions: [],
          mention_open: false,
          mention_search: "",
          mentioned_ids: []
        )}
      end

      # Hook emits push_event; LiveView handles it as a regular event
      def handle_event("mention_search", %{"query" => q}, socket) do
        suggestions =
          Users.search(q, limit: 8)
          |> Enum.map(&%{id: &1.id, name: &1.name, avatar: &1.avatar_url})

        {:noreply, assign(socket,
          mention_suggestions: suggestions,
          mention_open: true,
          mention_search: q
        )}
      end

      def handle_event("mention_select", %{"id" => id, "name" => _name}, socket) do
        ids = [id | socket.assigns.mentioned_ids] |> Enum.uniq()
        {:noreply, assign(socket,
          mentioned_ids: ids,
          mention_open: false,
          mention_search: ""
        )}
      end
    end

    <%!-- Template --%>
    <.mention_input
      id="comment-body"
      name="comment[body]"
      suggestions={@mention_suggestions}
      open={@mention_open}
      search={@mention_search}
      mentioned_ids={@mentioned_ids}
      on_mention="mention_search"
      on_select="mention_select"
      placeholder="Leave a comment… type @ to mention someone"
    />

## Displaying resolved mentions in read-only content

When rendering submitted comment content (e.g. in a feed), use `mention_chip/1`
to highlight resolved user mentions with the same visual style:

    <p>
      Hey
      <.mention_chip name="Alice" user_id={alice.id} />
      the PR is ready for review.
    </p>

## Hook setup

    # app.js
    import PhiaMentionInput from "./hooks/mention_input"
    let liveSocket = new LiveSocket("/live", Socket, {
      hooks: { PhiaMentionInput }
    })

## ARIA

The `<textarea>` carries `role="combobox"`, `aria-autocomplete="list"`,
`aria-haspopup="listbox"`, and `aria-expanded` toggled by the `open` assign.
The dropdown has `role="listbox"`. Each suggestion option has `role="option"`.

# `mention_chip`

Renders an inline `@mention` highlight chip for server-rendered content.

Use this component when displaying already-saved content that contains
resolved mentions — for example, rendering a comment body from the database
where mentioned user IDs have been resolved to names.

In client-side mode, the `PhiaMentionInput` hook inserts chips dynamically
into the textarea. `mention_chip/1` is for the read-only rendering path.

## Example

    <p>
      <.mention_chip name="Sarah Lin" user_id={sarah.id} />
      can you review the attached document?
    </p>

## Attributes

* `name` (`:string`) (required) - Display name of the mentioned user (rendered as `@name`).
* `user_id` (`:string`) (required) - User ID stored in the `data-mention-id` attribute for client-side processing.
* `class` (`:string`) - Additional CSS classes for the chip span. Defaults to `nil`.

# `mention_dropdown`

Renders the `@mention` suggestion dropdown.

Uses two function heads:
- `open: false` → renders `~H""` (empty fragment — no DOM element at all)
- `open: true` → renders the `<ul role="listbox">` with suggestion items

This pattern is preferred over CSS visibility toggling because it keeps the
DOM clean and prevents screen readers from announcing the hidden list.

Each suggestion fires `on_select` with `phx-value-id` and `phx-value-name`.

## Attributes

* `id` (`:string`) - DOM id for the listbox element — referenced by `aria-controls` on the textarea. Defaults to `nil`.
* `suggestions` (`:list`) - List of `%{id, name, avatar}` suggestion maps. Defaults to `[]`.
* `open` (`:boolean`) - Controls dropdown visibility. Uses two function heads: false → empty fragment. Defaults to `false`.
* `on_select` (`:string`) - `phx-click` event name fired when a suggestion is chosen. Defaults to `"mention_select"`.
* `class` (`:string`) - Additional CSS classes for the listbox `<ul>`. Defaults to `nil`.

# `mention_input`

Renders the mention input widget.

The root div contains:
1. A `<textarea>` wired to the `PhiaMentionInput` hook
2. A hidden `<input>` that holds the CSV of mentioned user IDs
3. A `mention_dropdown/1` suggestion panel controlled by the `open` assign

The LiveView controls open/close state and the suggestion list. The hook
handles `@` detection in the textarea and DOM insertion of `@name` chips.

## Attributes

* `id` (`:string`) (required) - DOM id for the textarea element. The `PhiaMentionInput` hook is anchored
  to this element and uses it to identify the instance.

* `name` (`:string`) (required) - Form field name for the textarea content.
  The hidden input for mentioned IDs will be named `#{name}_ids`.

* `suggestions` (`:list`) - List of `%{id: string, name: string, avatar: string | nil}` suggestion maps.
  Updated by the LiveView in response to `on_mention` events.
  An empty list renders "No results" inside the open dropdown.

  Defaults to `[]`.
* `open` (`:boolean`) - Whether the suggestion dropdown is currently visible.
  Set to `true` in `handle_event("mention_search", ...)` and
  `false` in `handle_event("mention_select", ...)`.

  Defaults to `false`.
* `search` (`:string`) - Current `@mention` search query typed by the user. Defaults to `""`.
* `value` (`:string`) - Current textarea text value (for server-rendered initial content). Defaults to `""`.
* `mentioned_ids` (`:list`) - List of already-selected user ID strings.
  Serialised as a comma-separated value in the hidden `name_ids` input
  for form submission and changeset processing.

  Defaults to `[]`.
* `on_mention` (`:string`) - Event name that the hook emits via `push_event` when the user types after `@`.
  The LiveView receives `%{"query" => query}`.

  Defaults to `nil`.
* `on_select` (`:string`) - `phx-click` event name fired when a suggestion is selected.
  The LiveView receives `%{"id" => user_id, "name" => user_name}`.

  Defaults to `"mention_select"`.
* `placeholder` (`:string`) - Textarea placeholder text. Defaults to `"Type a message… use @ to mention"`.
* `class` (`:string`) - Additional CSS classes for the root wrapper div. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the root div.

---

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