defmodule Corex.AngleSlider do @moduledoc ~S''' Phoenix implementation of [Zag.js Angle Slider](https://zagjs.com/components/react/angle-slider). ## Examples ### Basic ```heex <.angle_slider id="angle" class="angle-slider"> <:label>Angle ``` ### With marks ```heex <.angle_slider id="angle" class="angle-slider" marker_values={[0, 90, 180, 270]}> <:label>Angle ``` ### Controlled In controlled mode, use `on_value_change` and `on_value_change_client` so the thumb moves during drag. Use `on_value_change_end` and `on_value_change_end_client` if you only need to react when the user releases. ```elixir defmodule MyAppWeb.AngleSliderLive do use MyAppWeb, :live_view def mount(_params, _session, socket) do {:ok, assign(socket, :angle, 0)} end def handle_event("angle_changed", %{"value" => value}, socket) do {:noreply, assign(socket, :angle, value)} end def render(assigns) do ~H""" <.angle_slider id="angle" controlled value={@angle} on_value_change="angle_changed" marker_values={[0, 90, 180, 270]} class="angle-slider"> <:label>Angle """ end end ``` ## API Control In order to use the API, you must use an id on the component. ***Client-side*** ```heex ``` ***Server-side*** ```elixir def handle_event("set_angle", %{"value" => value}, socket) do {:noreply, Corex.AngleSlider.set_value(socket, "my-angle-slider", String.to_float(value))} end ``` ## Styling Use data attributes to target elements: ```css [data-scope="angle-slider"][data-part="root"] {} [data-scope="angle-slider"][data-part="control"] {} [data-scope="angle-slider"][data-part="thumb"] {} [data-scope="angle-slider"][data-part="value-text"] {} [data-scope="angle-slider"][data-part="marker-group"] {} [data-scope="angle-slider"][data-part="marker"] {} ``` If you wish to use the default Corex styling, you can use the class `angle-slider` on the component. This requires to install `Mix.Tasks.Corex.Design` first and import the component css file. ```css @import "../corex/main.css"; @import "../corex/tokens/themes/neo/light.css"; @import "../corex/components/angle-slider.css"; ``` You can then use modifiers ```heex <.angle_slider class="angle-slider angle-slider--accent angle-slider--lg" value={0} /> ``` Learn more about modifiers and [Corex Design](https://corex-ui.com/components/angle-slider#modifiers) ''' @doc type: :component use Phoenix.Component alias Corex.AngleSlider.Anatomy.{ Control, HiddenInput, Label, Marker, MarkerGroup, Props, Root, Text, Thumb, Value, ValueText } alias Corex.AngleSlider.Connect alias Phoenix.LiveView alias Phoenix.LiveView.JS attr(:id, :string, required: false, doc: "The id of the angle slider") attr(:value, :float, default: 0.0, doc: "The value or controlled value in degrees") attr(:controlled, :boolean, default: false, doc: "Whether the value is controlled") attr(:step, :float, default: 1.0, doc: "Step value") attr(:disabled, :boolean, default: false, doc: "Whether the slider is disabled") attr(:read_only, :boolean, default: false, doc: "Whether the slider is read-only") attr(:invalid, :boolean, default: false, doc: "Whether the slider is invalid") attr(:name, :string, default: nil, doc: "Name for form submission") attr(:dir, :string, default: nil, values: [nil, "ltr", "rtl"], doc: "Direction") attr(:on_value_change, :string, default: nil, doc: "Server event when value changes (uncontrolled)" ) attr(:on_value_change_client, :string, default: nil, doc: "Client event when value changes (uncontrolled)" ) attr(:on_value_change_end, :string, default: nil, doc: "Server event when value change ends (controlled)" ) attr(:on_value_change_end_client, :string, default: nil, doc: "Client event when value change ends (controlled)" ) attr(:marker_values, :list, default: [], doc: "List of angle values to show as markers (e.g. [0, 90, 180, 270])" ) attr(:rest, :global) slot :label, required: false do attr(:class, :string, required: false) end def angle_slider(assigns) do assigns = assigns |> assign_new(:id, fn -> "angle-slider-#{System.unique_integer([:positive])}" end) |> assign_new(:dir, fn -> "ltr" end) ~H"""