StarView.Component (star_view v0.7.0)

Copy Markdown View Source

Shared UI + its event handlers in one module — for drawers, pickers, and other components used across many pages.

defmodule MyAppWeb.DetailDrawer do
  use StarView.Component

  def drawer(assigns) do
    ~H"""
    <div id="detail-drawer">
      <input data-on:change={event("change_title:#{@item.id}")} />
    </div>
    """
  end

  def handle_event("change_title:" <> _id, _signals, %{method: "POST"} = conn) do
    # ... update, then patch (SSE is already started by the dispatcher)
    patch_signals(conn, %{saved: true})
  end
end

Pages embed the UI as plain function components and need no handle_event clauses for it — events route to this module through StarView.Dispatch. use StarView.Component marks the module dispatchable (the same marker as use StarView controllers), so the dispatch route is the allowlist. Wire it with StarView.Router:

star_view_components "/ds"

which defaults to POST. Declare extra unsafe :event_methods explicitly; read-only GET requires a get_events: [Module] allowlist. A plain post "/ds/:module/:event", StarView.Dispatch, [], alias: false route (the installer default) also works, but only for the default POST events.

Unlike StarView.Page, event/2 here targets the component's dispatch URL: <base>/<encoded-module>/<event>. The base defaults to /ds and is read client-side from <body data-ds-base="...">, so it must match the base you give star_view_components/1. Two common setups:

# Router: star_view_components "/ds"   (the default — no layout
# attribute needed)

# Custom base and/or app path prefix — declare it once in the root
# layout, including the dispatch segment:
#   Router: scope "/:workspace_slug" do star_view_components "/ds" end
<Layout.app conn={@conn}
  body_attrs={%{"data-ds-base" => workspace_path(@current_scope.workspace.slug) <> "/ds"}}>
  ...
</Layout.app>

Colocation only: no server-side component state, no lifecycle. State lives in signals, the DOM, and the database.

Pass checked_events: true to derive an event contract from the actual handler clauses and check literal local event/1,2 references in ~STAR. See StarView.Events.