81 lines
3.4 KiB
Elixir
81 lines
3.4 KiB
Elixir
defmodule ZoeyscomputerWeb.SearchableDropdown do
|
|
use Phoenix.Component
|
|
alias Phoenix.LiveView.JS
|
|
|
|
attr :id, :string, required: true
|
|
attr :options, :list, required: true
|
|
attr :selected, :string, default: nil
|
|
attr :class, :string, default: nil
|
|
attr :name, :string, required: true
|
|
attr :form, :any, required: true
|
|
|
|
def searchable_dropdown(assigns) do
|
|
~H"""
|
|
<div class={["relative w-full", @class]} id={"#{@id}-container"}>
|
|
<div class="relative" phx-click-away={JS.hide(to: "##{@id}-dropdown", transition: "fade-out")}>
|
|
<input type="hidden" name={@name} value={@selected} id={"#{@id}-input"} />
|
|
<button
|
|
type="button"
|
|
class="flex w-full items-center justify-between rounded-md border border-ctp-surface0 bg-ctp-base px-3 py-2 text-sm text-ctp-text shadow-sm hover:bg-ctp-surface0 focus:outline-none focus:ring-2 focus:ring-ctp-lavender transition-colors duration-200"
|
|
phx-click={
|
|
JS.toggle(to: "##{@id}-dropdown", in: "fade-in", out: "fade-out")
|
|
|> JS.focus(to: "##{@id}-search")
|
|
}
|
|
aria-haspopup="listbox"
|
|
aria-expanded="false"
|
|
>
|
|
<span class="block truncate">
|
|
<%= @selected || "Select an option..." %>
|
|
</span>
|
|
<svg
|
|
class="h-5 w-5 text-ctp-overlay0 transform transition-transform duration-200"
|
|
class={"#{if @selected, do: "rotate-180", else: ""}"}
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
>
|
|
<path
|
|
fill-rule="evenodd"
|
|
d="M10 3a.75.75 0 01.55.24l3.25 3.5a.75.75 0 11-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 01-1.1-1.02l3.25-3.5A.75.75 0 0110 3z"
|
|
clip-rule="evenodd"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
<div
|
|
id={"#{@id}-dropdown"}
|
|
class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md border border-ctp-surface0 bg-ctp-base shadow-lg hidden transition-all duration-200 ease-in-out"
|
|
phx-hook="DropdownAnimation"
|
|
>
|
|
<div class="p-2">
|
|
<input
|
|
type="text"
|
|
id={"#{@id}-search"}
|
|
placeholder="Search..."
|
|
class="w-full rounded-md border border-ctp-surface0 bg-ctp-mantle px-3 py-2 text-sm text-ctp-text placeholder-ctp-overlay0 focus:outline-none focus:ring-2 focus:ring-ctp-lavender transition-colors duration-200"
|
|
phx-hook="SearchableDropdown"
|
|
data-dropdown-id={@id}
|
|
data-form-id={@form.id}
|
|
/>
|
|
</div>
|
|
<ul class="max-h-48 overflow-y-auto py-1" role="listbox" id={"#{@id}-options"}>
|
|
<li :for={option <- @options} class="transition-colors duration-150 ease-in-out">
|
|
<button
|
|
type="button"
|
|
class="w-full px-3 py-2 text-left text-sm hover:bg-ctp-surface0 focus:bg-ctp-surface0 focus:outline-none cursor-pointer transition-colors duration-150 ease-in-out"
|
|
phx-click={
|
|
JS.push("select_language", value: %{language: option}, target: "##{@form.id}")
|
|
|> JS.hide(to: "##{@id}-dropdown", transition: "fade-out")
|
|
}
|
|
phx-target={"##{@form.id}"}
|
|
role="option"
|
|
data-option={option}
|
|
>
|
|
<%= option %>
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
"""
|
|
end
|
|
end
|