feat: adds field visibility dropdown live component
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
carla 2025-12-02 15:00:09 +01:00
parent 45a9bc0cc0
commit 0fb43a0816
6 changed files with 981 additions and 33 deletions

View file

@ -111,6 +111,126 @@ defmodule MvWeb.CoreComponents do
end
end
@doc """
Renders a dropdown menu.
## Examples
<.dropdown_menu items={@items} open={@open} phx-target={@myself} />
"""
attr :id, :string, default: "dropdown-menu"
attr :items, :list, required: true, doc: "List of %{label: string, value: any} maps"
attr :button_label, :string, default: "Dropdown"
attr :icon, :string, default: nil
attr :checkboxes, :boolean, default: false
attr :selected, :map, default: %{}
attr :open, :boolean, default: false, doc: "Whether the dropdown is open"
attr :show_select_buttons, :boolean, default: false, doc: "Show select all/none buttons"
attr :phx_target, :any, default: nil
def dropdown_menu(assigns) do
unless Map.has_key?(assigns, :phx_target) do
raise ArgumentError, ":phx_target is required in dropdown_menu/1"
end
assigns =
assign_new(assigns, :items, fn -> [] end)
|> assign_new(:button_label, fn -> "Dropdown" end)
|> assign_new(:icon, fn -> nil end)
|> assign_new(:checkboxes, fn -> false end)
|> assign_new(:selected, fn -> %{} end)
|> assign_new(:open, fn -> false end)
|> assign_new(:show_select_buttons, fn -> false end)
|> assign(:phx_target, assigns.phx_target)
|> assign_new(:id, fn -> "dropdown-menu" end)
~H"""
<div class="relative" phx-click-away="close_dropdown" phx-target={@phx_target}>
<button
type="button"
tabindex="0"
role="button"
aria-haspopup="menu"
aria-expanded={@open}
aria-controls={@id}
class="btn btn-ghost"
phx-click="toggle_dropdown"
phx-target={@phx_target}
>
<%= if @icon do %><.icon name={@icon} /><% end %>
<span><%= @button_label %></span>
</button>
<ul
:if={@open}
id={@id}
role="menu"
class="absolute right-0 mt-2 bg-base-100 z-[100] p-2 shadow-lg rounded-box w-64 max-h-96 overflow-y-auto border border-base-300"
tabindex="0"
phx-window-keydown="close_dropdown"
phx-key="Escape"
phx-target={@phx_target}
>
<li :if={@show_select_buttons} role="none">
<div class="flex justify-between items-center mb-2 px-2">
<span class="font-semibold">{gettext("Options")}</span>
<div class="flex gap-1">
<button
type="button"
role="menuitem"
aria-label={gettext("Select all")}
phx-click="select_all"
phx-target={@phx_target}
class="btn btn-xs btn-ghost"
>
{gettext("All")}
</button>
<button
type="button"
role="menuitem"
aria-label={gettext("Select none")}
phx-click="select_none"
phx-target={@phx_target}
class="btn btn-xs btn-ghost"
>
{gettext("None")}
</button>
</div>
</div>
</li>
<li :if={@show_select_buttons} role="separator" class="divider my-1"></li>
<%= for item <- @items do %>
<li role="none">
<label
role={if @checkboxes, do: "menuitemcheckbox", else: "menuitem"}
aria-checked={@checkboxes && Map.get(@selected, item.value, true)}
tabindex="0"
class="flex items-center gap-2 px-2 py-1 rounded cursor-pointer hover:bg-base-200"
phx-click="select_item"
phx-value-item={item.value}
phx-target={@phx_target}
>
<%= if @checkboxes do %>
<input
type="checkbox"
class="checkbox checkbox-sm"
checked={Map.get(@selected, item.value, true)}
tabindex="-1"
aria-hidden="true"
readonly
/>
<% end %>
<span><%= item.label %></span>
</label>
</li>
<% end %>
</ul>
</div>
"""
end
@doc """
Renders an input with label and error messages.