#!/usr/bin/env elixir
# Popover reference conformance fixture.
# Dogfoods the SHIPPED component (lib/.../components/popover.ex) and the SHIPPED hook
# (priv/static/lic_hooks.js) — the conformance suite tests the real artifacts, not a
# re-implementation.
# Run: elixir app.exs (http://127.0.0.1:4129)
Mix.install([
{:phoenix, "~> 1.8"},
{:phoenix_live_view, "~> 1.1"},
{:bandit, "~> 1.7"},
{:jason, "~> 1.4"}
])
Application.put_env(:phoenix, :json_library, Jason)
# Load the real shipped component. Compiling it extracts its colocated hook
# (the shipped client JS) into this fixture's own build path; ColocatedAssets.compile()
# then writes the index.js manifest — the same artifact-producing pipeline a consumer's
# `mix compile` runs. The fixture serves that output at /colocated and imports it as a
# real ES module, so the conformance suite tests the true shipped artifact under the
# exact LiveView version being swept (no cross-version reuse of repo _build output).
Code.require_file(Path.join(__DIR__, "../../lib/live_interaction_contracts/components/popover.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: 4129],
server: true,
adapter: Bandit.PhoenixAdapter,
live_view: [signing_salt: "popover-ref-salt"],
secret_key_base: String.duplicate("popover-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"""
Popover reference
<%= @inner_content %>
"""
end
end
defmodule PRWeb.MainLive do
use Phoenix.LiveView
import LiveInteractionContracts.Components.Popover
def mount(_p, _s, socket),
do: {:ok, assign(socket, content: 0, attr: 0, sib: 0, trig: 0, spacer: 40, observed: [])}
def render(assigns) do
~H"""
<.popover id="pop" role="menu" mode="auto" on_open_change="toggled" placement="bottom" data-rev={@attr}>
<:trigger>Open ({@trig})
<:content>
item {@content}
<%!-- 260px of room above so placement="top" genuinely fits (otherwise
flip-block correctly flips it below and the test would measure the
fallback, not the preset — WebKit's taller text rendering caught this) --%>
<.popover id="pop2" role="menu" mode="manual" placement="top">
<:trigger>top-anchored
<:content>