defmodule Headless do use Phoenix.Component, global_prefixes: ~w(x-) @doc """ Toggle (switch) component. Uses regular checkbox input under the hood. Example: <.toggle field={form[:is_admin]}/> """ attr :field, Phoenix.HTML.FormField, required: true attr :rest, :global slot :inner_block, required: true slot :input do attr :class, :any end def toggle(assigns) do ~H""" """ end @doc """ Combobox (select + search) component. This component is built from the ground up to be compatible with Phoenix LiveView including dynamicly changing the list of options. Under the hood this component uses a hidden input to store the selected value to ensure seamless integration with Phoenix forms. Options are rendered server-side using `:option` slot. The client-side dropdown and search functionality is provided by Alpine.js operating directly on the rendered DOM. Features supported: - Client-side search - Keyboard navigation (arrows) - Keyboard selection (enter) - Mouse selection (click) Example: <.combobox field={form[:user_id]} options={@users} value={&1 &1.id} searchkey={& [&1.name, &1.email]}> <:selected :let={user}><%= user.name %> <:option :let={user}><%= user.name %> - <%= user.email %> """ attr :field, Phoenix.HTML.FormField attr :options, :list attr :value, :any, doc: "Function returning value for option" attr :searchkey, :any, doc: "Function returning search key for option" attr :class, :any, default: nil attr :rest, :global slot :selected, doc: "Slot rendering the selected option" do attr :class, :any end slot :option, doc: "Slot rendering option inside the panel" slot :placeholder, doc: "Placeholder shown when no option is selected" do attr :class, :any end slot :button, doc: "Button that opens the panel" do attr :class, :any end slot :search, doc: "Search input" do attr :class, :any attr :placeholder, :string end slot :panel, doc: "Container for options" do attr :class, :any end def combobox(assigns) do ~H"""
<.input field={@field} type="hidden" x-bind="input" />
""" end @doc """ Render input for a form field. Heavily based on default Phoenix generated CoreComponents """ attr :field, Phoenix.HTML.FormField attr :id, :any, default: nil attr :name, :any attr :value, :any attr :type, :string, default: "text" attr :checked, :boolean, doc: "the checked flag for checkbox inputs" attr :rest, :global slot :inner_block def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do assigns |> assign(field: nil, id: assigns.id || field.id) |> assign(:errors, field.errors) |> assign_new(:name, fn -> field.name end) |> assign_new(:value, fn -> field.value end) |> input() end def input(%{type: "checkbox"} = assigns) do assigns = assign_new(assigns, :checked, fn -> Phoenix.HTML.Form.normalize_value("checkbox", assigns[:value]) end) ~H""" """ end def input(assigns) do ~H""" """ end defp data(keyword), do: Jason.encode!(Enum.into(keyword, %{})) defp slotattr(slot, name, default \\ nil) defp slotattr([], _name, default), do: default defp slotattr([entry], name, default), do: Map.get(entry, name, default) end