lib/phoenix/ui/components/backdrop.ex

defmodule Phoenix.UI.Components.Backdrop do
  @moduledoc """
  Provides Backdrop component.
  """
  use Phoenix.UI, :component

  attr(:element, :string, default: "div")
  attr(:extend_class, :string)
  attr(:invisible, :boolean, default: false)
  attr(:rest, :global, include: ~w(open))
  attr(:transition_duration, :integer, default: 300)

  slot(:inner_block)

  @doc """
  Renders backdrop component.

  ## Examples

      ```
      <.backdrop/>
      ```

  """
  @spec backdrop(Socket.assigns()) :: Rendered.t()
  def backdrop(assigns) do
    assigns = assign_class(assigns, ~w(
        backdrop fixed inset-0 z-50 invisible opacity-0
        open:visible open:opacity-100 transition-all ease-in-out
        #{classes(:color, assigns)}
        #{classes(:transition, assigns)}
      ))

    ~H"""
    <.dynamic_tag class={@class} name={@element} {@rest}>
      <%= render_slot(@inner_block) %>
    </.dynamic_tag>
    """
  end

  ### JS Interactions ##########################

  @doc """
  Hides backdrop by selector.

  ## Examples

      iex> hide_backdrop(selector)
      %JS{}

      iex> hide_backdrop(js, selector)
      %JS{}

  """
  @spec hide_backdrop(String.t()) :: struct()
  def hide_backdrop(selector), do: hide_backdrop(%JS{}, selector)

  @spec hide_backdrop(struct(), String.t()) :: struct()
  def hide_backdrop(%JS{} = js, selector) do
    JS.remove_attribute(js, "open", to: selector)
  end

  @doc """
  Shows backdrop by selector.

  ## Examples

      iex> show_backdrop(selector)
      %JS{}

      iex> show_backdrop(js, selector)
      %JS{}

  """
  @spec show_backdrop(String.t()) :: struct()
  def show_backdrop(selector), do: show_backdrop(%JS{}, selector)

  @spec show_backdrop(struct(), String.t()) :: struct()
  def show_backdrop(%JS{} = js, selector) do
    JS.set_attribute(js, {"open", "true"}, to: selector)
  end

  ### CSS Classes ##########################

  # Color
  defp classes(:color, %{invisible: false}), do: "bg-slate-900/70 backdrop-blur-sm"

  # Transition
  defp classes(:transition, %{transition_duration: duration}), do: "duration-#{duration}"

  defp classes(_rule_group, _assigns), do: nil
end