Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Improve multiple components #142

Draft
wants to merge 3 commits into
base: feature/accessibility-hook
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 64 additions & 33 deletions lib/salad_ui/hover_card.ex
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
defmodule SaladUI.HoverCard do
@moduledoc """
Implement hover card component
Hover card component

## Usage
<.hover_card>
<.hover_card_trigger>
<.button variant="link">
@salad_ui
</.button>
</.hover_card_trigger>
<.hover_card_content>
Hover card content
</.hover_card_content>
</.hover_card>
## Examples:

<.hover_card id="my-hover-card">
<.hover_card_trigger>
<.button variant="link">
@salad_ui
</.button>
</.hover_card_trigger>
<.hover_card_content>
Hover card content
</.hover_card_content>
</.hover_card>
"""
use SaladUI, :component

@doc """
Render hover card wrapper
Renders the root container for the hover card
"""

attr :id, :string, required: true
attr :open, :boolean, default: false

attr :side, :string,
default: "top",
values: ~w(bottom bottom-start bottom-end left left-start left-end right right-start right-end top top-start top-end)

attr :options, :map,
default: %{},
doc: """
Options supported by the Zag.js library for configuring this component.
See https://zagjs.com/components/react/tabs#machine-context for full list of available options.
"""

attr :on_open, :list,
default: [],
values: [[], [:client], [:server], [:client, :server]],
doc: """
A list of atoms indicating where to emit custom events each time the hover card is opened/closed
"""

attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
Expand All @@ -32,6 +55,14 @@ defmodule SaladUI.HoverCard do
@class
])
}
id={@id}
phx-hook="ZagHook"
data-component="hover-card"
data-parts={Jason.encode!(["trigger", "positioner", "content", "arrow", "arrow-tip"])}
data-options={
%{open: @open, positioning: %{placement: @side}} |> Map.merge(@options) |> Jason.encode!()
}
data-listeners={[[:on_open_change | @on_open]] |> Jason.encode!()}
{@rest}
>
{render_slot(@inner_block)}
Expand All @@ -40,7 +71,7 @@ defmodule SaladUI.HoverCard do
end

@doc """
Render hover card trigger
Renders the trigger for the hover card
"""
attr :class, :string, default: nil
attr :rest, :global
Expand All @@ -49,6 +80,7 @@ defmodule SaladUI.HoverCard do
def hover_card_trigger(assigns) do
~H"""
<div
data-part="trigger"
class={
classes([
"",
Expand All @@ -63,32 +95,31 @@ defmodule SaladUI.HoverCard do
end

@doc """
Render hover card content
Renders the content for the hover card
"""
attr :class, :string, default: nil
attr :side, :string, values: ~w(bottom left right top), default: "top"
attr :align, :string, values: ["start", "center", "end"], default: "center"
attr :rest, :global
slot :inner_block, required: true

def hover_card_content(assigns) do
assigns =
assign(assigns, :variant_class, side_variant(assigns.side, assigns.align))

~H"""
<div
data-side={@side}
class={
classes([
"absolute hidden group-hover/hover-card:block",
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none animate-in fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
@variant_class,
@class
])
}
{@rest}
>
{render_slot(@inner_block)}
<div data-part="positioner" class="inline-block">
<div
data-part="content"
class={
classes([
"opacity-0 group-hover/hover-card:opacity-100",
"z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none animate-in fade-in-0 zoom-in-95",
@class
])
}
{@rest}
>
<div data-part="arrow">
<div data-part="arrow-tip"></div>
</div>
{render_slot(@inner_block)}
</div>
</div>
"""
end
Expand Down
80 changes: 49 additions & 31 deletions lib/salad_ui/tooltip.ex
Original file line number Diff line number Diff line change
@@ -1,38 +1,63 @@
defmodule SaladUI.Tooltip do
@moduledoc false
use SaladUI, :component

@doc """
Render a tooltip
@moduledoc """
Tooltip component

## Examples:

<.tooltip>
<.button variant="outline">Hover me</.button>
<.tooltip_content class="bg-primary text-white" theme={nil}>
<.tooltip id="my-tooltip">
<.tooltip_trigger>
<.button variant="outline">Hover me</.button>
</.tooltip_trigger>
<.tooltip_content class="bg-primary text-white">
<p>Hi! I'm a tooltip.</p>
</.tooltip_content>
</.tooltip>

"""

use SaladUI, :component

attr :id, :string, required: true

attr :side, :string,
default: "top",
values: ~w(bottom bottom-start bottom-end left left-start left-end right right-start right-end top top-start top-end)

attr :options, :map,
default: %{},
doc: """
Options supported by the Zag.js library for configuring this component.
See https://zagjs.com/components/react/tooltip#machine-context for full list of available options.
"""

attr :on_open, :list,
default: [],
values: [[], [:client], [:server], [:client, :server]],
doc: """
A list of atoms indicating where to emit custom events each time the tooltip is opened/closed
"""

attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true

@doc """
Renders the root container for the tooltip component
"""
def tooltip(assigns) do
~H"""
<div
data-component="tooltip"
data-parts={Jason.encode!(["root", "trigger", "positioner", "content"])}
data-part="root"
data-options={
Jason.encode!(%{
id: unique_id(),
additional_context: ["positioning"]
})
class={
classes([
"relative group/tooltip inline-block",
@class
])
}
id={@id}
phx-hook="ZagHook"
class={@class}
data-component="tooltip"
data-parts={Jason.encode!(["trigger", "positioner", "content"])}
data-options={%{positioning: %{placement: @side}} |> Map.merge(@options) |> Jason.encode!()}
data-listeners={[[:on_open_change | @on_open]] |> Jason.encode!()}
{@rest}
>
{render_slot(@inner_block)}
Expand All @@ -41,41 +66,34 @@ defmodule SaladUI.Tooltip do
end

@doc """
Render only for compatible with shad ui
Renders the trigger for the tooltip
"""
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true

def tooltip_trigger(assigns) do
~H"""
<div data-part="trigger" class={@class} {@rest}>
<div class="inline-block" data-part="trigger">
{render_slot(@inner_block)}
</div>
"""
end

@doc """
Render
Renders the content for the tooltip
"""
attr :class, :string, default: nil
attr :side, :string, default: "top", values: ~w(bottom left right top)

attr :rest, :global
slot :inner_block, required: true

def tooltip_content(assigns) do
~H"""
<div
data-part="positioner"
data-ctx-positioning={Jason.encode!(%{strategy: "fixed", placement: @side})}
>
<div data-part="positioner">
<div
data-part="content"
hidden
class={
classes([
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[placement=bottom]:slide-in-from-top-2 data-[placement=left]:slide-in-from-right-2 data-[placement=right]:slide-in-from-left-2 data-[placement=top]:slide-in-from-bottom-2",
"whitespace-nowrap opacity-0 group-hover/tooltip:opacity-100",
"z-50 w-auto overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95",
@class
])
}
Expand Down