defmodule <%= @module_name %>.Components.UI.Dialog do
@moduledoc """
Accessible Dialog (Modal) component following the WAI-ARIA Dialog pattern.
Uses `Phoenix.LiveView.JS` for open/close and the `PhiaDialog` JavaScript Hook
for focus trap, keyboard navigation, and scroll locking.
## Registration in app.js
import PhiaDialog from "./phia_hooks/dialog.js"
let liveSocket = new LiveSocket("/live", Socket, {
hooks: { PhiaDialog, ...yourOtherHooks }
})
## Example
<.dialog id="confirm-delete">
<.dialog_trigger for="confirm-delete">
<.button variant={:destructive}>Delete
<.dialog_content id="confirm-delete">
<.dialog_header>
<.dialog_title id="confirm-delete-title">Delete Item
<.dialog_description id="confirm-delete-description">
This action cannot be undone.
<.dialog_footer>
<.dialog_close for="confirm-delete">Cancel
"""
use Phoenix.Component
import <%= @module_name %>.ClassMerger, only: [cn: 1]
alias Phoenix.LiveView.JS
attr :id, :string, required: true, doc: "Unique ID used as the hook anchor"
attr :class, :string, default: nil
slot :inner_block, required: true
def dialog(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
attr :for, :string, required: true, doc: "ID of the dialog to open"
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def dialog_trigger(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
attr :id, :string, required: true, doc: "ID matching the parent dialog/1's :id"
attr :class, :string, default: nil
slot :inner_block, required: true
def dialog_content(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def dialog_header(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
attr :id, :string, default: nil
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def dialog_title(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
attr :id, :string, default: nil
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def dialog_description(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def dialog_footer(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
attr :for, :string, required: true, doc: "ID of the dialog to close"
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def dialog_close(assigns) do
~H"""
<%%= render_slot(@inner_block) %>
"""
end
end