defmodule Corex.Carousel do @moduledoc ~S''' Phoenix implementation of [Zag.js Carousel](https://zagjs.com/components/react/carousel). ## Examples ### Basic with image URLs ```heex <.carousel id="car" items={["/images/beach.jpg", "/images/fall.jpg", "/images/sand.jpg"]} class="carousel"> <:prev_trigger> <:next_trigger> ``` Items can be URLs (strings) or maps with `:url` and optional `:alt` keys. ## Styling Use data attributes to target elements: ```css [data-scope="carousel"][data-part="root"] {} [data-scope="carousel"][data-part="control"] {} [data-scope="carousel"][data-part="item-group"] {} [data-scope="carousel"][data-part="item"] {} [data-scope="carousel"][data-part="prev-trigger"] {} [data-scope="carousel"][data-part="next-trigger"] {} [data-scope="carousel"][data-part="indicator-group"] {} [data-scope="carousel"][data-part="indicator"] {} ``` If you wish to use the default Corex styling, you can use the class `carousel` 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/carousel.css"; ``` You can then use modifiers ```heex <.carousel class="carousel carousel--accent carousel--lg" items={[]}> ``` Learn more about modifiers and [Corex Design](https://corex-ui.com/components/carousel#modifiers) ''' @doc type: :component use Phoenix.Component alias Corex.Carousel.Anatomy.{ Props, Root, Control, ItemGroup, Item, PrevTrigger, NextTrigger, IndicatorGroup, Indicator } alias Corex.Carousel.Connect attr(:id, :string, required: false) attr(:aria_label, :string, default: nil) attr(:items, :list, required: true, doc: "List of image URLs (strings) or maps with :url and optional :alt" ) attr(:page, :integer, default: 0) attr(:controlled, :boolean, default: false) attr(:dir, :string, default: nil, values: [nil, "ltr", "rtl"]) attr(:orientation, :string, default: "horizontal", values: ["horizontal", "vertical"]) attr(:slides_per_page, :integer, default: 1) attr(:slides_per_move, :any, default: nil, doc: "Number of slides to move per step, or \"auto\"" ) attr(:loop, :boolean, default: false) attr(:autoplay, :boolean, default: false) attr(:autoplay_delay, :integer, default: 4000) attr(:allow_mouse_drag, :boolean, default: false) attr(:spacing, :string, default: "0px") attr(:padding, :string, default: nil) attr(:in_view_threshold, :float, default: 0.6) attr(:snap_type, :string, default: "mandatory", values: ["proximity", "mandatory"]) attr(:auto_size, :boolean, default: false) attr(:on_page_change, :string, default: nil) attr(:on_page_change_client, :string, default: nil) attr(:rest, :global) slot(:prev_trigger, required: true) slot(:next_trigger, required: true) def carousel(assigns) do items = List.wrap(assigns.items) slide_count = length(items) slides_per_page = assigns.slides_per_page || 1 total_pages = if slide_count == 0 do 0 else div(slide_count + slides_per_page - 1, slides_per_page) end page = assigns.page || 0 loop = assigns.loop || false prev_disabled = !loop and page <= 0 next_disabled = !loop and (total_pages == 0 or page >= total_pages - 1) assigns = assigns |> assign_new(:id, fn -> "carousel-#{System.unique_integer([:positive])}" end) |> assign_new(:dir, fn -> "ltr" end) |> assign(:items, items) |> assign(:slide_count, slide_count) |> assign(:total_pages, total_pages) |> assign(:prev_disabled, prev_disabled) |> assign(:next_disabled, next_disabled) ~H"""
{Map.get(item,
""" end end