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
endThen in the template:
<.live_component
module={PhoenixKitWeb.Components.MediaBrowser}
id="media-browser"
parent_uploads={@uploads}
/>URL sync (shareable folder links)
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— callsMediaBrowser.setup_uploads/1so@uploads.media_filesis available on every mount of this LiveView. Withurl_sync, also assigns:initial_paramsparsed from the mount params.- Fallback
handle_event("validate", _, socket)— absorbs the upload channel'sphx-changeevents. User-defined clauses with other event names still win because they are defined first. - With
url_sync: a:handle_paramshook (feeds URL params to the component + captures the live path) and a:handle_infohook that intercepts{MediaBrowser, id, {:navigate, _}}andpush_patches, both attached inon_mountso they compose with the host's own handlers. - Fallback
handle_info({MediaBrowser, _, _}, socket)— forwards toMediaBrowser.handle_parent_info/2for component registration and upload piping. - Fallback
handle_info({:leaf_changed, _}, socket)— routes Leaf editor content updates from the sidebar comments (when PhoenixKitComments is installed) toPhoenixKitComments.Web.CommentsComponent.forward_leaf_event/2. Without this, comment Leaf editors render but the typed content never reaches the server. The clause only injects whenPhoenixKitComments.Web.CommentsComponentis loaded — otherwise it's compiled away. User-defined:leaf_changedclauses (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).