Search Select Functionality Implementation as a LiveComponent

Hello Fellas

So I was building as the title implies a search Select functionality for a project of mine and since I was utilizing the functionality in many places I tried to create a re-usable component.
Specs

  1. Should be able to provide a search select functionality and be able to work with on Forms
  2. Should be able to search both in memory as well as a database

my train of thought made my implement it as Phoenix.LiveComponent

defmodule MehungryWeb.SelectComponent do
  @moduledoc """
  A module to facilitate Select item widget of forms this module is tightly couppled with the Hooks.SelectComponent in the JS side of things 
  
  expects 
  items: %{id: String, name: String}
  form: Form(The form that the widget is going to work on)
  input_variable: Atom, and an input variable which is the Field of the Form that this widget is going to operate  
  """
  use MehungryWeb, :live_component

  @impl true
  def update(assigns, socket) do

    label_function =
      case Map.get(assigns, :label_function) do
        nil ->
          fn x -> x.name end

        label_f ->
          label_f
      end


    selected_items =
      MehungryWeb.SelectComponentUtils.get_selected_items(
        assigns.form.params,
        assigns.input_variable,
        label_function,
        assigns
      )
  
    selected_items = Enum.filter(selected_items, fn x -> not is_nil(x) end)
      
    items = Enum.map(assigns.items, fn x -> %{name: label_function.(x), id: x.id} end)
    presenting_items = Enum.slice(items, 0..10)
    socket =
      socket
      |> assign(:items, items)
      |> assign(:presenting_items, presenting_items)
      |> assign(:listing_open, Map.get(assigns, :initial_open, false))
      |> assign(:selected_items, selected_items)
      |> assign(:form, assigns.form)
      |> assign(:input_variable, assigns.input_variable)

    {:ok, socket}
  end

  def handle_event("handle-item-click", %{"id" => id}, socket) do
    selected_item = Enum.find(socket.assigns.items, fn x -> x.id == id end)
    selected_items = socket.assigns.selected_items ++ [selected_item]

    socket =
      socket
      |> assign(:listing_open, false)
      |> assign(:selected_items, selected_items)

    items = Enum.map(selected_items, fn x -> x.id end)
    # Pushes the message that the SelectComponent Hook is waiting for int he JS side
    {:noreply,
     push_event(
       socket,
       "selected_id" <> socket.assigns.input_variable,
       %{id: items}
     )}
  end

 def handle_event("handle-selected-item-click", %{"id" => id}, socket) do
    {id, _} = Integer.parse(id)

    selected_items = Enum.filter(socket.assigns.selected_items, fn x -> x.id != id end)

    socket =
      socket
      |> assign(:selected_items, selected_items)

    {:noreply, socket}
  end

  @impl true
  def handle_event("validate", %{"search_input" => _search_string}, socket) do
    socket =
      socket
      |> assign(:listing_open, true)

    {:noreply, socket}
  end

  def handle_event("validate", _params, socket) do
    {:noreply, socket}
  end

  def handle_event("window-blur", _, socket) do
    socket =
      socket
      |> assign(:listing_open, false)

    {:noreply, socket}
  end

def handle_event("search_input_focus", _, socket) do
    socket =
      socket
      |> assign(:listing_open, true)

    {:noreply, socket}
  end

  def handle_event("toggle-listing", _, socket) do
    socket =
      socket
      |> assign(:listing_open, !socket.assigns.listing_open)

    {:noreply, socket}
  end

  def handle_event("close-listing", _, socket) do
    socket =
      socket
      |> assign(:listing_open, false)

    {:noreply, socket}
  end

  #----------------------------------------------------------------------------------Render --------------------------------------------------------------------------------------------->
  @impl true
  def render(assigns) do
    ~H"""
    <div
      class="col-span-2"
      data-reference-id={@input_variable}
      phx-hook="SelectComponent"
      id={"select_component"<>  @input_variable }
    >
      <.input
        field={@form[String.to_atom(@input_variable)]}
        type="select"
        options={[]}
        style="visibility: hidden; position: absolute;"
      />

      <div
        class="w-full max-w-lg "
        phx-click-away="close-listing"
        phx-target={@myself}
        id={"select-item"<> @input_variable }
      >
        <!-- Start Component -->
        <div class="relative">
          <.list_selected
            selected_items={@selected_items}
            myself={@myself}
            form={@form}
            input_variable={@input_variable}
          />
          <.list_search_result myself={@myself} listing_open={@listing_open} items={@items} />
          <.arrow_down_svg myself={@myself} />
        </div>
        <!-- End Component -->
      </div>
    </div>
    """
  end
  # ------------------------------------------------------------------------------- List Selected ------------------------------------------------------------------------------------
  def list_selected(assigns) do
    ~H"""
    <div class="flex items-center justify-between px-1 border border-2 rounded-md relative pr-8 bg-white">
      <ul class="flex flex-wrap items-center w-full">
        <!-- Tags (Selected) -->
        <%= for x <- @selected_items do %>
          <.selected_item id={Map.get(x, :id)} myself={@myself} name={x.name} />
        <% end %>
        <!-- Search Input -->
        <%= if Enum.empty?(@selected_items) do %>
          <.input_search myself={@myself} form={@form} input_variable={@input_variable} />
        <% end %>
        <!-- Arrow Icon -->
      </ul>
    </div>
    """
  end

  defp selected_item(assigns) do
    ~H"""
    <div>
      <li
        phx-click="handle-selected-item-click"
        phx-value-id={@id}
        phx-target={@myself}
        tabindex="0"
        class="relative m-1 px-2 py-1.5 border rounded-md cursor-pointer hover:bg-gray-100 after:content-['x'] after:ml-1.5 after:text-red-300 outline-none focus:outline-none ring-0 focus:ring-2 focus:ring-amber-300 ring-inset transition-all"
      >
        <%= @name %>
      </li>
    </div>
    """
  end
 defp input_search(assigns) do
    ~H"""
    <.input
      phx-focus="search_input_focus"
      phx-target={@myself}
      field={
        @form[
          String.to_atom("search_input" <> @input_variable)
        ]
      }
      type="text"
      class="test flex-grow py-2 px-2 mx-1 my-1.5 outline-none focus:outline-none focus:ring-amber-300 focus:ring-2 ring-inset transition-all rounded-md w-full"
    />
    """
  end
  #----------------------------------------------------------------------------------------------------- END List Selected   ------------------------------------------------------
  #----------------------------------------------------------------------------------------------------- Search Result -----------------------------------------------------------
  defp list_search_result(assigns) do
    ~H"""
    <div>
      <ul class="w-full list-none   border-t-0 rounded-md focus:outline-none overflow-y-auto outline-none focus:outline-none bg-white absolute left-0 bottom-100 max-h-56 bg-white z-50">
        <%= if @listing_open do %>
          <%= for x <- @items do %>
            <!-- Item Element -->
            <.option_item myself={@myself} x={x} />
            <!-- Empty Text -->
            <div>
              <li class="cursor-pointer px-2 py-2 text-gray-400"></li>
            </div>
          <% end %>
        <% end %>
      </ul>
    </div>
    """
  end

  defp option_item(assigns) do
    ~H"""
    <div class="relative z-50">
      <div class="bg-white">
        <li
          class="hover:bg-amber-200 cursor-pointer px-2 py-2 bg-white"
          phx-click="handle-item-click"
          phx-value-id={@x.id}
          id={@x.id}
          phx-target={@myself}
        >
          <%= @x.name %>
        </li>
      </div>
    </div>
    """
  end
 #----------------------------------------------------------------------------------------------------- Search Result -----------------------------------------------------------



  defp arrow_down_svg(assigns) do
    ~H"""
    <svg
      phx-click="toggle-listing"
      phx-target={@myself}
      width="24"
      height="24"
      stroke-width="0"
      fill="#ccc"
      class="absolute right-2 top-1/2 -translate-y-1/2 cursor-pointer focus:outline-none"
      tabindex="-1"
    >
      <path d="M12 17.414 3.293 8.707l1.414-1.414L12 14.586l7.293-7.293 1.414 1.414L12 17.414z" />
    </svg>
    """
  end

Recently trying to refactor/improve the code I stabled upon this in the documentation of the Phoenix.LiveComponent

You should also avoid using live components to provide abstract DOM components. As a guideline, a good LiveComponent encapsulates application concerns and not DOM functionality

And that make me wonder how would you fellas would go about implementing such a thing ?
Is this like a corner case where it’s both dom/functionality along with app concerns because also of the db-connection aspect that justifies utilizing LiveComponents like so ?