|
| 1 | +defmodule PrimaWeb.DemoLive.AsyncComboboxDemo do |
| 2 | + @moduledoc false |
| 3 | + use PrimaWeb, :live_component |
| 4 | + import Prima.Combobox |
| 5 | + |
| 6 | + @options [ |
| 7 | + "Cherry", |
| 8 | + "Kiwi", |
| 9 | + "Grapefruit", |
| 10 | + "Orange", |
| 11 | + "Banana" |
| 12 | + ] |
| 13 | + |
| 14 | + @impl true |
| 15 | + def mount(socket) do |
| 16 | + socket = |
| 17 | + socket |
| 18 | + |> stream_configure(:suggestions, dom_id: &"suggestions-#{&1}") |
| 19 | + |> stream(:suggestions, []) |
| 20 | + |
| 21 | + {:ok, socket} |
| 22 | + end |
| 23 | + |
| 24 | + @impl true |
| 25 | + def render(assigns) do |
| 26 | + ~H""" |
| 27 | + <form phx-submit="save"> |
| 28 | + <.combobox class="relative w-64" id="demo-async-combobox"> |
| 29 | + <div class="relative mt-2 rounded-md shadow-sm"> |
| 30 | + <.combobox_input |
| 31 | + name="user[favourite_fruit]" |
| 32 | + class="block w-full rounded-md border-0 py-1.5 pr-10 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 cursor-default placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6 peer" |
| 33 | + phx-change="async_combobox_search" |
| 34 | + phx-target={@myself} |
| 35 | + placeholder="Type to search..." |
| 36 | + /> |
| 37 | + <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3 invisible peer-[.phx-change-loading]:visible"> |
| 38 | + <svg |
| 39 | + class="animate-spin -ml-1 h-5 w-5 text-gray-500" |
| 40 | + xmlns="http://www.w3.org/2000/svg" |
| 41 | + fill="none" |
| 42 | + viewBox="0 0 24 24" |
| 43 | + > |
| 44 | + <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"> |
| 45 | + </circle> |
| 46 | + <path |
| 47 | + class="opacity-75" |
| 48 | + fill="currentColor" |
| 49 | + d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" |
| 50 | + > |
| 51 | + </path> |
| 52 | + </svg> |
| 53 | + </div> |
| 54 | + </div> |
| 55 | +
|
| 56 | + <.combobox_options |
| 57 | + class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm" |
| 58 | + phx-update="stream" |
| 59 | + id="demo-async-combobox-options" |
| 60 | + > |
| 61 | + <%= for {id, option} <- @streams.suggestions do %> |
| 62 | + <.combobox_option |
| 63 | + id={id} |
| 64 | + value={option} |
| 65 | + class="relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 data-focus:bg-indigo-600 data-focus:text-white" |
| 66 | + > |
| 67 | + {option} |
| 68 | + </.combobox_option> |
| 69 | + <% end %> |
| 70 | + </.combobox_options> |
| 71 | + </.combobox> |
| 72 | + </form> |
| 73 | + """ |
| 74 | + end |
| 75 | + |
| 76 | + @impl true |
| 77 | + def handle_event("async_combobox_search", params, socket) do |
| 78 | + input = get_in(params, params["_target"]) |
| 79 | + |
| 80 | + suggestions = |
| 81 | + Enum.filter(@options, fn option -> |
| 82 | + String.contains?(String.downcase(option), String.downcase(input)) |
| 83 | + end) |
| 84 | + |
| 85 | + {:noreply, stream(socket, :suggestions, suggestions, reset: true)} |
| 86 | + end |
| 87 | +end |
0 commit comments