defmodule Phoenix.UI.Components.Tooltip do @moduledoc """ Provides tooltip component. """ use Phoenix.UI, :component @default_color "slate" @default_position "top" @default_variant "simple" @doc """ Renders tooltip component. ## Examples ``` <.tooltip> content ``` """ @spec tooltip(Socket.assigns()) :: Rendered.t() def tooltip(raw) do assigns = raw |> assign_new(:color, fn -> @default_color end) |> assign_new(:position, fn -> @default_position end) |> assign_new(:variant, fn -> @default_variant end) |> build_tooltip_attrs() ~H"""
<%= render_slot(@inner_block) %>
<%= if is_bitstring(@content) do %> <%= @content %> <% else %> <%= render_slot(@content) %> <% end %>
""" end ### Tooltip Attrs ########################## defp build_tooltip_attrs(assigns) do class = build_class(~w( z-50 invisible opacity-0 group-hover:visible group-hover:opacity-100 absolute text-xs rounded text-center whitespace-nowrap py-1 px-2 transition-all ease-in-out delay-150 duration-300 #{classes(:color, assigns)} #{classes(:margin, assigns)} #{classes(:position, assigns)} #{classes(:variant, assigns)} #{Map.get(assigns, :extend_class)} )) attrs = assigns |> assigns_to_attributes([:color, :content, :id, :position, :variant]) |> Keyword.put_new(:class, class) assign(assigns, :tooltip_attrs, attrs) end ### CSS Classes ########################## # Color defp classes(:color, %{color: color}), do: "bg-#{color}-800 text-#{color}-200" # Margin defp classes(:margin, %{position: "bottom_end"}), do: "mt-3" defp classes(:margin, %{position: "bottom_start"}), do: "mt-3" defp classes(:margin, %{position: "bottom"}), do: "mt-3" defp classes(:margin, %{position: "left_end"}), do: "mr-3" defp classes(:margin, %{position: "left_start"}), do: "mr-3" defp classes(:margin, %{position: "left"}), do: "mr-3" defp classes(:margin, %{position: "right_end"}), do: "ml-3" defp classes(:margin, %{position: "right_start"}), do: "ml-3" defp classes(:margin, %{position: "right"}), do: "ml-3" defp classes(:margin, %{position: "top_end"}), do: "mb-3" defp classes(:margin, %{position: "top_start"}), do: "mb-3" defp classes(:margin, %{position: "top"}), do: "mb-3" # Position defp classes(:position, %{position: "bottom_end"}), do: "top-full right-0" defp classes(:position, %{position: "bottom_start"}), do: "top-full left-0" defp classes(:position, %{position: "bottom"}), do: "top-full left-1/2 -translate-x-1/2" defp classes(:position, %{position: "left_end"}), do: "right-full bottom-0" defp classes(:position, %{position: "left_start"}), do: "right-full top-0" defp classes(:position, %{position: "left"}), do: "right-full top-1/2 -translate-y-1/2" defp classes(:position, %{position: "right_end"}), do: "left-full bottom-0" defp classes(:position, %{position: "right_start"}), do: "left-full top-0" defp classes(:position, %{position: "right"}), do: "left-full top-1/2 -translate-y-1/2" defp classes(:position, %{position: "top_end"}), do: "bottom-full right-0" defp classes(:position, %{position: "top_start"}), do: "bottom-full left-0" defp classes(:position, %{position: "top"}), do: "bottom-full left-1/2 -translate-x-1/2" # Variant defp classes(:variant, %{color: color, position: position, variant: "arrow"}) do case position do pos when pos in ["bottom_end", "bottom_start", "bottom"] -> "after:absolute after:-top-1.5 after:left-1/2 after:-translate-x-1/2 after:border-solid after:border-b-8 after:border-x-transparent after:border-x-8 after:border-t-0 after:border-b-#{color}-800" pos when pos in ["left_end", "left_start", "left"] -> "after:absolute after:-right-1.5 after:top-1/2 after:-translate-y-1/2 after:border-solid after:border-l-8 after:border-y-transparent after:border-y-8 after:border-r-0 after:border-l-#{color}-800" pos when pos in ["right_end", "right_start", "right"] -> "after:absolute after:-left-1.5 after:top-1/2 after:-translate-y-1/2 after:border-solid after:border-r-8 after:border-y-transparent after:border-y-8 after:border-l-0 after:border-r-#{color}-800" pos when pos in ["top_end", "top_start", "top"] -> "after:absolute after:-bottom-1.5 after:left-1/2 after:-translate-x-1/2 after:border-solid after:border-t-8 after:border-x-transparent after:border-x-8 after:border-b-0 after:border-t-#{color}-800" end end defp classes(_rule_group, _assigns), do: nil end