defmodule LiveViewContinuity.Dialog do @moduledoc """ A native modal dialog with server-owned intent and patch-safe browser state. See `DIALOG.md` for the observable interaction contract. """ use Phoenix.Component alias Phoenix.LiveView.JS attr(:id, :string, required: true) attr(:open, :boolean, required: true) attr(:on_open, :string, required: true) attr(:on_close, :string, required: true) attr(:initial_focus, :string, default: nil) attr(:class, :any, default: nil) attr(:dialog_class, :any, default: nil) attr(:rest, :global) slot :trigger, required: true do attr(:class, :any) end slot :title, required: true do attr(:class, :any) end slot :description do attr(:class, :any) end slot(:inner_block, required: true) slot :close, required: true do attr(:class, :any) end def dialog(assigns) do validate_id!(assigns.id) assigns = assign_entries!(assigns) ~H"""
"-popup"} class={@dialog_class} aria-labelledby={@id <> "-title"} aria-describedby={if @description_entry, do: @id <> "-description"} data-lvc-dialog-popup phx-mounted={JS.ignore_attributes("open")} >

"-title"} class={@title_entry[:class]}>{render_slot(@title_entry)}

"-description"} class={@description_entry[:class]}> {render_slot(@description_entry)}

{render_slot(@inner_block)}
""" end defp assign_entries!(assigns) do trigger = one!(assigns.trigger, "trigger", true) title = one!(assigns.title, "title", true) description = one!(assigns.description, "description", false) close = one!(assigns.close, "close", true) one!(assigns.inner_block, "body", true) assigns |> assign(:trigger_entry, trigger) |> assign(:title_entry, title) |> assign(:description_entry, description) |> assign(:close_entry, close) end defp one!([entry], _name, _required), do: entry defp one!([], _name, false), do: nil defp one!(entries, name, _), do: raise(ArgumentError, "dialog requires exactly one #{name} slot, got: #{length(entries)}") defp validate_id!(id) do if id == "" or String.contains?(id, <<0>>) or Regex.match?(~r/[\t\n\f\r ]/, id), do: raise( ArgumentError, "dialog id must be a non-empty string without ASCII whitespace or NUL" ) end end