Current section
Files
Jump to
Current section
Files
lib/live_debugger/app/web/live_components/live_dropdown.ex
defmodule LiveDebugger.App.Web.LiveComponents.LiveDropdown do
@moduledoc """
Dropdown LiveComponent that can be used to display a dropdown menu
"""
use LiveDebugger.App.Web, :live_component
@doc """
Closes the dropdown. You can use it when you want to close the dropdown from other component.
"""
def close(id) do
send_update(__MODULE__, id: id, action: :close)
end
@impl true
def update(%{action: :close}, socket) do
{:ok, assign(socket, :open, false)}
end
@impl true
def update(assigns, %{assigns: %{mounted?: true}} = socket) do
socket
|> assign(:id, assigns.id)
|> assign(:class, assigns[:class] || "")
|> assign(:button, assigns.button)
|> assign(:inner_block, assigns.inner_block)
|> assign(:direction, assigns[:direction] || :bottom_right)
|> ok()
end
@impl true
def update(assigns, socket) do
socket
|> assign(:id, assigns.id)
|> assign(:class, assigns[:class] || "")
|> assign(:button, assigns.button)
|> assign(:inner_block, assigns.inner_block)
|> assign(:open, assigns[:open] || false)
|> assign(:direction, assigns[:direction] || :bottom_right)
|> assign(:mounted?, true)
|> ok()
end
attr(:id, :string, required: true)
attr(:open, :boolean, required: true, doc: "Whether the dropdown is open")
attr(:class, :string, default: "", doc: "Additional classes to add to the dropdown container")
attr(:direction, :atom,
default: :bottom_right,
doc: "Direction of the dropdown: :bottom_left or :bottom_right"
)
slot(:button, required: true)
slot(:inner_block, required: true)
@impl true
def render(assigns) do
~H"""
<div id={@id <> "-live-dropdown-container"} class={["relative", @class]} phx-hook="LiveDropdown">
<div id={@id <> "-button"} phx-click={if !@open, do: "open"} phx-target={@myself}>
<%= render_slot(@button, @open) %>
</div>
<div
:if={@open}
id={@id <> "-content"}
class={[
"absolute bg-surface-0-bg rounded border border-default-border mt-1 z-50",
dropdown_position_class(@direction)
]}
>
<%= render_slot(@inner_block) %>
</div>
</div>
"""
end
@impl true
def handle_event("open", _, socket) do
{:noreply, assign(socket, :open, true)}
end
@impl true
def handle_event("close", _, socket) do
{:noreply, assign(socket, :open, false)}
end
defp dropdown_position_class(:bottom_left), do: "right-0"
defp dropdown_position_class(:bottom_right), do: "left-0"
defp dropdown_position_class(_), do: "left-0"
end