defmodule Moon.Design.Dropdown do
@moduledoc "Component for rendering dropdown info, mostly lists"
# TODO: Add bottom sheet and backdrop animations
use Moon.StatefulComponent
@doc "Value(s) of the options to be marked as selected"
prop(value, :any)
@doc "Event fired when trigger is clicked"
prop(on_trigger, :event)
@doc "Event fired to close Dropdown.BottomOptions"
prop(on_close, :event)
@doc "Put true here if you want dropdown to be shown by default"
prop(is_open, :boolean)
@doc "Addictional classes to be added to a dropdown"
prop(class, :css_class)
@doc "Data-testid attribute for HTML tag"
prop(testid, :string)
@doc "Dropdown autoclose on click away"
prop(autoclose, :boolean, default: true)
@doc "Disabled state for the dropdown"
prop(disabled, :boolean)
@doc "Attribute phx-hook. Used for dependant components"
prop(hook, :string)
@doc """
Experimental: makes BottomSheet behave as Modal on some screen widths,
please reffer to https://tailwindcss.com/docs/screens
"""
prop(as_dropdown_on, :string, values: ~w(sm md lg xl 2xl))
@doc "Additional values to be passed"
prop(side_values, :map, default: %{})
@doc "Event fired when option is selected"
prop(on_change, :event)
@doc "Slot for triggering the open/closing state"
slot(trigger, required: true)
@doc "Content to be showable"
slot(default)
@doc "Backdrop of Dropdown as BottomSheet on small screens, see Dropdown.Backdrop"
slot(backdrop)
def handle_event("on_change_default", %{"value" => value}, socket) do
{:noreply, assign(socket, value: value, is_open: false)}
end
def handle_event("on_trigger_default", _, socket) do
{:noreply, assign(socket, is_open: !socket.assigns.is_open)}
end
def handle_event("close_me", _, socket) do
{:noreply, assign(socket, is_open: false)}
end
def handle_event("open_me", _, socket) do
{:noreply, assign(socket, is_open: true)}
end
def close(dropdown_id) do
send_update_after(__MODULE__, [id: dropdown_id, is_open: false], 100)
end
def render(assigns) do
~F"""
<div
class={merge(["relative", get_config(:default_class), @class])}
:on-click-away={(@autoclose && "close_me") || nil}
{=@id}
data-testid={@testid}
phx-hook={@hook}
>
<#slot
{
@trigger,
value: @value,
is_open: @is_open,
disabled: @disabled,
on_trigger: @on_trigger || %{name: "on_trigger_default", target: @myself}
}
context_put={
is_open: @is_open,
disabled: @disabled,
on_trigger: @on_trigger || %{name: "on_trigger_default", target: @myself},
open_me: %{name: "open_me", target: @myself},
close_me: %{name: "close_me", target: @myself}
}
/>
<#slot
{@backdrop}
context_put={
is_open: @is_open,
as_dropdown_on: @as_dropdown_on
}
/>
<#slot context_put={
values: @side_values,
on_change: @on_change || %{name: "on_change_default", target: @myself},
close_me: @on_close || %{name: "close_me", target: @myself},
is_open: @is_open,
value: @value,
as_dropdown_on: @as_dropdown_on
} />
</div>
"""
end
end