defmodule PhiaUi.Components.Rating do @moduledoc """ Star Rating component for PhiaUI. CSS-only implementation using native radio inputs and SVG star icons. Supports read-only display and interactive selection. Form integration is available via `form_rating/1`. ## Examples <%!-- Display only --%> <.rating value={4} readonly={true} /> <%!-- Interactive --%> <.rating value={@rating} phx-change="set_rating" /> <%!-- Form-integrated --%> <.form_rating field={@form[:rating]} label="Rating" /> <%!-- Large size --%> <.rating value={3} size="lg" /> <%!-- Half-star display --%> <.rating value={3.5} half={true} readonly={true} /> <%!-- Heart icon --%> <.rating value={4} icon={:heart} /> <%!-- With hover labels --%> <.rating value={3} labels={["Poor", "Fair", "Good", "Great", "Excellent"]} /> """ use Phoenix.Component import PhiaUi.ClassMerger, only: [cn: 1] attr(:value, :any, default: 0, doc: "Current rating value (0 to max). Float when half=true.") attr(:max, :integer, default: 5, doc: "Maximum number of stars") attr(:readonly, :boolean, default: false, doc: "Whether the rating is read-only") attr(:size, :string, default: "default", values: ~w(sm default lg), doc: "Size of the stars") attr(:name, :string, default: "rating", doc: "Input name attribute") attr(:half, :boolean, default: false, doc: "Enable half-star display for float values") attr(:icon, :atom, values: [:star, :heart, :thumb], default: :star, doc: "Icon style") attr(:labels, :list, default: [], doc: "Hover label strings per position (e.g. ['Poor','Good'])") attr(:class, :string, default: nil, doc: "Additional CSS classes") attr(:rest, :global, include: ~w(phx-change phx-blur id), doc: "HTML attributes forwarded to the fieldset" ) @doc """ Renders a star rating with radio inputs. When `half=false` (default): integer-only values, simple SVG path per star. When `half=true`: float values display with a clip overlay (50% fill for .5 values). The `icon` attr switches the SVG shape to `:star`, `:heart`, or `:thumb`. The `labels` list adds `title` tooltip text to each star label. """ def rating(assigns) do assigns = assign(assigns, :stars, Enum.to_list(1..assigns.max)) ~H"""
""" end attr(:field, Phoenix.HTML.FormField, required: true, doc: "A Phoenix.HTML.FormField struct") attr(:label, :string, default: nil, doc: "Label text") attr(:description, :string, default: nil, doc: "Helper text") attr(:max, :integer, default: 5, doc: "Maximum number of stars") attr(:size, :string, default: "default", values: ~w(sm default lg), doc: "Star size") attr(:half, :boolean, default: false, doc: "Enable half-star display for float values") attr(:icon, :atom, values: [:star, :heart, :thumb], default: :star, doc: "Icon style") attr(:labels, :list, default: [], doc: "Hover label strings per position") attr(:class, :string, default: nil, doc: "Additional CSS classes") attr(:rest, :global, include: ~w(phx-change phx-blur phx-debounce), doc: "HTML attributes forwarded to fieldset" ) @doc """ Renders a form-integrated star rating with label, description, and errors. """ def form_rating(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do assigns = assigns |> assign(:errors, Enum.map(field.errors, &translate_error/1)) |> assign_new(:name, fn -> field.name end) |> assign_new(:value, fn -> parse_value(field.value) end) ~H"""{@description}
<.rating value={@value} max={@max} size={@size} name={@name} half={@half} icon={@icon} labels={@labels} class={@class} {@rest} />{error}