defmodule Moon.Design.Dropdown.BottomOptions do
@moduledoc "Options list for the Dropdown component"
# TODO: add panel position options, currently only bottom
use Moon.StatelessComponent
import Moon.Helpers.MakeList
@doc "Value of the selected option(s)"
prop(value, :any, from_context: :value)
@doc "On option click event, in most cases got from context"
prop(on_change, :event, from_context: :on_change)
@doc "Click event, in most cases got from context"
prop(on_close, :event, from_context: :close_me)
@doc "If the optionlist is open, got from context"
prop(is_open, :boolean, from_context: :is_open)
@doc "Size of the options"
prop(size, :string, values!: ~w(sm md lg), default: "md")
@doc "Additional CSS classes for the div"
prop(class, :css_class)
@doc "Additional values to be passed"
prop(values, :map, from_context: :values)
@doc "List of the options. Used when no "
prop(titles, :list, default: [])
prop(option_module, :atom, default: Moon.Design.Dropdown.Option)
@doc "Data-testid attribute for div"
prop(testid, :string)
@doc "Id attribute for div"
prop(id, :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), from_context: :as_dropdown_on)
slot(option)
slot(default)
def render(assigns) do
~F"""
<div
class={merge([
"fixed inset-x-0 w-full z-[99999] bottom-0 rounded-t-xl shadow-moon-lg box-border bg-goku shadow-moon-lg focus:outline-none overflow-hidden",
dropdown_classes(@as_dropdown_on),
@class,
@is_open && "translate-y-0",
!@is_open && "translate-y-full",
"transition-transform duration-300 ease-in-out transform",
"flex flex-col absolute z-[99] p-1 my-2 w-full top-full rounded-moon-s-md bottom-auto":
!@as_dropdown_on
])}
{=@id}
data-testid={@testid}
:on-click-away={@on_close}
role="listbox"
>
{#if slot_assigned?(:option)}
{#for {option, index} <- Enum.with_index(make_list(@option))}
<#slot
{option}
context_put={
is_selected: Enum.member?(make_list(@value), option.value || "#{index}"),
size: @size,
on_click: @on_change,
value: index,
values: @values
}
/>
{/for}
{#else}
<.moon
:for={title <- @titles}
module={@option_module}
is_selected={Enum.member?(make_list(@value), title)}
{=@size}
on_click={@on_change}
value={title}
values={@values}
>{title |> to_string()}</.moon>
{/if}
<#slot />
</div>
"""
end
defp dropdown_classes(nil), do: []
defp dropdown_classes(size) do
~w(absolute z-[99] bottom-auto rounded-moon-s-md my-2 shadow-moon-lg box-border top-full)
|> Enum.map(&"#{size}:#{&1}")
end
end