PhoenixKitWeb.Components.MediaBrowser.Embed (phoenix_kit v1.7.130)

Copy Markdown View Source

One-line embedder for PhoenixKitWeb.Components.MediaBrowser.

LiveView uploads must live on the parent socket (not the LiveComponent), so embedding the MediaBrowser requires three small pieces of plumbing on the parent: an allow_upload, a "validate" event stub for the upload channel, and a handle_info delegator for component→parent messages.

This module bundles all three into a single use call.

Usage

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

  def mount(_params, _session, socket) do
    {:ok, socket}
  end
end

Then in the template:

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

Pass url_sync: true (or url_sync: [id: "your-component-id"]) to make the embedded browser reflect the current folder / search / page / view in the page URL — so a deep link like …?folder=<uuid> reopens that folder on reload and can be shared with someone else.

use PhoenixKitWeb.Components.MediaBrowser.Embed, url_sync: true

# multiple browsers, or a non-default component id:
use PhoenixKitWeb.Components.MediaBrowser.Embed,
  url_sync: [id: "my-media-browser"]

With url_sync on, the host template must pass the controlled-mode attrs through to the component:

<.live_component
  module={PhoenixKitWeb.Components.MediaBrowser}
  id="media-browser"
  on_navigate={:navigate}
  initial_params={@initial_params}
  parent_uploads={@uploads}
/>

Everything else is automatic: initial_params is parsed from the URL in on_mount, folder navigation push_patches the new params into the address bar, and a reload feeds them back to the component. The folder is tracked by uuid (stable across renames); an unknown / out-of-scope uuid falls back to root. The base path is taken from the live URL, so any router prefix is respected.

URL sync is implemented with LiveView lifecycle hooks (attach_hook(:handle_params) + attach_hook(:handle_info) in on_mount), not injected handle_params/3 clauses — so it composes cleanly with a host LiveView that already defines its own handle_params / handle_info (e.g. an …/orders/:id/edit/files page that loads the order in its own handle_params). Nothing to reconcile; both run. The push_patch only appends the query string to the current path, so every existing segment (locale, parent resource ids, sub-tab) is preserved.

Single-browser-per-page is assumed: the query keys (folder, q, page, orphaned, view) are not namespaced per component, so two url-synced browsers on one page would fight over them. Give only one the url_sync option in that case.

What gets injected

  • on_mount — calls MediaBrowser.setup_uploads/1 so @uploads.media_files is available on every mount of this LiveView. With url_sync, also assigns :initial_params parsed from the mount params.
  • Fallback handle_event("validate", _, socket) — absorbs the upload channel's phx-change events. User-defined clauses with other event names still win because they are defined first.
  • With url_sync: a :handle_params hook (feeds URL params to the component + captures the live path) and a :handle_info hook that intercepts {MediaBrowser, id, {:navigate, _}} and push_patches, both attached in on_mount so they compose with the host's own handlers.
  • Fallback handle_info({MediaBrowser, _, _}, socket) — forwards to MediaBrowser.handle_parent_info/2 for component registration and upload piping.
  • Fallback handle_info({:leaf_changed, _}, socket) — routes Leaf editor content updates from the sidebar comments (when PhoenixKitComments is installed) to PhoenixKitComments.Web.CommentsComponent.forward_leaf_event/2. Without this, comment Leaf editors render but the typed content never reaches the server. The clause only injects when PhoenixKitComments.Web.CommentsComponent is loaded — otherwise it's compiled away. User-defined :leaf_changed clauses (e.g. for a post-content editor on the same page) still win because they are defined first.

All fallbacks are injected via @before_compile, so user clauses declared earlier in the module match before them.

Summary

Functions

Build the query-string map from a {:navigate, params} payload — omitting defaults so a root, unsearched, first-page view yields a clean bare URL.

Parse a LiveView params map into the nav_params shape MediaBrowser's controlled mode expects (folder, q, page, filter_orphaned, view).

Functions

build_nav_query(p)

Build the query-string map from a {:navigate, params} payload — omitting defaults so a root, unsearched, first-page view yields a clean bare URL.

on_mount(arg1, params, session, socket)

parse_nav_params(params)

Parse a LiveView params map into the nav_params shape MediaBrowser's controlled mode expects (folder, q, page, filter_orphaned, view).