defmodule Phoenix.UI.Components.Collapse do @moduledoc """ Provides collapse component. """ use Phoenix.UI, :component attr(:element, :string, default: "div") attr(:extend_class, :string) attr(:max_size, :string, default: "5000px") attr(:orientation, :string, default: "vertical", values: ["horizontal", "vertical"]) attr(:rest, :global, include: ~w(open)) attr(:transition_duration, :integer, default: 300) slot(:inner_block, required: true) @doc """ Renders collapse component. ## Examples ``` <.collapse> content ``` """ @spec collapse(Socket.assigns()) :: Rendered.t() def collapse(assigns) do assigns = assign_class(assigns, ~w( collapse overflow-hidden invisible open:visible transition-all ease-in-out #{classes(:max_size, assigns)} #{classes(:open, assigns)} #{classes(:transition, assigns)} )) ~H""" <.dynamic_tag class={@class} name={@element} {@rest}> <%= render_slot(@inner_block) %> """ end ### JS Interactions ########################## @doc """ Closes collapse by selector. ## Examples iex> close_collapse(selector) %JS{} iex> close_collapse(js, selector) %JS{} """ @spec close_collapse(String.t()) :: struct() def close_collapse(selector), do: close_collapse(%JS{}, selector) @spec close_collapse(struct(), String.t()) :: struct() def close_collapse(%JS{} = js, selector) do JS.remove_attribute(js, "open", to: selector) end @doc """ Opens collapse by selector. ## Examples iex> open_collapse(selector) %JS{} iex> open_collapse(js, selector) %JS{} """ @spec open_collapse(String.t()) :: struct() def open_collapse(selector), do: open_collapse(%JS{}, selector) @spec open_collapse(struct(), String.t()) :: struct() def open_collapse(%JS{} = js, selector) do JS.set_attribute(js, {"open", "true"}, to: selector) end ### CSS Classes ########################## # Max Size defp classes(:max_size, %{max_size: size, orientation: "vertical"}), do: "open:max-h-[#{size}]" # Open defp classes(:open, %{orientation: "horizontal"}), do: "max-w-0 open:max-w-full" defp classes(:open, %{orientation: "vertical"}), do: "max-h-0" # Transition defp classes(:transition, %{transition_duration: duration}), do: "duration-#{duration}" defp classes(_rule_group, _assigns), do: nil end