# `PhoenixKitWeb.Components.MediaBrowser`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.2.0/lib/phoenix_kit_web/components/media_browser.ex#L1)

MediaBrowser LiveComponent — embeddable media management UI.

Provides a full media browser with folder navigation, file upload, search,
and selection tools. Operates in two modes:

- **Uncontrolled** (default): all navigation state is owned internally.
  No URL sync.
- **Controlled** (opt-in): when `on_navigate` is set to a truthy value,
  navigation events (`navigate_folder`, `search`, `clear_search`, `set_page`)
  emit `{PhoenixKitWeb.Components.MediaBrowser, id, {:navigate, params}}`
  to the parent LiveView process instead of mutating local state. The parent
  must call `push_patch` and feed URL params back via `send_update` with a
  `:nav_params` key.

## Enabling uploads

The fastest path is the `Embed` helper — one `use` line gives you
uploads, the validate-channel stub, and the message delegator:

    defmodule MyAppWeb.MediaPage do
      use MyAppWeb, :live_view
      use PhoenixKitWeb.Components.MediaBrowser.Embed
    end

Manual setup (if you prefer explicit wiring) is three calls:

    def mount(_params, _session, socket) do
      {:ok, PhoenixKitWeb.Components.MediaBrowser.setup_uploads(socket)}
    end

    def handle_event("validate", _params, socket), do: {:noreply, socket}

    def handle_info({__MODULE__, _, _} = msg, socket) do
      PhoenixKitWeb.Components.MediaBrowser.handle_parent_info(msg, socket)
    end

## Usage (uncontrolled)

    <.live_component
      module={PhoenixKitWeb.Components.MediaBrowser}
      id="media-browser"
      phoenix_kit_current_user={@phoenix_kit_current_user}
    />

## Picking into a typed slot

`only_file_type` restricts the browser to one kind for its whole lifetime —
the listing is filtered to it, the type-filter control is hidden, and an
off-type upload is refused, so the other kinds are simply not reachable:

    <.live_component
      module={PhoenixKitWeb.Components.MediaBrowser}
      id="audio-picker"
      select_mode
      only_file_type="audio"
      phoenix_kit_current_user={@phoenix_kit_current_user}
    />

Use it wherever the selection fills a typed field. Offering everything and
validating afterwards works, but it lets someone choose a PNG for an audio
slot and only find out on the rejection — and if a consumer forgets that
re-check, the PNG lands in the field and renders as a dead `<audio>`.

Values: `image`, `video`, `document`, `audio`, `archive`, `other`.

## Usage (controlled — URL-sync driven by parent)

    <.live_component
      module={PhoenixKitWeb.Components.MediaBrowser}
      id="media-browser"
      phoenix_kit_current_user={@phoenix_kit_current_user}
      on_navigate={true}
    />

The parent LiveView must implement:

    def handle_info({PhoenixKitWeb.Components.MediaBrowser, "media-browser",
                     {:navigate, params}}, socket) do
      # push_patch to update URL, handle_params will send_update back
    end

## Required attributes

- `id` — unique DOM id (required by LiveComponent)

## Optional attributes

- `phoenix_kit_current_user` — logged-in user struct (for upload attribution)
- `scope_folder_id` — constrain the browser to a virtual root folder
- `on_navigate` — when truthy, enables controlled mode (URL-sync via parent)
- `admin` — clicking a file always opens the in-place modal viewer
  (image / video / PDF / icon + metadata + Download + prev/next
  navigation). When `true`, the viewer sidebar additionally shows an
  "Open details page" button linking to `/admin/media/:uuid`, and
  rotations made in the viewer persist to the file row. Bulk-select is
  still reachable via the toolbar's Select button — once `select_mode`
  is on, clicks toggle selection instead of opening the modal.

# `handle_event`

# `handle_parent_info`

Catch-all handler for parent LiveViews to delegate MediaBrowser messages.

# `render`

# `setup_uploads`

Handles the upload setup message from the MediaBrowser component.

Parent LiveViews embedding MediaBrowser should add this to their `handle_info`:

    def handle_info({PhoenixKitWeb.Components.MediaBrowser, _id, :setup_uploads}, socket) do
      {:noreply, PhoenixKitWeb.Components.MediaBrowser.setup_uploads(socket)}
    end

Or use the catch-all delegator:

    def handle_info({PhoenixKitWeb.Components.MediaBrowser, _, _} = msg, socket) do
      PhoenixKitWeb.Components.MediaBrowser.handle_parent_info(msg, socket)
    end

# `update`

---

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