defmodule SigmaKit.Components.Modal do
use Phoenix.LiveComponent
alias Phoenix.LiveView.JS
import SigmaKit.Components.Js, only: [show: 2, hide: 2]
import SigmaKit.Components.Buttons, only: [button: 1]
@doc """
Renders a modal.
## Examples
<.modal id="confirm-modal">
This is a modal.
JS commands may be passed to the `:on_cancel` to configure
the closing/cancel event, for example:
<.modal id="confirm" on_cancel={JS.navigate(~p"/posts")}>
This is another modal.
"""
attr :id, :string, required: true
attr :show, :boolean, default: false
attr :title, :string, default: nil
attr :on_cancel, JS, default: %JS{}
attr :form, :any, default: nil
attr :as, :any, default: nil
attr :noclose, :boolean, default: false
attr :submit, :string, default: "submit"
attr :change, :string, default: "validate"
attr :submit_text, :string, default: "Submit"
attr :target, :any, default: nil
attr :wide, :boolean, default: true
attr :error, :string, default: nil
slot :inner_block, required: true
slot :description
slot :actions
def modal(assigns) do
~H"""
<.focus_wrap
id={"#{@id}-container"}
phx-window-keydown={!@noclose && JS.exec("data-cancel", to: "##{@id}")}
phx-key="escape"
phx-click-away={!@noclose && JS.exec("data-cancel", to: "##{@id}")}
class="ring-zinc-700/10 relative hidden={!@show} rounded-2xl bg-black shadow-lg ring-1 transition overflow-hidden"
>
{@title}
{render_slot(@description)}
{@error}
{render_slot(@inner_block)}
{render_slot(@actions)}
<.form
:let={f}
id={"#{@id}-form"}
as={@as}
for={@form}
phx-submit={@submit}
phx-change={@change}
phx-target={@target}
>
{render_slot(@inner_block, f)}
{render_slot(@actions)}
<.button type="button" phx-click={JS.exec("data-cancel", to: "##{@id}")}>
Cancel
<.button primary>
{@submit_text}
"""
end
def show_modal(js \\ %JS{}, id) when is_binary(id) do
js
|> JS.show(to: "##{id}")
|> JS.show(
to: "##{id}-bg",
time: 300,
transition: {"transition-all transform ease-out duration-300", "opacity-0", "opacity-100"}
)
|> show("##{id}-container")
|> JS.add_class("overflow-hidden", to: "body")
|> JS.focus_first(to: "##{id}-content")
end
def hide_modal(js \\ %JS{}, id) do
js
|> JS.hide(
to: "##{id}-bg",
transition: {"transition-all transform ease-in duration-200", "opacity-100", "opacity-0"}
)
|> hide("##{id}-container")
|> JS.hide(to: "##{id}", transition: {"block", "block", "hidden"})
|> JS.remove_class("overflow-hidden", to: "body")
|> JS.pop_focus()
end
end