Packages
moon
2.78.4
2.90.5
retired
2.90.4
2.90.3
2.90.2
2.90.1
2.90.0
2.89.4
2.89.1
2.89.0
2.88.0
2.87.11
2.87.10
2.87.9
2.87.8
2.87.7
2.87.6
2.87.5
2.87.4
2.87.3
2.87.2
2.87.1
2.87.0
2.86.1
2.86.0
2.85.1
2.85.0
2.84.0
2.83.0
2.82.0
2.81.4
2.81.3
2.81.2
2.81.1
2.81.0
2.80.2
2.80.1
2.80.0
2.79.13
2.79.12
2.79.11
2.79.10
2.79.9
2.79.8
2.79.7
2.79.6
2.79.5
2.79.4
2.79.3
2.79.2
2.79.1
2.79.0
2.78.4
2.78.3
2.78.2
2.78.1
2.78.0
2.77.0
2.76.5
2.76.4
2.76.3
2.76.2
2.76.1
2.76.0
2.75.0
2.74.1
2.74.0
2.73.8
2.73.7
2.73.6
2.73.5
2.73.4
2.73.3
2.73.2
2.73.1
2.73.0
2.72.5
2.72.4
2.72.3
2.72.2
2.72.1
2.72.0
2.71.1
2.71.0
2.70.0
2.69.2
2.69.1
2.69.0
2.68.11
2.68.10
Components-based design system written in elixir
Current section
Files
Jump to
Current section
Files
lib/moon/components/accordion.ex
# https://www.figma.com/file/S3q1SkVngbwHuwpxHKCsgtJj/Moon---Components?node-id=23452%3A7
defmodule Moon.Components.Accordion do
@moduledoc false
use Moon.StatelessComponent
alias Phoenix.LiveView.JS
alias Moon.Autolayouts.LeftToRight
alias Moon.Autolayouts.PullAside
alias Moon.Icons.ControlsChevronUp
prop(id, :string)
prop(class, :css_class)
prop(open_by_default, :boolean, default: false)
prop(is_content_inside, :boolean, default: true)
prop(is_content_overflow_hidden, :boolean, default: true)
prop(with_button, :boolean, default: true)
prop(disabled, :boolean, default: false)
# we do add 2-letter sizes for consistence with Ract API, long sizes for backward compability & nice
prop(size, :string,
values!: ["small", "medium", "large", "xlarge", "sm", "md", "lg", "xl"],
default: "md"
)
prop(pull_a_side_class, :css_class)
prop(bg_color, :css_class, default: "bg-goku")
slot(title, required: true)
slot(header_content)
slot(content, required: true)
def render(assigns) do
~F"""
<div
id={@id}
aria-expanded={[if(@open_by_default, do: "true", else: "false")]}
class={
"w-full rounded-moon-s-sm h-max flex flex-col items-center p-4",
@bg_color,
get_padding(@size),
@class
}
>
<PullAside
left_grow
class={
"w-full gap-3",
"cursor-not-allowed opacity-60": @disabled,
"cursor-pointer": !@disabled,
"#{@pull_a_side_class}": @pull_a_side_class
}
>
<:left>
<div :on-click={toggle_content(@id, @disabled)} class="flex items-center grow">
<h3 class={"font-semibold", font_class(@size)} aria-level={3}><#slot {@title} /></h3>
</div>
</:left>
<:right>
<div class={hidden: !@with_button}>
<LeftToRight class="text-trunks">
<#slot {@header_content} />
<div
:on-click={toggle_content(@id, @disabled)}
aria-hidden="true"
id={@id <> "-arrow"}
class={
"transition-transform transition-200",
"rotate-90": !@open_by_default,
"rotate-180": @open_by_default
}
>
<ControlsChevronUp font_size="1.5rem" />
</div>
</LeftToRight>
</div>
</:right>
</PullAside>
{#if @is_content_inside}
<div
id={@id <> "-content"}
class={
"w-full h-full",
get_margin(@size),
"overflow-hidden": @is_content_overflow_hidden,
hidden: !@open_by_default
}
>
<#slot {@content} />
</div>
{/if}
</div>
{#if !@is_content_inside}
<div
id={@id <> "-content"}
class={
"w-full h-full",
get_margin(@size),
"overflow-hidden": @is_content_overflow_hidden,
hidden: !@open_by_default
}
>
<#slot {@content} />
</div>
{/if}
"""
end
def toggle_content(id, disabled) do
if !disabled do
JS.toggle(to: "#" <> id <> "-content")
|> JS.dispatch(
"moon:update-accordion-aria",
detail: %{
accordion_id: id
},
to: "#" <> id
)
|> JS.remove_class(
"rotate-90",
to: "#" <> id <> "-arrow.rotate-90"
)
|> JS.add_class(
"rotate-90",
to: "#" <> id <> "-arrow:not(.rotate-90)"
)
|> JS.remove_class(
"rotate-180",
to: "#" <> id <> "-arrow.rotate-180"
)
|> JS.add_class(
"rotate-180",
to: "#" <> id <> "-arrow:not(.rotate-180)"
)
end
end
defp get_padding(size) do
case size do
"xlarge" -> "p-4"
"xl" -> "p-4"
"large" -> "p-3"
"lg" -> "p-3"
"medium" -> "py-2 pr-2 pl-3"
"md" -> "py-2 pr-2 pl-3"
_ -> "py-1 pr-1 pl-3"
end
end
def get_margin(size) do
case size do
"xlarge" -> "mt-4"
"xl" -> "mt-4"
"large" -> "mt-3"
"lg" -> "mt-3"
_ -> "mt-2"
end
end
defp font_class(size) do
case size do
"xlarge" -> "text-moon-16"
"xl" -> "text-moon-16"
_ -> "text-moon-14"
end
end
end