#!/usr/bin/env elixir # Select reference conformance fixture. # Dogfoods the SHIPPED component (lib/.../components/select.ex) + its colocated hook — # the conformance suite tests the real artifacts, not a re-implementation. # Run: elixir app.exs (http://127.0.0.1:4134) Mix.install([ {:phoenix, "~> 1.8"}, {:phoenix_live_view, "~> 1.2"}, {:bandit, "~> 1.7"}, {:jason, "~> 1.4"} ]) Application.put_env(:phoenix, :json_library, Jason) # Compiling the shipped component extracts its colocated hook into this fixture's own # build path; ColocatedAssets.compile() writes the index.js manifest — the same # pipeline a consumer's `mix compile` runs. Served at /colocated, imported as a real # ES module, so the suite tests the true shipped artifact under the swept LV version. Code.require_file(Path.join(__DIR__, "../../lib/live_interaction_contracts/components/select.ex")) Phoenix.LiveView.ColocatedAssets.compile() colocated_dir = Path.join([Mix.Project.build_path(), "phoenix-colocated", to_string(Mix.Project.config()[:app] || "")]) Application.put_env(:pr, :colocated_dir, colocated_dir) Application.put_env(:pr, PRWeb.Endpoint, http: [ip: {127, 0, 0, 1}, port: 4134], server: true, adapter: Bandit.PhoenixAdapter, live_view: [signing_salt: "select-ref-salt"], secret_key_base: String.duplicate("select-reference-secret!!", 4), pubsub_server: PR.PubSub, check_origin: false, debug_errors: true ) defmodule PRWeb.Layout do use Phoenix.Component @phoenix_js File.read!(Application.app_dir(:phoenix, "priv/static/phoenix.min.js")) @lv_js File.read!(Application.app_dir(:phoenix_live_view, "priv/static/phoenix_live_view.min.js")) def render("root.html", assigns) do assigns = assign(assigns, phoenix_js: @phoenix_js, lv_js: @lv_js) ~H""" Select reference <%= @inner_content %> """ end end defmodule PRWeb.MainLive do use Phoenix.LiveView import LiveInteractionContracts.Components.Select @labels %{"alpha" => "Alpha", "beta" => "Beta", "gamma" => "Gamma"} def mount(_p, _s, socket) do {:ok, assign(socket, value: nil, gamma_rev: 0, attr_rev: 0, sib: 0, removed: MapSet.new(), change_count: 0, spacer: 40 )} end def render(assigns) do assigns = assign(assigns, options: build_options(assigns)) ~H"""
<.select id="sel" name="fruit" value={@value} on_value_change="change" placement="bottom" data-rev={@attr_rev}> <:trigger>{Map.get(%{"alpha" => "Alpha", "beta" => "Beta", "gamma" => "Gamma"}, @value, "Pick one")} <:item :for={o <- @options} id={o.id}>{o.label}
sib {@sib}
{@change_count}:{@value || "none"}
""" end defp build_options(assigns) do for id <- ~w(alpha beta gamma), id not in assigns.removed do label = if id == "gamma", do: "Gamma #{assigns.gamma_rev}", else: @labels[id] %{id: id, label: label} end end def handle_event("change", %{"id" => id}, s), do: {:noreply, assign(s, value: id, change_count: s.assigns.change_count + 1)} def handle_event("content", _, s), do: {:noreply, update(s, :gamma_rev, &(&1 + 1))} def handle_event("attr", _, s), do: {:noreply, update(s, :attr_rev, &(&1 + 1))} def handle_event("sib", _, s), do: {:noreply, update(s, :sib, &(&1 + 1))} def handle_event("remove_beta", _, s), do: {:noreply, assign(s, removed: MapSet.put(s.assigns.removed, "beta"))} def handle_event("move", _, s), do: {:noreply, assign(s, spacer: s.assigns.spacer + 150)} # deep enough that the ~54px listbox cannot fit below on any engine's font metrics def handle_event("bottom", _, s), do: {:noreply, assign(s, spacer: 660)} def handle_event("reset", _, s), do: {:noreply, assign(s, spacer: 40)} end defmodule PRWeb.Router do use Phoenix.Router import Phoenix.LiveView.Router pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :protect_from_forgery plug :put_root_layout, html: {PRWeb.Layout, :root} end scope "/" do pipe_through :browser live "/", PRWeb.MainLive end end defmodule PRWeb.Endpoint do use Phoenix.Endpoint, otp_app: :pr @session_options [store: :cookie, key: "_pr_key", signing_salt: "selectref", same_site: "Lax"] socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] plug Plug.Static, at: "/colocated", from: Application.compile_env!(:pr, :colocated_dir), gzip: false plug Plug.Session, @session_options plug PRWeb.Router end {:ok, _} = Supervisor.start_link([{Phoenix.PubSub, name: PR.PubSub}, PRWeb.Endpoint], strategy: :one_for_one) IO.puts("VERSIONS phoenix=#{Application.spec(:phoenix, :vsn)} live_view=#{Application.spec(:phoenix_live_view, :vsn)} elixir=#{System.version()} otp=#{System.otp_release()}") IO.puts("READY http://127.0.0.1:4134") Process.sleep(:infinity)