defmodule Phoenix.UI.Components.Drawer do
@moduledoc """
Provides drawer component.
"""
import Phoenix.UI.Components.{Backdrop, Paper}
use Phoenix.UI, :component
attr(:anchor, :string, default: "left", values: ["bottom", "left", "right", "top"])
attr(:extend_class, :string)
attr(:id, :string, required: true)
attr(:open, :boolean, default: false)
attr(:rest, :global)
attr(:square, :boolean, default: true)
attr(:variant, :string, default: "temporary", values: ["temporary"])
@doc """
Renders drawer component.
## Examples
```
<.drawer id="basic_drawer">
content
</.drawer>
```
"""
@spec drawer(Socket.assigns()) :: Rendered.t()
def drawer(assigns) do
extend_class = build_class(~w(
fixed overflow-hidden z-50 invisible open:visible
transition-all ease-in-out duration-300
#{classes(:anchor, assigns)}
#{classes(:open, assigns)}
#{Map.get(assigns, :extend_class)}
))
assigns = assign(assigns, :extend_class, extend_class)
~H"""
<.backdrop id={"#{@id}_drawer_backdrop"} open={@open} phx-click={hide_drawer("##{@id}")}>
</.backdrop>
<.paper
extend_class={@extend_class}
id={@id}
open={@open}
phx-click-away={hide_drawer("##{@id}")}
phx-key="escape"
phx-window-keydown={hide_drawer("##{@id}")}
square={@square}
variant="elevated"
{@rest}
>
<%= render_slot(@inner_block) %>
</.paper>
"""
end
### JS Interactions ##########################
@doc """
Hides drawer matching selector.
## Examples
iex> hide_drawer(selector)
%JS{}
iex> hide_drawer(js, selector)
%JS{}
"""
@spec hide_drawer(String.t()) :: struct()
def hide_drawer(selector), do: hide_drawer(%JS{}, selector)
@spec hide_drawer(struct(), String.t()) :: struct()
def hide_drawer(%JS{} = js, selector) do
js
|> JS.remove_attribute("open", to: selector)
|> hide_backdrop("#{selector}_drawer_backdrop")
end
@doc """
Shows drawer matching selector.
## Examples
iex> show_drawer(selector)
%JS{}
iex> show_drawer(js, selector)
%JS{}
"""
@spec show_drawer(String.t()) :: struct()
def show_drawer(selector), do: show_drawer(%JS{}, selector)
@spec show_drawer(struct(), String.t()) :: struct()
def show_drawer(%JS{} = js, selector) do
js
|> JS.set_attribute({"open", "true"}, to: selector)
|> show_backdrop("#{selector}_drawer_backdrop")
end
### CSS Classes ##########################
# Anchor
defp classes(:anchor, %{anchor: "bottom"}), do: "bottom-0 left-0 right-0"
defp classes(:anchor, %{anchor: "left"}), do: "bottom-0 left-0 top-0"
defp classes(:anchor, %{anchor: "right"}), do: "bottom-0 right-0 top-0"
defp classes(:anchor, %{anchor: "top"}), do: "left-0 right-0 top-0"
# Open
defp classes(:open, %{anchor: "bottom"}), do: "max-h-0 open:max-h-full"
defp classes(:open, %{anchor: "left"}), do: "max-w-0 open:max-w-full"
defp classes(:open, %{anchor: "right"}), do: "max-w-0 open:max-w-full"
defp classes(:open, %{anchor: "top"}), do: "max-h-0 open:max-h-full"
defp classes(_rule_group, _assigns), do: nil
end