From 1cd539b2daaa8204ee34369a5ff763562596cb95 Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Tue, 10 Feb 2026 10:16:21 +0000 Subject: [PATCH] Fix usage rules to include elixir/otp and link Fluxon --- AGENTS.md | 2523 ++--------------------------------------------------- mix.exs | 10 +- 2 files changed, 94 insertions(+), 2439 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c6a75d6b..22911597 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,6 +3,90 @@ [Project architecture](architecture.md) + +## usage_rules:elixir usage +# Elixir Core Usage Rules + +## Pattern Matching +- Use pattern matching over conditional logic when possible +- Prefer to match on function heads instead of using `if`/`else` or `case` in function bodies +- `%{}` matches ANY map, not just empty maps. Use `map_size(map) == 0` guard to check for truly empty maps + +## Error Handling +- Use `{:ok, result}` and `{:error, reason}` tuples for operations that can fail +- Avoid raising exceptions for control flow +- Use `with` for chaining operations that return `{:ok, _}` or `{:error, _}` + +## Common Mistakes to Avoid +- Elixir has no `return` statement, nor early returns. The last expression in a block is always returned. +- Don't use `Enum` functions on large collections when `Stream` is more appropriate +- Avoid nested `case` statements - refactor to a single `case`, `with` or separate functions +- Don't use `String.to_atom/1` on user input (memory leak risk) +- Lists and enumerables cannot be indexed with brackets. Use pattern matching or `Enum` functions +- Prefer `Enum` functions like `Enum.reduce` over recursion +- When recursion is necessary, prefer to use pattern matching in function heads for base case detection +- Using the process dictionary is typically a sign of unidiomatic code +- Only use macros if explicitly requested +- There are many useful standard library functions, prefer to use them where possible + +## Function Design +- Use guard clauses: `when is_binary(name) and byte_size(name) > 0` +- Prefer multiple function clauses over complex conditional logic +- Name functions descriptively: `calculate_total_price/2` not `calc/2` +- Predicate function names should not start with `is` and should end in a question mark. +- Names like `is_thing` should be reserved for guards + +## Data Structures +- Use structs over maps when the shape is known: `defstruct [:name, :age]` +- Prefer keyword lists for options: `[timeout: 5000, retries: 3]` +- Use maps for dynamic key-value data +- Prefer to prepend to lists `[new | list]` not `list ++ [new]` + +## Mix Tasks + +- Use `mix help` to list available mix tasks +- Use `mix help task_name` to get docs for an individual task +- Read the docs and options fully before using tasks + +## Testing +- Run tests in a specific file with `mix test test/my_test.exs` and a specific test with the line number `mix test path/to/test.exs:123` +- Limit the number of failed tests with `mix test --max-failures n` +- Use `@tag` to tag specific tests, and `mix test --only tag` to run only those tests +- Use `assert_raise` for testing expected exceptions: `assert_raise ArgumentError, fn -> invalid_function() end` +- Use `mix help test` to for full documentation on running tests + +## Debugging + +- Use `dbg/1` to print values while debugging. This will display the formatted value and other relevant information in the console. + + + +## usage_rules:otp usage +# OTP Usage Rules + +## GenServer Best Practices +- Keep state simple and serializable +- Handle all expected messages explicitly +- Use `handle_continue/2` for post-init work +- Implement proper cleanup in `terminate/2` when necessary + +## Process Communication +- Use `GenServer.call/3` for synchronous requests expecting replies +- Use `GenServer.cast/2` for fire-and-forget messages. +- When in doubt, use `call` over `cast`, to ensure back-pressure +- Set appropriate timeouts for `call/3` operations + +## Fault Tolerance +- Set up processes such that they can handle crashing and being restarted by supervisors +- Use `:max_restarts` and `:max_seconds` to prevent restart loops + +## Task and Async +- Use `Task.Supervisor` for better fault tolerance +- Handle task failures with `Task.yield/2` or `Task.shutdown/2` +- Set appropriate task timeouts +- Use `Task.async_stream/3` for concurrent enumeration with back-pressure + + ## phoenix:ecto usage ## Ecto Guidelines @@ -546,2443 +630,6 @@ mix usage_rules.search_docs "Enum.zip" --query-by title ## fluxon usage _Fluxon UI Components_ -# Fluxon UI Components Usage Rules - -This document provides a guide for Large Language Models (LLMs) on how to use Fluxon UI components. It covers component attributes, slots, and provides usage examples for different scenarios. - -## Accordion - -The Accordion component provides collapsible content sections with headers that toggle panel visibility. - -### Components -- `accordion`: Main container that manages state and accessibility -- `accordion_item`: Individual collapsible sections - -### Attributes - -#### accordion -- `id` (string, optional): Unique identifier for the accordion container -- `class` (any, optional): Additional CSS classes for the accordion container -- `multiple` (boolean, default: false): Allow multiple items to be expanded simultaneously -- `prevent_all_closed` (boolean, default: false): Prevent all items from being closed at once -- `animation_duration` (integer, default: 300): Duration of expand/collapse animation in milliseconds -- `rest`: Additional HTML attributes - -#### accordion_item -- `id` (string, optional): Unique identifier for the accordion item -- `class` (any, optional): Additional CSS classes for the accordion item container -- `expanded` (boolean, default: false): Initial expanded state of the item -- `icon` (boolean, default: true): Show/hide the chevron icon -- `rest`: Additional HTML attributes - -### Slots - -#### accordion -- `inner_block` (required): Contains one or more accordion_item components - -#### accordion_item -- `header` (required): Always-visible clickable area that toggles the panel - - `class` (optional): Additional CSS classes for the header button -- `panel` (required): Expandable content area - - `class` (optional): Additional CSS classes for the panel content - -### Usage Examples - -#### Basic Accordion -```heex -<.accordion> - <.accordion_item> - <:header>What is Fluxon? - <:panel> - Fluxon is a powerful UI component library for Phoenix LiveView applications. - - - - <.accordion_item> - <:header>How do I get started? - <:panel> - Add Fluxon to your dependencies and follow the installation guide. - - - -``` - -#### Multiple Sections and Rich Headers -```heex -<.accordion multiple> - <.accordion_item> - <:header class="flex items-center gap-3"> - <.icon name="document" class="size-5 text-zinc-400" /> -
-

Documentation

-

View the complete documentation

-
- <.badge class="ml-auto">New - - <:panel>Detailed documentation content... - - -``` - -#### Custom Animation and No Icon -```heex -<.accordion animation_duration={500}> - <.accordion_item icon={false}> - <:header>Custom Header Without Chevron - <:panel>No chevron icon is shown for this item - - -``` - -## Alert - -The Alert component displays status messages, notifications, and interactive feedback with various visual styles and interactive elements. - -### Attributes -- `id` (string, optional): Unique identifier for the alert element -- `class` (any, optional): Additional CSS classes for the alert element -- `title` (string, optional): Main heading text of the alert -- `subtitle` (string, optional): Secondary text displayed alongside the title -- `color` (string, default: "default"): Visual style color - "default", "primary", "danger", "success", "info", "warning" -- `hide_icon` (boolean, default: false): Hide the alert's status icon -- `hide_close` (boolean, default: false): Hide the alert's close button -- `on_close` (JS, default: %JS{}): LiveView JS commands to execute when closed - -### Slots -- `inner_block` (optional): Main content displayed in the alert body -- `icon` (optional): Custom icon to replace the default status icon - -### Usage Examples - -#### Basic Alert with Colors -```heex -<.alert>Simple alert message - -<.alert color="info" title="Update Available"> - A new version of the application is ready to install. - - -<.alert color="success" title="Order Confirmed"> - Your order has been successfully processed. - - -<.alert color="warning" title="Session Expiring"> - Your session will expire in 5 minutes. - - -<.alert color="danger" title="Connection Lost"> - Unable to connect to the server. - -``` - -#### Alert with Actions -```heex -<.alert - color="warning" - title="Unsaved Changes" - on_close={JS.push("dismiss_warning")}> - You have unsaved changes that will be lost. - -
- <.button size="xs">Save Changes - <.button size="xs" color="ghost">Discard -
- -``` - -#### Non-dismissible and Custom Icon -```heex -<.alert hide_close> - This alert cannot be dismissed - - -<.alert> - <:icon> - <.icon name="hero-bell" class="size-5" /> - - Custom notification icon - -``` - -## Autocomplete - -The Autocomplete component provides a text input that filters a list of options as the user types, with keyboard navigation and accessibility features. It supports both client-side and server-side search capabilities. - -### Attributes -- `id` (any, optional): Unique identifier for the autocomplete component -- `name` (any): Form name for the autocomplete (required when not using `field`) -- `field` (Phoenix.HTML.FormField, optional): Form field to bind to -- `class` (any, optional): Additional CSS classes for the field wrapper element -- `label` (string, optional): Primary label for the autocomplete -- `sublabel` (string, optional): Additional context displayed beside the main label -- `help_text` (string, optional): Help text displayed below the autocomplete -- `description` (string, optional): Description displayed below the label -- `placeholder` (string, optional): Text to display when input is empty -- `autofocus` (boolean, default: false): Whether input should have autofocus -- `disabled` (boolean, default: false): Disable the autocomplete component -- `size` (string, default: "md"): Size variant - "xs", "sm", "md", "lg", "xl" -- `search_threshold` (integer, default: 0): Minimum characters before showing suggestions -- `no_results_text` (string, default: "No results found for \"%{query}\"."): Text for no results -- `on_search` (string, optional): LiveView event name for server-side search -- `debounce` (integer, default: 200): Debounce time in milliseconds for server-side searches -- `search_mode` (string, default: "contains"): Search mode - "contains", "starts-with", "exact" -- `open_on_focus` (boolean, default: false): Open listbox when input is focused -- `value` (any, optional): Current selected value -- `errors` (list, default: []): List of error messages -- `options` (list, required): List of options in various formats -- `clearable` (boolean, default: false): Show clear button to remove selection -- `rest`: Additional HTML attributes - -### Slots -- `inner_prefix` (optional): Content inside input field before text -- `outer_prefix` (optional): Content outside and before input field -- `inner_suffix` (optional): Content inside input field after text -- `outer_suffix` (optional): Content outside and after input field -- `option` (optional): Custom option rendering slot -- `empty_state` (optional): Custom empty state rendering -- `header` (optional): Custom header content for listbox -- `footer` (optional): Custom footer content for listbox - -### Usage Examples - -#### Basic and Form Integration -```heex -<.autocomplete - name="country" - options={[{"United States", "us"}, {"Canada", "ca"}]} - placeholder="Search countries..." -/> - -<.form :let={f} for={@changeset} phx-change="validate" phx-submit="save"> - <.autocomplete - field={f[:user_id]} - label="Assigned To" - options={@users} - /> - -``` - -#### Different Option Formats -```heex - -<.autocomplete - name="fruits" - options={["Apple", "Banana", "Cherry"]} - placeholder="Search fruits..." -/> - - -<.autocomplete - name="products" - options={[ - {"Fruits", [{"Apple", "apple"}, {"Banana", "banana"}]}, - {"Vegetables", [{"Carrot", "carrot"}, {"Broccoli", "broccoli"}]} - ]} - placeholder="Search products..." -/> -``` - -#### Size Variants and Labels -```heex -<.autocomplete name="sm" size="sm" placeholder="Small" options={@options} /> -<.autocomplete name="lg" size="lg" placeholder="Large" options={@options} /> - -<.autocomplete - name="language" - label="Programming Language" - sublabel="Required" - description="Choose the web framework for your project" - help_text="Choose from our supported platforms" - placeholder="Select your favorite..." - options={["Elixir", "Phoenix", "LiveView"]} -/> -``` - -#### Affixes and Search Features -```heex - -<.autocomplete name="user_search" options={@users} placeholder="Search users..."> - <:inner_prefix> - <.icon name="hero-magnifying-glass" class="size-4" /> - - - - -<.autocomplete - name="movie" - options={@movies} - on_search="search_movies" - search_threshold={2} - clearable - placeholder="Type to search movies..." -/> -``` - -#### Custom Option Rendering -```heex -<.autocomplete - name="users" - placeholder="Search team members..." - options={[{"John Doe", "john"}, {"Jane Smith", "jane"}]} -> - <:option :let={{label, value}}> -
-
- {String.first(label)} -
-
-
{label}
-
@{value}
-
-
- - -``` - -## Badge - -The Badge component provides versatile visual markers for status indicators, categories, and notification counts with semantic colors, size variants, and visual styles. - -### Attributes -- `class` (any, optional): Additional CSS classes for the badge element -- `color` (string, default: "primary"): Semantic color - "primary", "info", "success", "warning", "danger" -- `size` (string, default: "md"): Size variant - "xs", "sm", "md", "lg", "xl" -- `variant` (string, default: "surface"): Visual style - "solid", "soft", "surface", "outline", "dashed", "ghost" -- `rest`: Additional HTML attributes - -### Slots -- `inner_block` (required): Content displayed within the badge (text, icons, or both) - -### Usage Examples - -#### Colors and Variants -```heex -<.badge>Default Badge -<.badge color="success">Active -<.badge color="danger" size="lg">Error -<.badge variant="ghost" color="info">Draft - -<.badge variant="solid" color="success">High Emphasis -<.badge variant="soft" color="info">Medium Emphasis -<.badge variant="outline" color="primary">Outline -``` - -#### Size Variants -```heex -<.badge size="xs">Extra Small -<.badge size="sm">Small -<.badge size="lg">Large -``` - -#### With Icons and Interactive -```heex -<.badge color="success"> - <.icon name="hero-check-circle" class="icon" /> Verified - - - -<.badge - color={if @selected, do: "primary", else: "info"} - variant={if @selected, do: "solid", else: "dashed"} - phx-click="toggle_selection" - class="cursor-pointer" -> - <.icon :if={@selected} name="hero-check" class="icon" /> - Category - -``` - -## Button - -The Button component provides consistent, accessible, and visually appealing interactive elements for actions and navigation. It automatically renders either a ` - - <.dropdown_button>Profile - <.dropdown_button>Settings - - -<.dropdown class="w-64"> - <.dropdown_custom class="flex items-center p-2"> - Avatar -
- Emma Johnson - emma@acme.com -
- - - <.dropdown_separator /> - - <.dropdown_header>Account - <.dropdown_link navigate={~p"/profile"}>Profile - <.dropdown_link navigate={~p"/billing"}>Billing - -``` - -#### Hover Interaction and Button Actions -```heex -<.dropdown open_on_hover hover_open_delay={200} hover_close_delay={300}> - <.dropdown_link navigate={~p"/profile"}>Profile - <.dropdown_link navigate={~p"/settings"}>Settings - - -<.dropdown> - <.dropdown_button phx-click="export_data">Export Data - <.dropdown_button phx-click="import_data">Import Data - <.dropdown_separator /> - <.dropdown_button phx-click="delete_all" phx-confirm="Are you sure?"> - Delete All - - -``` - -## Input - -The Input component provides versatile text input fields with support for various types, sizes, form integration, and customizable prefix/suffix content both inside and outside the input field. - -### Components -- `input`: Main text input component -- `input_group`: Container for visually grouping multiple related inputs - -### Attributes - -#### input -- `id` (any, optional): HTML id attribute for the input element -- `name` (any): Form name for the input (required when not using `field`) -- `field` (Phoenix.HTML.FormField, optional): Form field to bind to -- `value` (any, optional): Current input value -- `type` (string, default: "text"): HTML input type -- `label` (string, optional): Primary label for the input -- `sublabel` (string, optional): Additional context beside the main label -- `description` (string, optional): Detailed description below the label -- `help_text` (string, optional): Help text displayed below the input -- `placeholder` (string, optional): Placeholder text -- `size` (string, default: "md"): Size variant - "xs", "sm", "md", "lg", "xl" -- `disabled` (boolean, default: false): Disable the input -- `readonly` (boolean, optional): Make input readonly -- `errors` (list, default: []): List of error messages -- `class` (any, optional): Additional CSS classes -- `rest`: Additional HTML attributes - -#### input_group -- `class` (any, optional): Additional CSS classes for the group container -- `label` (string, optional): Primary label for the input group -- `sublabel` (string, optional): Additional context beside the main label -- `description` (string, optional): Detailed description of the input group -- `help_text` (string, optional): Help text displayed below the group -- `rest`: Additional HTML attributes - -### Slots - -#### input -- `inner_prefix` (optional): Content inside the input border, before the text -- `outer_prefix` (optional): Content outside and before the input field -- `inner_suffix` (optional): Content inside the input border, after the text -- `outer_suffix` (optional): Content outside and after the input field - -#### input_group -- `inner_block` (required): Input elements and controls to be grouped - -### Usage Examples - -#### Basic Input and Size Variants -```heex -<.input name="username" label="Username" placeholder="Enter username..." /> -<.input name="password" type="password" label="Password" /> -<.input name="email" type="email" label="Email" /> - -<.input name="input_sm" size="sm" placeholder="Small" /> -<.input name="input_lg" size="lg" placeholder="Large" /> -<.input name="input_xl" size="xl" placeholder="Extra Large" /> -``` - -#### Complete Labeling and Form Integration -```heex -<.input - name="full_example" - label="Email Address" - sublabel="(required)" - description="We'll send a confirmation link here." - help_text="We never share your email." - placeholder="you@example.com" -/> - -<.form :let={f} for={@form}> - <.input field={f[:email]} type="email" label="Email" /> - <.input field={f[:password]} type="password" label="Password" /> - -``` - -#### Input States and Types -```heex - -<.input name="disabled_input" value="Cannot change" disabled /> -<.input name="readonly_input" value="Readonly value" readonly /> - - -<.input type="date" name="date_input" label="Appointment Date" /> -<.input type="number" name="count" label="Quantity" min="1" max="10" /> -<.input type="search" name="site_search" placeholder="Search site..." /> -``` - -#### Inner Affixes -```heex - -<.input name="email_icon" placeholder="user@example.com"> - <:inner_prefix> - <.icon name="hero-at-symbol" class="icon" /> - - - - -<.input name="password_toggle" type="password" value="secretpassword"> - <:inner_suffix> - <.button variant="ghost" size="icon-sm" title="Show password"> - <.icon name="hero-eye" class="icon" /> - - - - - -<.input name="url_prefix" placeholder="yourdomain.com"> - <:inner_prefix class="pointer-events-none text-zinc-500">https://www. - -``` - -#### Outer Affixes -```heex - -<.input name="invite_user" placeholder="user@example.com"> - <:inner_prefix> - <.icon name="hero-at-symbol" class="icon" /> - - <:outer_suffix> - <.button variant="solid" color="primary"> - <.icon name="hero-paper-airplane" class="icon" /> Invite - - - - - -<.input name="website_url" placeholder="mysite"> - <:outer_prefix class="px-2 text-zinc-500">https:// - <:outer_suffix class="px-2 text-zinc-500">.example.com - -``` - -#### Input Groups -```heex - -<.input_group label="Full Name"> - <.input name="first_name" placeholder="First Name" /> - <.input name="last_name" placeholder="Last Name" /> - - - -<.input_group label="Price Range"> - <.input name="min_price" placeholder="Min price"> - <:inner_prefix>$ - -
- to -
- <.input name="max_price" placeholder="Max price"> - <:inner_prefix>$ - - -``` - -## Loading - -The Loading component provides versatile animated loading indicators for displaying loading states with multiple animation styles and customization options. - -### Attributes -- `class` (any, optional): Additional CSS classes for customizing size and color (default: size-5, text-zinc-600) -- `duration` (integer, default: 600): Duration of one complete animation cycle in milliseconds -- `variant` (string, default: "ring"): Animation style - "ring", "ring-bg", "dots-bounce", "dots-fade", "dots-scale" -- `rest`: Additional HTML attributes - -### Usage Examples - -#### Animation Variants -```heex -<.loading /> -<.loading variant="ring-bg" /> -<.loading variant="dots-bounce" /> -<.loading variant="dots-fade" /> -<.loading variant="dots-scale" /> -``` - -#### Size and Color Variations -```heex -<.loading class="size-4" /> -<.loading class="size-8" /> -<.loading class="size-12" /> - -<.loading class="text-blue-500" /> -<.loading class="text-green-500" /> -<.loading class="text-red-500" /> -``` - -#### Button Loading States -```heex -<.button disabled> - <.loading class="size-4" /> Loading... - - -<.button variant="solid" color="primary" disabled> - <.loading class="size-4 text-white" /> Processing - -``` - -#### Page and Section Loading -```heex - -
- <.loading class="size-8" /> -
- - -
-
- <.loading class="size-6" /> -
- -
- - -

Processing your request <.loading class="size-4 inline" variant="dots-bounce" />

-``` - -## Modal - -The Modal component provides a powerful and accessible modal overlay for displaying focused content with LiveView integration, supporting both client-side and server-side control. - -### Attributes -- `id` (string, required): Unique identifier for the modal component -- `open` (boolean, default: false): Whether the modal is initially open -- `on_close` (JS, optional): JavaScript commands to execute when the modal closes -- `on_open` (JS, optional): JavaScript commands to execute when the modal opens -- `class` (any, optional): Additional CSS classes for the modal content container -- `container_class` (any, optional): CSS classes for the outer modal container -- `close_on_esc` (boolean, default: true): Whether pressing ESC closes the modal -- `close_on_outside_click` (boolean, default: true): Whether clicking outside closes the modal -- `prevent_closing` (boolean, default: false): Prevent all client-side closing behaviors -- `hide_close_button` (boolean, default: false): Hide the default close button -- `animation` (string, default: "transition duration-300 ease-out"): Animation classes -- `animation_enter` (string, default: "opacity-100 scale-100"): Enter animation classes -- `animation_leave` (string, default: "opacity-0 scale-95"): Leave animation classes -- `backdrop_class` (string, optional): Custom classes for the modal backdrop -- `placement` (string, default: "center"): Modal positioning on screen -- `rest`: Additional HTML attributes - -### Slots -- `inner_block` (required): Content displayed within the modal - -### Usage Examples - -#### Basic Modal -```heex -<.button phx-click={Fluxon.open_dialog("basic-modal")}>Open Modal - -<.modal id="basic-modal"> -
-

Modal Title

-

This is the modal content.

- -
- <.button phx-click={Fluxon.close_dialog("basic-modal")}>Close -
-
- -``` - -#### Server-Side Control -```heex -<.button phx-click="show_modal">Open Server Modal - -<.modal id="server-modal" open={@show_modal} on_close={JS.push("hide_modal")}> -
-

Server Controlled Modal

-

This modal is controlled by server state.

- <.button phx-click="hide_modal" class="mt-4">Close -
- - - -<.modal id="secure-modal" open={@show_secure_modal} prevent_closing> -
-

Critical Operation

-

This modal can only be closed through server commands.

- <.button phx-click="hide_secure_modal" color="danger" class="mt-4"> - Complete Action - -
- -``` - -#### Custom Styling and Form Modal -```heex - -<.modal - id="large-modal" - class="w-full max-w-4xl max-h-[80vh] overflow-auto" - container_class="p-4" -> -
-

Large Modal

-

This modal has custom sizing and scrolling behavior.

-
- - - -<.modal id="form-modal" on_close={JS.push("reset_form")}> -
-

Create User

- - <.form :let={f} for={@changeset} phx-change="validate" phx-submit="create_user"> - <.input field={f[:name]} label="Full Name" /> - <.input field={f[:email]} type="email" label="Email" /> - -
- <.button type="submit" disabled={!@changeset.valid?}> - Create User - - <.button - type="button" - variant="outline" - phx-click={Fluxon.close_dialog("form-modal")} - > - Cancel - -
- -
- -``` - -#### Confirmation Modal -```heex -<.modal id="confirm-delete" class="w-96"> -
-
- <.icon name="hero-exclamation-triangle" class="size-6 text-red-600" /> -
- -

Delete Item

-

- Are you sure you want to delete this item? This action cannot be undone. -

- -
- <.button - color="danger" - phx-click="confirm_delete" - phx-value-id={@delete_item_id} - > - Delete - - <.button - variant="outline" - phx-click={Fluxon.close_dialog("confirm-delete")} - > - Cancel - -
-
- -``` - -## Navlist - -The Navlist component provides a comprehensive navigation system for building structured, accessible navigation menus with support for sections, headings, and interactive links. - -### Components -- `navlist`: Main navigation container that provides structure and spacing -- `navheading`: Optional section headers for organizing navigation groups -- `navlink`: Interactive navigation items with LiveView integration - -### Attributes - -#### navlist -- `heading` (string, optional): Primary heading for the navigation section -- `class` (any, optional): Additional CSS classes for the navigation container -- `rest`: Additional HTML attributes for the nav container - -#### navheading -- `class` (any, optional): Additional CSS classes for the heading element -- `rest`: Additional HTML attributes - -#### navlink -- `class` (any, optional): Additional CSS classes for the navigation link -- `active` (boolean, default: false): Whether this navigation item is currently active -- `rest`: Additional HTML attributes (supports navigation attributes like `navigate`, `patch`, `href`, etc.) - -### Slots - -#### navlist -- `inner_block` (required): Navigation items and headings - -#### navheading -- `inner_block` (required): Heading content - -#### navlink -- `inner_block` (required): Link content (text, icons, badges, etc.) - -### Usage Examples - -#### Basic Navigation -```heex -<.navlist heading="Main Navigation"> - <.navlink navigate={~p"/dashboard"} active> - <.icon name="hero-home" class="size-5" /> Dashboard - - <.navlink navigate={~p"/projects"}> - <.icon name="hero-folder" class="size-5" /> Projects - - <.navlink navigate={~p"/settings"}> - <.icon name="hero-cog-6-tooth" class="size-5" /> Settings - - -``` - -#### Multiple Sections -```heex -<.navlist heading="Main"> - <.navlink navigate={~p"/dashboard"} active> - <.icon name="hero-home" class="size-5" /> Dashboard - - <.navlink navigate={~p"/projects"}> - <.icon name="hero-folder" class="size-5" /> Projects - - - -<.navlist heading="Settings"> - <.navlink navigate={~p"/profile"}> - <.icon name="hero-user" class="size-5" /> Profile - - <.navlink navigate={~p"/preferences"}> - <.icon name="hero-cog-6-tooth" class="size-5" /> Preferences - - -``` - -#### Navigation with Badges -```heex -<.navlist heading="Inbox"> - <.navlink navigate={~p"/inbox/unread"}> - <.icon name="hero-envelope" class="size-5" /> - Unread - <.badge variant="solid" color="danger" class="ml-auto">23 - - - <.navlink navigate={~p"/inbox/starred"}> - <.icon name="hero-star" class="size-5" /> - Starred - <.badge variant="soft" color="warning" class="ml-auto">5 - - -``` - -#### External Links and Actions -```heex -<.navlist heading="Resources"> - <.navlink href="https://docs.example.com" target="_blank"> - <.icon name="hero-document-text" class="size-5" /> - Documentation - <.icon name="hero-arrow-top-right-on-square" class="size-4 ml-auto text-gray-400" /> - - - -<.navlist heading="Actions"> - <.navlink phx-click="export_data"> - <.icon name="hero-arrow-down-tray" class="size-5" /> - Export Data - - - <.navlink phx-click="refresh_data"> - <.icon name="hero-arrow-path" class="size-5" /> - Refresh - - -``` - -## Popover - -A powerful and accessible popover component that displays floating content anchored to a trigger element. - -### Attributes -- `id` (string, default: auto-generated): Optional unique identifier for the popover -- `target` (string, default: nil): CSS selector of an external element to use as positioning reference -- `class` (any, default: nil): Additional CSS classes for the popover content container -- `open_on_hover` (boolean, default: false): Opens popover on hover for tooltip-like behavior -- `open_on_focus` (boolean, default: false): Opens popover when trigger receives focus -- `placement` (string, default: "top"): Popover position - "top", "top-start", "top-end", "right", "right-start", "right-end", "left", "left-start", "left-end", "bottom", "bottom-start", "bottom-end" - -### Slots -- `inner_block`: The trigger element that will open the popover (optional when using target) -- `content` (required): The content to display in the popover - -### Usage Examples - -#### Basic Tooltip -```heex -<.popover open_on_hover> - <.icon name="hero-information-circle" class="text-zinc-400" /> - - <:content> -

The invoice will be generated at the end of the month.

- - -``` - -#### Interactive Menu and Form Help -```heex -<.popover placement="bottom-end" class="w-64"> - <.button variant="ghost"> - <.icon name="hero-cog-6-tooth" /> Settings - - - <:content> -
-
- Dark Mode - <.switch name="dark_mode" checked /> -
- <.button size="sm" class="w-full"> - Reset Preferences - -
- - - -<.input name="api-key" label="API Key" value="sk_test_..." class="font-mono"> - <:inner_suffix> - <.popover open_on_hover placement="right"> - <.icon name="hero-question-mark-circle" class="text-zinc-400" /> - - <:content> -
-

About API Keys

-

- Your API key is used to authenticate requests. Keep it secure. -

-
- - - - -``` - -#### Search Suggestions -```heex -<.popover open_on_focus placement="bottom-start" class="w-80"> - <.input type="search" placeholder="Search users..." phx-debounce="300" /> - - <:content> -
- <.loading /> -
-
-
{user.name}
-
{user.email}
-
- - -``` - -## Radio - -A versatile radio component for building single-selection interfaces with rich styling options. - -### Attributes -- `id` (any, default: nil): The unique identifier for the radio group -- `name` (string, required when not using field): The form name for the radio group -- `value` (any): The current selected value of the radio group -- `label` (string, default: nil): The primary label for the radio group -- `sublabel` (string, default: nil): Additional context displayed beside the main label -- `description` (string, default: nil): Detailed description below the label -- `errors` (list, default: []): List of error messages -- `class` (any, default: nil): Additional CSS classes for the radio group container -- `field` (Phoenix.HTML.FormField): The form field to bind to -- `disabled` (boolean, default: false): Disables all radio buttons in the group -- `variant` (string, default: nil): Visual variant - nil (default) or "card" -- `control` (string): Controls radio position in card variants - "left" or "right" -- `rest` (global): Additional attributes - -### Slots -- `radio` (required): Defines individual radio buttons with attributes: `value`, `label`, `sublabel`, `description`, `disabled`, `class`, `checked` - -### Usage Examples - -#### Basic Radio Group -```heex -<.radio_group name="system" value="debian" label="Operating System"> - <:radio value="ubuntu" label="Ubuntu" /> - <:radio value="debian" label="Debian" /> - <:radio value="fedora" label="Fedora" /> - -``` - -#### With Context and Form Integration -```heex -<.radio_group - name="system" - label="Operating System" - sublabel="Choose your preferred OS" - description="Select the operating system that best suits your needs" -> - <:radio - value="ubuntu" - label="Ubuntu" - sublabel="Popular and user-friendly" - description="Ubuntu is a Debian-based Linux operating system" - /> - <:radio - value="debian" - label="Debian" - sublabel="Stable and reliable" - description="Debian is composed of free and open-source software" - /> - - -<.form :let={f} for={@form} phx-change="validate" phx-submit="save"> - <.radio_group - field={f[:subscription]} - label="Subscription Plan" - description="Choose your preferred subscription plan" - > - <:radio value="basic" label="Basic Plan" sublabel="$10/month" /> - <:radio value="pro" label="Pro Plan" sublabel="$20/month" /> - <:radio value="enterprise" label="Enterprise Plan" sublabel="$50/month" /> - - -``` - -#### Card Variant -```heex -<.radio_group - name="plan" - label="Choose a plan" - description="Choose the plan that best suits your needs." - variant="card" - control="left" - class="gap-0" -> - <:radio value="basic" label="Basic" sublabel="Perfect for small projects" class="rounded-none -my-px rounded-t-lg" /> - <:radio value="pro" label="Professional" checked sublabel="Most popular for growing teams" class="rounded-none -my-px" /> - <:radio value="business" label="Business" sublabel="Advanced features for larger teams" class="rounded-none -my-px rounded-b-lg" /> - - -<.radio_group name="category" label="Category" variant="card" class="grid grid-cols-3"> - <:radio value="web-design" class="flex-1 group has-checked:border-blue-500 has-checked:bg-blue-50"> -
- <.icon name="hero-computer-desktop" class="size-6 text-zinc-500 group-has-checked:text-blue-500" /> - Web Design -
- - <:radio value="ui-ux" class="flex-1 group has-checked:border-blue-500 has-checked:bg-blue-50"> -
- <.icon name="hero-pencil" class="size-6 text-zinc-500 group-has-checked:text-blue-500" /> - UI/UX Design -
- - -``` - -## Select - -A select component that implements a modern, accessible selection interface with support for single and multiple selections. - -### Attributes -- `id` (any, default: nil): The unique identifier for the select component -- `name` (any, required when not using field): The form name for the select -- `field` (Phoenix.HTML.FormField): The form field to bind to -- `native` (boolean, default: false): Renders a native HTML select element instead of custom select -- `class` (any, default: nil): Additional CSS classes for the select component -- `label` (string, default: nil): The primary label for the select -- `sublabel` (string, default: nil): Additional context beside the main label -- `help_text` (string, default: nil): Help text displayed below the select -- `description` (string, default: nil): Description below the label but above select -- `placeholder` (string, default: nil): Text displayed when no option is selected -- `searchable` (boolean, default: false): Adds search input to filter options (custom select only) -- `disabled` (boolean, default: false): Disables the select component -- `size` (string, default: "md"): Controls select size - "xs", "sm", "md", "lg", "xl" -- `search_input_placeholder` (string, default: "Search..."): Placeholder for search input -- `search_no_results_text` (string, default: "No results found for %{query}."): No results text -- `search_threshold` (integer, default: 0): Minimum characters before filtering -- `debounce` (integer, default: 300): Debounce time for server searches -- `on_search` (string, default: nil): LiveView event name for server searches -- `multiple` (boolean, default: false): Allows selecting multiple options (not with native) -- `value` (any): Current selected value(s) -- `errors` (list, default: []): List of error messages -- `options` (list, required): List of options for the select -- `max` (integer, default: nil): Maximum selections when multiple -- `clearable` (boolean, default: false): Shows clear button -- `rest` (global): Additional attributes - -### Slots -- `option`: Optional slot for custom option rendering -- `toggle`: Optional slot for custom toggle rendering -- `header`: Optional slot for custom header content -- `footer`: Optional slot for custom footer content -- `inner_prefix`: Content inside select field before value display -- `outer_prefix`: Content outside and before select field -- `inner_suffix`: Content inside select field after value display -- `outer_suffix`: Content outside and after select field - -### Usage Examples - -#### Basic and Full-featured Select -```heex -<.select - name="country" - options={[{"United States", "US"}, {"Canada", "CA"}]} -/> - -<.select - name="payment_method" - label="Payment Method" - sublabel="Select payment type" - description="Choose your preferred payment method" - help_text="We securely process all payment information" - placeholder="Select payment method" - options={[ - {"Credit Card", "credit_card"}, - {"PayPal", "paypal"}, - {"Bank Transfer", "bank_transfer"} - ]} -/> -``` - -#### Native, Searchable and Multiple -```heex -<.select - name="country" - native - options={[{"United States", "US"}, {"Canada", "CA"}]} -/> - -<.select - name="country" - searchable - search_input_placeholder="Search for a country" - search_no_results_text="No countries found for %{query}" - options={@countries} -/> - -<.select - name="countries" - multiple - max={3} - clearable - options={[{"United States", "US"},{"Canada", "CA"},{"Mexico", "MX"}]} -/> -``` - -#### Form Integration and Affixes -```heex -<.form :let={f} for={@changeset} phx-change="validate" phx-submit="save"> - <.select - field={f[:country]} - label="Country" - options={@countries} - /> - - -<.select name="category" options={@categories} placeholder="Select category"> - <:inner_prefix> - <.icon name="hero-folder" class="icon" /> - - <:outer_suffix> - <.button size="md">Apply - - -``` - -#### Custom Option Rendering -```heex -<.select - name="role" - placeholder="Select role" - options={[{"Admin", "admin"}, {"Editor", "editor"}, {"Viewer", "viewer"}]} -> - <:option :let={{label, value}}> -
-
-
{label}
-
- {case value do - "admin" -> "Full access to all features" - "editor" -> "Can create and modify content" - "viewer" -> "Read-only access to content" - end} -
-
- <.icon :if={value == "admin"} name="hero-shield-check" class="size-4 text-blue-500" /> -
- - -``` - -## Separator - -A versatile separator component for creating visual boundaries between content sections. - -### Attributes -- `text` (string, default: nil): Optional text to display in the center of the separator -- `vertical` (boolean, default: false): Renders a vertical separator instead of horizontal -- `class` (any, default: nil): Additional CSS classes - -### Usage Examples - -#### Basic Separators -```heex -
Content above
-<.separator /> -
Content below
- -
- Left - <.separator vertical /> - Right -
- -<.separator text="or" /> -<.separator text="Section" class="my-6" /> -``` - -#### Form and Navigation Usage -```heex -
- <.input name="email" type="email" placeholder="Email" /> - <.input name="password" type="password" placeholder="Password" /> - <.button type="submit" class="w-full">Sign In - - <.separator text="or" /> - - <.button type="button" variant="outline" class="w-full"> - Sign in with Google - -
- -
- Profile - <.separator vertical /> - Settings - <.separator vertical /> - Logout -
-``` - -## Sheet - -A powerful and accessible sheet component that provides a sliding panel interface for displaying content from screen edges. - -### Attributes -- `id` (string, required): The unique identifier for the sheet component -- `open` (boolean, default: false): Whether the sheet is initially open -- `on_close` (JS, default: %JS{}): JavaScript commands to execute when sheet closes -- `on_open` (JS, default: %JS{}): JavaScript commands to execute when sheet opens -- `class` (any, default: ""): Additional CSS classes for sheet content container -- `close_on_esc` (boolean, default: true): Whether to close sheet when Escape is pressed -- `close_on_outside_click` (boolean, default: true): Whether to close when clicking outside -- `prevent_closing` (boolean, default: false): Prevents sheet from being closed through standard interactions -- `hide_close_button` (boolean, default: false): Whether to hide the close button -- `animation` (string, default: "transition duration-200 ease-in-out"): Base animation classes -- `animation_enter` (string): Classes applied when sheet enters (auto-set based on placement) -- `animation_leave` (string): Classes applied when sheet leaves (auto-set based on placement) -- `backdrop_class` (string, default: ""): Additional CSS classes for backdrop overlay -- `placement` (string, default: "left"): Edge the sheet slides from - "left", "right", "top", "bottom" - -### Slots -- `inner_block` (required): The content of the sheet - -### Usage Examples - -#### Basic Client-Side Control -```heex -<.button phx-click={Fluxon.open_dialog("filters-sheet")}>Filters - -<.sheet id="filters-sheet"> -

Filters

- -
- -
- - <.button phx-click={Fluxon.close_dialog("filters-sheet")}>Apply - -``` - -#### Server-Side Control -```heex -<.button phx-click="show-sheet">Open Filters - -<.sheet id="filters-sheet" open={@show_filters}> -

Server-controlled Sheet

- - - -<.sheet - id="filters-sheet" - open={@show_filters} - on_close={JS.push("hide_filters")} -> -

Filters with State Sync

- -``` - -#### Different Placements -```heex - -<.sheet id="nav-sheet" placement="left" class="w-80"> - - - - -<.sheet id="details-sheet" placement="right" class="w-96"> -

Details

-

Detailed information goes here.

- - - -<.sheet id="actions-sheet" placement="bottom" class="h-96"> -
- <.button class="w-full">Share - <.button class="w-full">Copy Link - <.button class="w-full">Delete -
- -``` - -#### Form in Sheet -```heex -<.sheet id="new-user-sheet" placement="right" class="w-96"> - <.form for={@form} phx-submit="save_user"> -
-
-

New User

-

Create a new user account.

-
- - <.input field={@form[:name]} label="Name" /> - <.input field={@form[:email]} type="email" label="Email" /> - -
- <.button phx-click={Fluxon.close_dialog("new-user-sheet")}> - Cancel - - <.button type="submit" phx-disable-with="Creating..."> - Create User - -
-
- - -``` - -## Switch - -A toggle switch component for binary choices and settings with immediate effect. - -### Attributes -- `id` (any, default: nil): The unique identifier for the switch -- `name` (string, required when not using field): The form name for the switch -- `class` (any, default: nil): Additional CSS classes for the switch wrapper -- `checked` (boolean): Whether the switch is in the on position -- `disabled` (boolean, default: false): Disables the switch -- `value` (any): The value associated with the switch -- `label` (string, default: nil): The primary label for the switch -- `sublabel` (string, default: nil): Additional context beside the main label -- `description` (string, default: nil): Detailed description below the label -- `size` (string, default: "md"): Controls switch size - "sm", "md", "lg" -- `color` (string, default: "primary"): Color theme when on - "primary", "danger", "success", "warning", "info" -- `field` (Phoenix.HTML.FormField): The form field to bind to -- `rest` (global): Additional attributes - -### Usage Examples - -#### Basic Switch and Size Variants -```heex -<.switch - name="notifications" - label="Enable Notifications" - checked={@settings.notifications} - phx-click="toggle_setting" - phx-value-setting="notifications" -/> - -<.switch name="small_switch" label="Small Switch" size="sm" checked={@settings.compact_mode} /> -<.switch name="large_switch" label="Large Switch" size="lg" checked={@settings.important_setting} /> -``` - -#### Labels and Context -```heex -<.switch name="simple" label="Enable Feature" checked={@feature_enabled} /> - -<.switch - name="with_sublabel" - label="Auto Save" - sublabel="Recommended" - checked={@settings.auto_save} -/> - -<.switch - name="comprehensive" - label="Advanced Analytics" - sublabel="Beta" - description="Share detailed usage patterns to help improve the product experience" - checked={@settings.analytics_enabled} -/> -``` - -#### Color Variants and Form Integration -```heex -<.switch name="primary" label="Default Setting" color="primary" checked={@settings.default} /> -<.switch name="success" label="Enable Backup" color="success" checked={@settings.backup_enabled} /> -<.switch name="danger" label="Public Profile" color="danger" checked={@settings.public_profile} /> - -<.form :let={f} for={@changeset} phx-change="validate" phx-submit="save"> - <.switch - field={f[:notifications_enabled]} - label="Push Notifications" - sublabel="Real-time updates" - description="Receive notifications about important account activity" - /> - - <.switch - field={f[:email_marketing]} - label="Email Marketing" - sublabel="Optional" - description="Receive promotional emails about new features" - /> - -``` - -#### Disabled States -```heex -<.switch - name="disabled_off" - label="Unavailable Feature" - description="This feature is currently unavailable" - disabled - checked={false} -/> - -<.switch - name="disabled_on" - label="Premium Feature" - sublabel="Upgrade required" - description="This feature requires a premium subscription" - disabled - checked={true} -/> -``` - -## Table - -A comprehensive table system for displaying structured data with rich customization options. - -### Components -- `table`: The main container providing structure and responsive behavior -- `table_head`: Header section with column definitions -- `table_body`: Content section containing rows of data -- `table_row`: Individual data rows with cell content - -### Attributes -- All components have `class` (optional) and `rest` attributes for customization - -### Slots - -#### table -- `inner_block` (required): Usually contains table_head and table_body components - -#### table_head -- `col` (required): Defines table columns rendered as th elements - -#### table_body -- `inner_block` (required): Usually contains table_row components - -#### table_row -- `cell` (required): Defines table cells with custom content and styling - -### Usage Examples - -#### Basic Table -```heex -<.table> - <.table_head> - <:col>Name - <:col>Status - <:col>Email - - - <.table_body> - <.table_row> - <:cell>Alice Smith - <:cell>New - <:cell>alice@example.com - - <.table_row> - <:cell>Bob Johnson - <:cell>In Progress - <:cell>bob@example.com - - - -``` - -#### Rich Content Table -```heex -<.table> - <.table_head> - <:col>Lead - <:col>Stage - <:col>Contact - <:col> - - <.table_body> - <.table_row> - <:cell class="w-full flex items-center gap-2"> - -
- Sarah Johnson - Product Manager -
- - <:cell> - <.badge color="green">Active - - <:cell>sarah.j@example.com - <:cell> - <.icon name="hero-ellipsis-horizontal" class="size-5" /> - - - - -``` - -#### Sortable Columns and Clickable Rows -```heex -<.table> - <.table_head> - <:col phx-click="sort" phx-value-column="name"> -
- Lead <.icon name="hero-chevron-up-down" class="size-4 text-zinc-500" /> -
- - <:col phx-click="sort" phx-value-column="stage"> -
- Stage <.icon name="hero-chevron-up-down" class="size-4 text-zinc-500" /> -
- - - <.table_body> - <.table_row> - <:cell>John Smith - <:cell>New Lead - - - - -<.table> - <.table_head> - <:col>Customer - <:col>Status - <:col>Last Order - - - <.table_body> - <.table_row - :for={customer <- @customers} - class="cursor-pointer hover:bg-zinc-50" - phx-click="show_customer" - phx-value-id={customer.id} - > - <:cell> -
- - {customer.name} -
- - <:cell><.badge color="green">Active - <:cell>{customer.last_order_date} - - - -``` - -#### Data Table with Actions -```heex -<.table> - <.table_head> - <:col>User - <:col>Role - <:col>Status - <:col>Actions - - - <.table_body> - <.table_row :for={user <- @users}> - <:cell> -
- -
-
{user.name}
-
{user.email}
-
-
- - <:cell> - - {user.role} - - - <:cell> - <.badge color={if user.active, do: "green", else: "red"}> - {if user.active, do: "Active", else: "Inactive"} - - - <:cell> -
- <.button size="sm" variant="ghost" phx-click="edit_user" phx-value-id={user.id}> - Edit - - <.button size="sm" variant="ghost" color="danger" phx-click="delete_user" phx-value-id={user.id}> - Delete - -
- - - - -``` - -#### Empty State Table -```heex -<.table> - <.table_head> - <:col>Name - <:col>Email - <:col>Status - - - <.table_body> - <.table_row :if={Enum.empty?(@users)}> - <:cell colspan="3" class="text-center py-12 text-zinc-500"> -
- <.icon name="hero-users" class="size-12 text-zinc-300" /> -
-

No users found

-

Get started by creating your first user.

-
- <.button size="sm" phx-click="new_user">Add User -
- - - - <.table_row :for={user <- @users}> - <:cell>{user.name} - <:cell>{user.email} - <:cell>{user.status} - - - -``` - -## Tabs - -A tabs system for creating accessible, interactive tabbed interfaces with keyboard navigation support. - -### Components -- `tabs`: The main container providing structure and JavaScript functionality -- `tabs_list`: Navigation container holding the interactive tab buttons -- `tabs_panel`: Content panels associated with each tab, displayed one at a time - -### Attributes - -#### tabs -- `id` (string): A unique identifier for the tabs container -- `class` (any, default: nil): Additional CSS classes for the tabs container -- `rest` (global): Additional HTML attributes - -#### tabs_list -- `class` (any, default: nil): Additional CSS classes for the tablist container -- `active_tab` (string): The name of the tab that should be initially active -- `variant` (string, default: "default"): The visual style variant - "default", "segmented", "ghost" -- `size` (string, default: "md"): The size of the tabs container - "xs", "sm", "md" - -#### tabs_panel -- `name` (string, required): The unique identifier for this panel -- `class` (any, default: nil): Additional CSS classes for the panel element -- `active` (boolean, default: false): Controls the visibility of the panel -- `rest` (global): Additional HTML attributes - -### Slots - -#### tabs -- `inner_block` (required): Typically contains one tabs_list and one or more tabs_panel components - -#### tabs_list -- `tab` (required): Defines an individual interactive tab button with required name attribute -- `inner_block` (required): Main content area containing the tab slots - -#### tabs_panel -- `inner_block` (required): The content displayed when corresponding tab is active - -### Usage Examples - -#### Basic Static Tabs -```heex -<.tabs id="my-tabs"> - <.tabs_list active_tab="settings"> - <:tab name="profile">Profile - <:tab name="settings">Settings - <:tab name="notifications">Notifications - - - <.tabs_panel name="profile"> - Profile content here... - - - <.tabs_panel name="settings" active> - Settings content here... - - - <.tabs_panel name="notifications"> - Notifications content here... - - -``` - -#### Visual Variants and Sizes -```heex - -<.tabs_list variant="default"> - <:tab name="tab1">Default Tab - - - -<.tabs_list variant="segmented"> - <:tab name="tab1">Segmented Tab - - - -<.tabs_list variant="ghost"> - <:tab name="tab1">Ghost Tab - - - -<.tabs_list size="xs"> - <:tab name="tab1">Extra Small Tab - - -<.tabs_list size="sm"> - <:tab name="tab1">Small Tab - -``` - -#### Rich Tab Content -```heex -<.tabs_list> - <:tab name="messages"> - <.icon name="hero-envelope" class="icon" /> - Messages - <.badge class="ml-2">3 - - - <:tab name="settings"> - <.icon name="hero-cog-6-tooth" class="icon" /> - Settings - - -``` - -#### LiveView Integration -```heex -<.tabs id="lv-sync-tabs"> - <.tabs_list active_tab={@active_tab}> - <:tab name="profile" phx-click={JS.push("set_active_tab", value: %{tab: "profile"})}> - Profile - - <:tab name="settings" phx-click={JS.push("set_active_tab", value: %{tab: "settings"})}> - Settings - - - - <.tabs_panel name="profile" active={@active_tab == "profile"}> - Profile content... - - <.tabs_panel name="settings" active={@active_tab == "settings"}> - Settings content... - - -``` - -#### Complex Form Tabs -```heex -<.tabs id="user-form-tabs"> - <.tabs_list active_tab={@active_tab} variant="segmented"> - <:tab name="basic" phx-click={JS.push("set_tab", value: %{tab: "basic"})}> - <.icon name="hero-user" class="icon" /> - Basic Info - - <:tab name="contact" phx-click={JS.push("set_tab", value: %{tab: "contact"})}> - <.icon name="hero-envelope" class="icon" /> - Contact - - - - <.tabs_panel name="basic" active={@active_tab == "basic"} class="space-y-4"> - <.input field={@form[:name]} label="Full Name" /> - <.input field={@form[:username]} label="Username" /> - - - <.tabs_panel name="contact" active={@active_tab == "contact"} class="space-y-4"> - <.input field={@form[:email]} type="email" label="Email" /> - <.input field={@form[:phone]} label="Phone Number" /> - - -``` - -## Textarea - -A versatile textarea component for capturing multi-line text input with form integration and size variants. - -### Attributes -- `id` (string, default: nil): The unique identifier for the textarea -- `field` (Phoenix.HTML.FormField): The form field to bind to -- `class` (any, default: nil): Additional CSS classes for the textarea -- `help_text` (string, default: nil): Optional help text displayed below the textarea -- `label` (string, default: nil): The primary label for the textarea -- `sublabel` (string, default: nil): Additional context beside the main label -- `description` (string, default: nil): Detailed description below the label -- `value` (string): The current value of the textarea -- `errors` (list, default: []): List of error messages -- `name` (string, required when not using field): The form name for the textarea -- `rows` (integer, default: 3): The number of visible text lines -- `disabled` (boolean, default: false): Disables the textarea -- `size` (string, default: "md"): Controls textarea size - "sm", "md", "lg", "xl" -- `rest` (global): Additional HTML attributes - -### Usage Examples - -#### Basic Textarea and Size Variants -```heex -<.textarea - name="description" - label="Description" - placeholder="Enter description..." -/> - -<.textarea name="description" label="Small" size="sm" placeholder="A compact textarea" /> -<.textarea name="description" label="Large" size="lg" placeholder="Larger textarea" /> -<.textarea name="description" label="Extra Large" size="xl" placeholder="Maximum emphasis" /> -``` - -#### With Labels and Form Integration -```heex -<.textarea - name="bio" - label="Biography" - help_text="Tell us about yourself" - rows={5} -/> - -<.form :let={f} for={@form} phx-change="validate" phx-submit="save"> - <.textarea - field={f[:description]} - label="Description" - help_text="Provide a detailed description of your project" - /> - - -<.form :let={f} for={@form} phx-change="validate"> - <.textarea - field={f[:description]} - label="Project Description" - sublabel="Optional" - description="Provide details about your project's goals and scope" - help_text="Be specific and concise" - rows={6} - /> - -``` - -#### Custom Styling and States -```heex -<.textarea - name="notes" - label="Meeting Notes" - size="lg" - class="font-mono" - rows={10} -/> - -<.textarea - name="readonly_field" - label="Read Only Field" - value="This content cannot be edited" - disabled -/> - -<.textarea - name="content" - label="Article Content" - rows={15} - maxlength={5000} - placeholder="Write your article content here..." - spellcheck="true" -/> -``` - -#### Rich Form Example -```heex -<.form :let={f} for={@form} phx-change="validate" phx-submit="save"> -
- <.textarea - field={f[:summary]} - label="Summary" - sublabel="Required" - rows={3} - maxlength={500} - help_text="Brief overview of the content" - /> - - <.textarea - field={f[:content]} - label="Full Content" - description="The main body of your article or post" - rows={12} - help_text="Use markdown formatting if needed" - /> - - <.textarea - field={f[:notes]} - label="Internal Notes" - sublabel="Optional" - size="sm" - rows={2} - help_text="Private notes for internal use" - /> -
- - <.button type="submit">Save Article - -``` - -## Tooltip - -A lightweight and accessible tooltip component for displaying informative content on hover or focus. - -### Attributes -- `id` (string, optional): Unique identifier for the tooltip -- `value` (string, optional): Text content for simple tooltips -- `class` (any, optional): Additional CSS classes for the tooltip container -- `arrow` (boolean, default: true): Whether to show the pointing arrow indicator -- `placement` (string, default: "top"): Tooltip position - "bottom", "left", "top", "right" -- `delay` (integer, default: 0): Delay in milliseconds before showing tooltip - -### Slots -- `inner_block` (required): The trigger element that shows tooltip on hover/focus -- `content` (optional): Rich content slot for complex tooltip content - -### Usage Examples - -#### Basic and Rich Content -```heex -<.tooltip value="Opens in a new window"> - <.button>Open - - -<.tooltip> - <.button>View details - - <:content> -
- -

Preview of the document layout and structure.

-
- - -``` - -#### Different Placements and Icon Tooltips -```heex -
- <.tooltip value="Top placement" placement="top"> - <.button>Top - - - <.tooltip value="Right placement" placement="right"> - <.button>Right - -
- -
- <.tooltip value="Share"> - <.button variant="ghost"><.icon name="hero-share" /> - - - <.tooltip value="Add to favorites"> - <.button variant="ghost"><.icon name="hero-star" /> - -
-``` - -#### Form Field Help and Custom Styling -```heex -
- <.input type="text" name="api_key" value=""> - <:inner_suffix> - <.tooltip value="Your API key can be found in the developer settings"> - <.icon name="hero-question-mark-circle" class="text-zinc-400" /> - - - -
- -<.tooltip - value="Draft saved" - class="bg-green-600 text-white" - arrow={false} -> - <.badge>Draft - - -<.tooltip value="Archived items are hidden from the main view" delay={300}> - <.icon name="hero-archive" class="text-zinc-400" /> - -``` - -#### User Profile Preview -```heex -<.tooltip class="max-w-xs"> - <.link navigate={"/users/#{@user.id}"}> - {@user.name} - - - <:content> -
-

{@user.name}

-

{@user.title}

-

{@user.department}

-
- - -``` - +@deps/fluxon/usage-rules.md diff --git a/mix.exs b/mix.exs index f5dc3208..4d633c5b 100644 --- a/mix.exs +++ b/mix.exs @@ -176,7 +176,15 @@ defmodule MusicLibrary.MixProject do defp usage_rules do [ file: "AGENTS.md", - usage_rules: :all + usage_rules: [ + :elixir, + :otp, + "phoenix:all", + :usage_rules, + "usage_rules:all", + # link fluxon as it's HUGE + {:fluxon, link: :at} + ] ] end end