Packages
petal_components
0.2.1
4.6.2
4.6.1
4.6.0
4.5.0
4.4.0
4.3.0
4.2.1
4.2.0
4.1.2
4.1.1
4.1.0
4.0.12
4.0.11
4.0.10
4.0.6
4.0.5
4.0.4
4.0.3
4.0.1
3.2.2
3.2.1
3.2.0
3.1.0
3.0.2
3.0.1
3.0.0
2.9.3
2.9.2
retired
2.9.1
retired
2.9.0
retired
2.8.4
2.8.3
2.8.2
2.8.1
2.8.0
2.7.4
2.7.3
2.7.2
2.7.1
2.7.0
2.6.1
2.6.0
2.5.2
2.5.1
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.1
2.2.0
2.1.2
2.1.1
2.1.0
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.1
1.7.0
1.6.2
1.6.1
1.6.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.14
1.2.13
1.2.12
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.19.10
0.19.9
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.7
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.15.0
0.14.1
0.14.0
0.13.7
0.13.6
0.13.5
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.8
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.0
Shadcn-style Phoenix LiveView components that AI assistants can actually use. Pair with the MCP server so AI coding tools can inspect the real component API.
Current section
Files
Jump to
Current section
Files
lib/petal/dropdown.ex
defmodule PetalComponents.Dropdown do
use Phoenix.Component
def dropdown(assigns) do
~H"""
<div
x-data="{ open: false }"
@keydown.escape.stop="open = false"
@click.outside="open = false"
class="relative z-10 inline-block text-left"
>
<div>
<%= if @label do %>
<button
type="button"
class="inline-flex justify-center w-full px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none"
x-ref="button"
@click="open = !open"
aria-haspopup="true"
x-bind:aria-expanded="open.toString()"
>
<%= @label %>
<svg class="w-5 h-5 ml-2 -mr-1" x-description="Heroicon name: solid/chevron-down" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg>
</button>
<% else %>
<button
type="button"
class="flex items-center text-gray-400 rounded-full hover:text-gray-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500"
id="options-menu"
@click="open = !open"
aria-haspopup="true"
x-bind:aria-expanded="open.toString()"
>
<span class="sr-only">Open options</span>
<svg
class="w-5 h-5"
x-description="Heroicon name: solid/dots-vertical"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
</svg>
</button>
<% end %>
</div>
<div
x-show="open"
x-transition:enter="transition ease-out duration-100"
x-transition:enter-start="transform opacity-0 scale-95"
x-transition:enter-end="transform opacity-100 scale-100"
x-transition:leave="transition ease-in duration-75"
x-transition:leave-start="transform opacity-100 scale-100"
x-transition:leave-end="transform opacity-0 scale-95"
class="absolute right-0 w-56 mt-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
role="menu"
aria-orientation="vertical"
aria-labelledby="options-menu"
style="display: none;"
>
<div class="py-1" role="none">
<%= render_slot(@inner_block) %>
</div>
</div>
</div>
"""
end
def dropdown_menu_item(%{type: "button"} = assigns) do
~H"""
<button class={dropdown_menu_item_classes()}>
<%= if assigns[:inner_block] do %>
<%= render_slot(@inner_block) %>
<% else %>
<%= @label %>
<% end %>
</button>
"""
end
def dropdown_menu_item(%{type: "a"} = assigns) do
~H"""
<a href={@href} class={dropdown_menu_item_classes()}>
<%= if assigns[:inner_block] do %>
<%= render_slot(@inner_block) %>
<% else %>
<%= @label %>
<% end %>
</a>
"""
end
def dropdown_menu_item(%{type: "live_patch"} = assigns) do
~H"""
<%= live_patch [
to: @href,
class: dropdown_menu_item_classes()] do %>
<%= if assigns[:inner_block] do %>
<%= render_slot(@inner_block) %>
<% else %>
<%= @label %>
<% end %>
<% end %>
"""
end
def dropdown_menu_item(%{type: "live_redirect"} = assigns) do
~H"""
<%= live_redirect [
to: @href,
class: dropdown_menu_item_classes()] do %>
<%= if assigns[:inner_block] do %>
<%= render_slot(@inner_block) %>
<% else %>
<%= @label %>
<% end %>
<% end %>
"""
end
def dropdown_menu_item_classes(),
do:
"block flex gap-2 items-center self-start justify-start px-4 py-2 text-sm text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 w-full text-left"
end