Dstar.Component (dstar v0.1.0-alpha.2)

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 Dstar.Component

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

  def handle_event(conn, "change_title:" <> id, signals) do
    # ... update, then patch
    conn |> start() |> patch_signals(%{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 via Dstar.Plugs.Dispatch (wire it with Dstar.Router.dstar_components/2).

Unlike Dstar.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 dstar_components/2. Two common setups:

# Router: dstar_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 dstar_components "/ds", [...] end
<body data-ds-base={workspace_path(@current_scope.workspace.slug) <> "/ds"}>

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