snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
981
apps/v4/registry/bases/aria/examples/_registry.ts
Normal file
981
apps/v4/registry/bases/aria/examples/_registry.ts
Normal file
@@ -0,0 +1,981 @@
|
||||
import { type Registry } from "shadcn/schema"
|
||||
|
||||
export const examples: Registry["items"] = [
|
||||
{
|
||||
name: "accordion-example",
|
||||
title: "Accordion",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["accordion", "button", "card", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/accordion-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "alert-example",
|
||||
title: "Alert",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["alert", "badge", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/alert-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "alert-dialog-example",
|
||||
title: "Alert Dialog",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["alert-dialog", "button", "dialog", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/alert-dialog-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "aspect-ratio-example",
|
||||
title: "Aspect Ratio",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["aspect-ratio", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/aspect-ratio-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "avatar-example",
|
||||
title: "Avatar",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["avatar", "button", "empty", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/avatar-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "badge-example",
|
||||
title: "Badge",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["badge", "spinner", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/badge-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "breadcrumb-example",
|
||||
title: "Breadcrumb",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["breadcrumb", "dropdown-menu", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/breadcrumb-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "button-example",
|
||||
title: "Button",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/button-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "button-group-example",
|
||||
title: "Button Group",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"button-group",
|
||||
"dropdown-menu",
|
||||
"field",
|
||||
"input",
|
||||
"input-group",
|
||||
"label",
|
||||
"popover",
|
||||
"select",
|
||||
"tooltip",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/button-group-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "calendar-example",
|
||||
title: "Calendar",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"calendar",
|
||||
"card",
|
||||
"field",
|
||||
"input",
|
||||
"label",
|
||||
"popover",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/calendar-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "card-example",
|
||||
title: "Card",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"avatar",
|
||||
"button",
|
||||
"card",
|
||||
"field",
|
||||
"input",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/card-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "carousel-example",
|
||||
title: "Carousel",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["card", "carousel", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/carousel-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "chart-example",
|
||||
title: "Chart",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["chart", "card", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/chart-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "checkbox-example",
|
||||
title: "Checkbox",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["checkbox", "field", "table", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/checkbox-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "collapsible-example",
|
||||
title: "Collapsible",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"card",
|
||||
"collapsible",
|
||||
"field",
|
||||
"input",
|
||||
"tabs",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/collapsible-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "combobox-example",
|
||||
title: "Combobox",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"card",
|
||||
"combobox",
|
||||
"dialog",
|
||||
"field",
|
||||
"input",
|
||||
"input-group",
|
||||
"item",
|
||||
"select",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/combobox-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "command-example",
|
||||
title: "Command",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "command", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/command-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "context-menu-example",
|
||||
title: "Context Menu",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "context-menu", "dialog", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/context-menu-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "dialog-example",
|
||||
title: "Dialog",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"checkbox",
|
||||
"dialog",
|
||||
"field",
|
||||
"input",
|
||||
"input-group",
|
||||
"kbd",
|
||||
"native-select",
|
||||
"select",
|
||||
"switch",
|
||||
"tabs",
|
||||
"textarea",
|
||||
"tooltip",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/dialog-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "drawer-example",
|
||||
title: "Drawer",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["drawer", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/drawer-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "dropdown-menu-example",
|
||||
title: "Dropdown Menu",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"avatar",
|
||||
"button",
|
||||
"dialog",
|
||||
"dropdown-menu",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/dropdown-menu-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "empty-example",
|
||||
title: "Empty",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "empty", "input-group", "kbd", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/empty-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "field-example",
|
||||
title: "Field",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"badge",
|
||||
"checkbox",
|
||||
"field",
|
||||
"input",
|
||||
"input-otp",
|
||||
"native-select",
|
||||
"radio-group",
|
||||
"select",
|
||||
"slider",
|
||||
"switch",
|
||||
"textarea",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/field-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "hover-card-example",
|
||||
title: "Hover Card",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "dialog", "hover-card", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/hover-card-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "input-example",
|
||||
title: "Input",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"field",
|
||||
"input",
|
||||
"native-select",
|
||||
"select",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/input-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "input-group-example",
|
||||
title: "Input Group",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"button-group",
|
||||
"card",
|
||||
"dropdown-menu",
|
||||
"field",
|
||||
"input",
|
||||
"input-group",
|
||||
"kbd",
|
||||
"popover",
|
||||
"spinner",
|
||||
"textarea",
|
||||
"tooltip",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/input-group-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "input-otp-example",
|
||||
title: "Input OTP",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "card", "field", "input-otp", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/input-otp-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "item-example",
|
||||
title: "Item",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "item", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/item-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "kbd-example",
|
||||
title: "Kbd",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"input-group",
|
||||
"kbd",
|
||||
"tooltip",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/kbd-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "label-example",
|
||||
title: "Label",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"checkbox",
|
||||
"field",
|
||||
"input",
|
||||
"label",
|
||||
"textarea",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/label-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "native-select-example",
|
||||
title: "Native Select",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["field", "native-select", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/native-select-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "pagination-example",
|
||||
title: "Pagination",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["field", "pagination", "select", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/pagination-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "popover-example",
|
||||
title: "Popover",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"dialog",
|
||||
"field",
|
||||
"input",
|
||||
"popover",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/popover-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "progress-example",
|
||||
title: "Progress",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["field", "item", "progress", "slider", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/progress-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "radio-group-example",
|
||||
title: "Radio Group",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["field", "radio-group", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/radio-group-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "resizable-example",
|
||||
title: "Resizable",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["resizable", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/resizable-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "scroll-area-example",
|
||||
title: "Scroll Area",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["scroll-area", "separator", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/scroll-area-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "select-example",
|
||||
title: "Select",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"dialog",
|
||||
"field",
|
||||
"input",
|
||||
"item",
|
||||
"native-select",
|
||||
"select",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/select-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "separator-example",
|
||||
title: "Separator",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["separator", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/separator-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "sheet-example",
|
||||
title: "Sheet",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "field", "input", "sheet", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/sheet-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "sidebar-example",
|
||||
title: "Sidebar",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"dropdown-menu",
|
||||
"item",
|
||||
"label",
|
||||
"sidebar",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/sidebar-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "sidebar-icon-example",
|
||||
title: "Sidebar (Icon)",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"avatar",
|
||||
"button",
|
||||
"collapsible",
|
||||
"dropdown-menu",
|
||||
"item",
|
||||
"sidebar",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/sidebar-icon-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "sidebar-inset-example",
|
||||
title: "Sidebar (Inset)",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["collapsible", "sidebar", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/sidebar-inset-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "sidebar-floating-example",
|
||||
title: "Sidebar (Floating)",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"card",
|
||||
"dropdown-menu",
|
||||
"field",
|
||||
"item",
|
||||
"sidebar",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/sidebar-floating-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "skeleton-example",
|
||||
title: "Skeleton",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["skeleton", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/skeleton-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "slider-example",
|
||||
title: "Slider",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["label", "slider", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/slider-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "sonner-example",
|
||||
title: "Sonner",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["sonner", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/sonner-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "spinner-example",
|
||||
title: "Spinner",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"badge",
|
||||
"button",
|
||||
"empty",
|
||||
"field",
|
||||
"input-group",
|
||||
"spinner",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/spinner-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "switch-example",
|
||||
title: "Switch",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["field", "label", "switch", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/switch-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "table-example",
|
||||
title: "Table",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"dropdown-menu",
|
||||
"input",
|
||||
"select",
|
||||
"table",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/table-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "tabs-example",
|
||||
title: "Tabs",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "dropdown-menu", "tabs", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/tabs-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "textarea-example",
|
||||
title: "Textarea",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["field", "textarea", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/textarea-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "toggle-example",
|
||||
title: "Toggle",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["toggle", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/toggle-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "toggle-group-example",
|
||||
title: "Toggle Group",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["input", "select", "toggle-group", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/toggle-group-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "tooltip-example",
|
||||
title: "Tooltip",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["button", "kbd", "tooltip", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/tooltip-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "demo",
|
||||
title: "Demo",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"alert-dialog",
|
||||
"badge",
|
||||
"button",
|
||||
"button-group",
|
||||
"card",
|
||||
"checkbox",
|
||||
"dropdown-menu",
|
||||
"field",
|
||||
"input-group",
|
||||
"item",
|
||||
"radio-group",
|
||||
"slider",
|
||||
"switch",
|
||||
"textarea",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/demo.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "component-example",
|
||||
title: "Example",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"alert-dialog",
|
||||
"badge",
|
||||
"button",
|
||||
"card",
|
||||
"combobox",
|
||||
"dropdown-menu",
|
||||
"field",
|
||||
"input",
|
||||
"select",
|
||||
"textarea",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/component-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "attachment-example",
|
||||
title: "Attachment",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["attachment"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/attachment-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "bubble-example",
|
||||
title: "Bubble",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["bubble", "button", "collapsible", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/bubble-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "message-scroller-example",
|
||||
title: "Message Scroller",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"attachment",
|
||||
"bubble",
|
||||
"button",
|
||||
"card",
|
||||
"example",
|
||||
"input-group",
|
||||
"marker",
|
||||
"message",
|
||||
"message-scroller",
|
||||
"spinner",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/message-scroller-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "questionnaire-example",
|
||||
title: "Questionnaire",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"button",
|
||||
"card",
|
||||
"dialog",
|
||||
"example",
|
||||
"questionnaire",
|
||||
"sonner",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/questionnaire-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "marker-example",
|
||||
title: "Marker",
|
||||
type: "registry:example",
|
||||
registryDependencies: [
|
||||
"marker",
|
||||
"button",
|
||||
"accordion",
|
||||
"drawer",
|
||||
"spinner",
|
||||
"example",
|
||||
],
|
||||
files: [
|
||||
{
|
||||
path: "examples/marker-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "message-example",
|
||||
title: "Message",
|
||||
type: "registry:example",
|
||||
registryDependencies: ["bubble", "message", "button", "example"],
|
||||
files: [
|
||||
{
|
||||
path: "examples/message-example.tsx",
|
||||
type: "registry:example",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
336
apps/v4/registry/bases/aria/examples/accordion-example.tsx
Normal file
336
apps/v4/registry/bases/aria/examples/accordion-example.tsx
Normal file
@@ -0,0 +1,336 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/registry/bases/aria/ui/accordion"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AccordionExample() {
|
||||
return (
|
||||
<ExampleWrapper className="w-full max-w-4xl lg:grid-cols-1 2xl:max-w-4xl 2xl:grid-cols-1">
|
||||
<AccordionBasic />
|
||||
<AccordionMultiple />
|
||||
<AccordionWithBorders />
|
||||
<AccordionInCard />
|
||||
<AccordionWithDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionBasic() {
|
||||
const items = [
|
||||
{
|
||||
value: "item-1",
|
||||
trigger: "Is it accessible?",
|
||||
content: "Yes. It adheres to the WAI-ARIA design pattern.",
|
||||
},
|
||||
{
|
||||
value: "item-2",
|
||||
trigger: "Is it styled?",
|
||||
content:
|
||||
"Yes. It comes with default styles that matches the other components' aesthetic.",
|
||||
},
|
||||
{
|
||||
value: "item-3",
|
||||
trigger: "Is it animated?",
|
||||
content:
|
||||
"Yes. It's animated by default, but you can disable it if you prefer.",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Accordion className="mx-auto max-w-lg">
|
||||
{items.map((item) => (
|
||||
<AccordionItem key={item.value} id={item.value}>
|
||||
<AccordionTrigger>{item.trigger}</AccordionTrigger>
|
||||
<AccordionContent>{item.content}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionMultiple() {
|
||||
const items = [
|
||||
{
|
||||
value: "item-1",
|
||||
trigger:
|
||||
"What are the key considerations when implementing a comprehensive enterprise-level authentication system?",
|
||||
content:
|
||||
"Implementing a robust enterprise authentication system requires careful consideration of multiple factors. This includes secure password hashing and storage, multi-factor authentication (MFA) implementation, session management, OAuth2 and SSO integration, regular security audits, rate limiting to prevent brute force attacks, and maintaining detailed audit logs. Additionally, you'll need to consider scalability, performance impact, and compliance with relevant data protection regulations such as GDPR or HIPAA.",
|
||||
},
|
||||
{
|
||||
value: "item-2",
|
||||
trigger:
|
||||
"How does modern distributed system architecture handle eventual consistency and data synchronization across multiple regions?",
|
||||
content:
|
||||
"Modern distributed systems employ various strategies to maintain data consistency across regions. This often involves using techniques like CRDT (Conflict-Free Replicated Data Types), vector clocks, and gossip protocols. Systems might implement event sourcing patterns, utilize message queues for asynchronous updates, and employ sophisticated conflict resolution strategies. Popular solutions like Amazon's DynamoDB and Google's Spanner demonstrate different approaches to solving these challenges, balancing between consistency, availability, and partition tolerance as described in the CAP theorem.",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Accordion allowsMultipleExpanded className="mx-auto max-w-lg">
|
||||
{items.map((item) => (
|
||||
<AccordionItem key={item.value} id={item.value}>
|
||||
<AccordionTrigger>{item.trigger}</AccordionTrigger>
|
||||
<AccordionContent>{item.content}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionWithBorders() {
|
||||
const items = [
|
||||
{
|
||||
value: "billing",
|
||||
trigger: "How does billing work?",
|
||||
content:
|
||||
"We offer monthly and annual subscription plans. Billing is charged at the beginning of each cycle, and you can cancel anytime. All plans include automatic backups, 24/7 support, and unlimited team members. There are no hidden fees or setup costs.",
|
||||
},
|
||||
{
|
||||
value: "security",
|
||||
trigger: "Is my data secure?",
|
||||
content:
|
||||
"Yes. We use end-to-end encryption, SOC 2 Type II compliance, and regular third-party security audits. All data is encrypted at rest and in transit using industry-standard protocols. We also offer optional two-factor authentication and single sign-on for enterprise customers.",
|
||||
},
|
||||
{
|
||||
value: "integration",
|
||||
trigger: "What integrations do you support?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
We integrate with 500+ popular tools including Slack, Zapier,
|
||||
Salesforce, HubSpot, and more. You can also build custom
|
||||
integrations using our REST API and webhooks.{" "}
|
||||
</p>
|
||||
<p>
|
||||
Our API documentation includes code examples in 10+ programming
|
||||
languages.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="With Borders">
|
||||
<Accordion className="mx-auto max-w-lg style-vega:gap-2 style-nova:gap-2 style-lyra:gap-2">
|
||||
{items.map((item) => (
|
||||
<AccordionItem
|
||||
key={item.value}
|
||||
id={item.value}
|
||||
className="style-vega:rounded-lg style-vega:border style-nova:rounded-lg style-nova:border style-lyra:border"
|
||||
>
|
||||
<AccordionTrigger className="font-medium style-vega:px-4 style-vega:text-sm style-nova:px-2.5 style-nova:text-sm style-lyra:px-2 style-lyra:text-xs style-maia:text-sm style-mira:text-xs style-luma:text-sm">
|
||||
{item.trigger}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="text-muted-foreground style-vega:px-4 style-nova:px-2.5 style-nova:text-sm style-lyra:px-2 style-lyra:text-xs style-maia:px-0 style-mira:px-0 style-luma:px-0">
|
||||
{item.content}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionInCard() {
|
||||
const items = [
|
||||
{
|
||||
value: "plans",
|
||||
trigger: "What subscription plans do you offer?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
We offer three subscription tiers: Starter ($9/month), Professional
|
||||
($29/month), and Enterprise ($99/month). Each plan includes
|
||||
increasing storage limits, API access, priority support, and team
|
||||
collaboration features.
|
||||
</p>
|
||||
<p>
|
||||
<a href="#">Annual billing is available</a> with a 20% discount. All
|
||||
plans include a 14-day free trial with no credit card required.
|
||||
</p>
|
||||
<Button size="sm">
|
||||
View plans
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "billing",
|
||||
trigger: "How does billing work?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
Billing occurs automatically at the start of each billing cycle. We
|
||||
accept all major credit cards, PayPal, and ACH transfers for
|
||||
enterprise customers.
|
||||
</p>
|
||||
<p>
|
||||
You'll receive an invoice via email after each payment. You can
|
||||
update your payment method or billing information anytime in your
|
||||
account settings. Failed payments will trigger automated retry
|
||||
attempts and email notifications.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "upgrade",
|
||||
trigger: "Can I upgrade or downgrade my plan?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
Yes, you can change your plan at any time. When upgrading,
|
||||
you'll be charged a prorated amount for the remainder of your
|
||||
billing cycle and immediately gain access to new features.
|
||||
</p>
|
||||
<p>
|
||||
When downgrading, the change takes effect at the end of your current
|
||||
billing period, and you'll retain access to premium features
|
||||
until then. No refunds are provided for downgrades.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "cancel",
|
||||
trigger: "How do I cancel my subscription?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
You can cancel your subscription anytime from your account settings.
|
||||
There are no cancellation fees or penalties. Your access will
|
||||
continue until the end of your current billing period.
|
||||
</p>
|
||||
<p>
|
||||
After cancellation, your data is retained for 30 days in case you
|
||||
want to reactivate. You can export all your data before or after
|
||||
canceling. We'd love to hear your feedback about why
|
||||
you're leaving.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
value: "refund",
|
||||
trigger: "What is your refund policy?",
|
||||
content: (
|
||||
<>
|
||||
<p>
|
||||
We offer a 30-day money-back guarantee for new subscriptions. If
|
||||
you're not satisfied within the first 30 days, contact our
|
||||
support team for a full refund.
|
||||
</p>
|
||||
<p>
|
||||
After 30 days, we don't provide refunds for partial billing
|
||||
periods, but you can cancel anytime to avoid future charges.
|
||||
Enterprise customers have custom refund terms outlined in their
|
||||
contracts.
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Card className="mx-auto w-full max-w-lg gap-4">
|
||||
<CardHeader>
|
||||
<CardTitle>Subscription & Billing</CardTitle>
|
||||
<CardDescription>
|
||||
Common questions about your account, plans, and payments
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Accordion
|
||||
allowsMultipleExpanded
|
||||
defaultExpandedKeys={["plans"]}
|
||||
className="style-maia:rounded-md style-mira:rounded-md"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<AccordionItem key={item.value} id={item.value}>
|
||||
<AccordionTrigger>{item.trigger}</AccordionTrigger>
|
||||
<AccordionContent>{item.content}</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AccordionWithDisabled() {
|
||||
const items = [
|
||||
{
|
||||
value: "item-1",
|
||||
trigger: "Can I access my account history?",
|
||||
content:
|
||||
"Yes, you can view your complete account history including all transactions, plan changes, and support tickets in the Account History section of your dashboard.",
|
||||
disabled: false,
|
||||
},
|
||||
{
|
||||
value: "item-2",
|
||||
trigger: "Premium feature information",
|
||||
content:
|
||||
"This section contains information about premium features. Upgrade your plan to access this content.",
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
value: "item-3",
|
||||
trigger: "How do I update my email address?",
|
||||
content:
|
||||
"You can update your email address in your account settings. You'll receive a verification email at your new address to confirm the change.",
|
||||
disabled: false,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="With Disabled">
|
||||
<Accordion className="mx-auto max-w-lg overflow-hidden border style-vega:rounded-lg style-nova:rounded-lg style-lyra:rounded-none style-maia:rounded-lg style-mira:rounded-lg style-luma:rounded-xl">
|
||||
{items.map((item) => (
|
||||
<AccordionItem
|
||||
key={item.value}
|
||||
id={item.value}
|
||||
isDisabled={item.disabled}
|
||||
className="p-1 data-expanded:bg-muted/50"
|
||||
>
|
||||
<AccordionTrigger className="style-vega:px-4 style-nova:px-2.5 style-lyra:px-2">
|
||||
{item.trigger}
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="style-vega:px-4 style-nova:px-2.5 style-lyra:px-2">
|
||||
{item.content}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
216
apps/v4/registry/bases/aria/examples/alert-dialog-example.tsx
Normal file
216
apps/v4/registry/bases/aria/examples/alert-dialog-example.tsx
Normal file
@@ -0,0 +1,216 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogMedia,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/alert-dialog"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AlertDialogExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<AlertDialogBasic />
|
||||
<AlertDialogSmall />
|
||||
<AlertDialogWithMedia />
|
||||
<AlertDialogSmallWithMedia />
|
||||
<AlertDialogDestructive />
|
||||
<AlertDialogInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogBasic() {
|
||||
return (
|
||||
<Example title="Basic" className="items-center">
|
||||
<AlertDialogTrigger>
|
||||
<Button variant="outline">Default</Button>
|
||||
<AlertDialog>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete your
|
||||
account and remove your data from our servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogSmall() {
|
||||
return (
|
||||
<Example title="Small" className="items-center">
|
||||
<AlertDialogTrigger>
|
||||
<Button variant="outline">Small</Button>
|
||||
<AlertDialog size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to this device?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogWithMedia() {
|
||||
return (
|
||||
<Example title="With Media" className="items-center">
|
||||
<AlertDialogTrigger>
|
||||
<Button variant="outline">Default (Media)</Button>
|
||||
<AlertDialog>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia>
|
||||
<IconPlaceholder
|
||||
lucide="BluetoothIcon"
|
||||
tabler="IconBluetooth"
|
||||
hugeicons="BluetoothIcon"
|
||||
phosphor="BluetoothIcon"
|
||||
remixicon="RiBluetoothLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This will permanently delete your account and remove your data
|
||||
from our servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogSmallWithMedia() {
|
||||
return (
|
||||
<Example title="Small With Media" className="items-center">
|
||||
<AlertDialogTrigger>
|
||||
<Button variant="outline">Small (Media)</Button>
|
||||
|
||||
<AlertDialog size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia>
|
||||
<IconPlaceholder
|
||||
lucide="BluetoothIcon"
|
||||
tabler="IconBluetooth"
|
||||
hugeicons="BluetoothIcon"
|
||||
phosphor="BluetoothIcon"
|
||||
remixicon="RiBluetoothLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to this device?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogDestructive() {
|
||||
return (
|
||||
<Example title="Destructive" className="items-center">
|
||||
<AlertDialogTrigger>
|
||||
<Button variant="destructive">Delete Chat</Button>
|
||||
<AlertDialog size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia className="bg-destructive/10 text-destructive dark:bg-destructive/20 dark:text-destructive">
|
||||
<IconPlaceholder
|
||||
lucide="Trash2Icon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Delete chat?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This will permanently delete this chat conversation. View{" "}
|
||||
<a href="#">Settings</a> delete any memories saved during this
|
||||
chat.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel variant="ghost">Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction variant="destructive">Delete</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertDialogInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog" className="items-center">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Alert Dialog Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Click the button below to open an alert dialog.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<AlertDialogTrigger>
|
||||
<Button>Open Alert Dialog</Button>
|
||||
<AlertDialog size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete
|
||||
your account and remove your data from our servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
227
apps/v4/registry/bases/aria/examples/alert-example.tsx
Normal file
227
apps/v4/registry/bases/aria/examples/alert-example.tsx
Normal file
@@ -0,0 +1,227 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Alert,
|
||||
AlertAction,
|
||||
AlertDescription,
|
||||
AlertTitle,
|
||||
} from "@/registry/bases/aria/ui/alert"
|
||||
import { Badge } from "@/registry/bases/aria/ui/badge"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AlertExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1">
|
||||
<AlertExample1 />
|
||||
<AlertExample2 />
|
||||
<AlertExample3 />
|
||||
<AlertExample4 />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample1() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert>
|
||||
<AlertTitle>Success! Your changes have been saved.</AlertTitle>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<AlertTitle>Success! Your changes have been saved.</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is an alert with title and description.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
This one has a description only. No title. No icon.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample2() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>
|
||||
Let's try one with icon, title and a <a href="#">link</a>.
|
||||
</AlertTitle>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertDescription>
|
||||
This one has an icon and a description only. No title.{" "}
|
||||
<a href="#">But it has a link</a> and a <a href="#">second link</a>.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>Success! Your changes have been saved</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is an alert with icon, title and description.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>
|
||||
This is a very long alert title that demonstrates how the component
|
||||
handles extended text content and potentially wraps across multiple
|
||||
lines
|
||||
</AlertTitle>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertDescription>
|
||||
This is a very long alert description that demonstrates how the
|
||||
component handles extended text content and potentially wraps across
|
||||
multiple lines
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>
|
||||
This is an extremely long alert title that spans multiple lines to
|
||||
demonstrate how the component handles very lengthy headings while
|
||||
maintaining readability and proper text wrapping behavior
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is an equally long description that contains detailed
|
||||
information about the alert. It shows how the component can
|
||||
accommodate extensive content while preserving proper spacing,
|
||||
alignment, and readability across different screen sizes and
|
||||
viewport widths. This helps ensure the user experience remains
|
||||
consistent regardless of the content length.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample3() {
|
||||
return (
|
||||
<Example title="Destructive">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>Something went wrong!</AlertTitle>
|
||||
<AlertDescription>
|
||||
Your session has expired. Please log in again.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
<Alert variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>Unable to process your payment.</AlertTitle>
|
||||
<AlertDescription>
|
||||
<p>
|
||||
Please verify your <a href="#">billing information</a> and try
|
||||
again.
|
||||
</p>
|
||||
<ul className="list-inside list-disc">
|
||||
<li>Check your card details</li>
|
||||
<li>Ensure sufficient funds</li>
|
||||
<li>Verify billing address</li>
|
||||
</ul>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AlertExample4() {
|
||||
return (
|
||||
<Example title="With Actions">
|
||||
<div className="mx-auto flex w-full max-w-lg flex-col gap-4">
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>The selected emails have been marked as spam.</AlertTitle>
|
||||
<AlertAction>
|
||||
<Button size="xs">Undo</Button>
|
||||
</AlertAction>
|
||||
</Alert>
|
||||
<Alert>
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
<AlertTitle>The selected emails have been marked as spam.</AlertTitle>
|
||||
<AlertDescription>
|
||||
This is a very long alert title that demonstrates how the component
|
||||
handles extended text content.
|
||||
</AlertDescription>
|
||||
<AlertAction>
|
||||
<Badge variant="secondary">Badge</Badge>
|
||||
</AlertAction>
|
||||
</Alert>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import Image from "next/image"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { AspectRatio } from "@/registry/bases/aria/ui/aspect-ratio"
|
||||
|
||||
export default function AspectRatioExample() {
|
||||
return (
|
||||
<ExampleWrapper className="max-w-4xl 2xl:max-w-4xl">
|
||||
<AspectRatio16x9 />
|
||||
<AspectRatio21x9 />
|
||||
<AspectRatio1x1 />
|
||||
<AspectRatio9x16 />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio16x9() {
|
||||
return (
|
||||
<Example title="16:9" className="items-center justify-center">
|
||||
<AspectRatio
|
||||
ratio={16 / 9}
|
||||
className="rounded-lg bg-muted style-luma:rounded-3xl"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-luma:rounded-3xl"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio1x1() {
|
||||
return (
|
||||
<Example title="1:1" className="items-start">
|
||||
<AspectRatio
|
||||
ratio={1 / 1}
|
||||
className="rounded-lg bg-muted style-luma:rounded-3xl"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-luma:rounded-3xl"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio9x16() {
|
||||
return (
|
||||
<Example title="9:16" className="items-center justify-center">
|
||||
<AspectRatio
|
||||
ratio={9 / 16}
|
||||
className="rounded-lg bg-muted style-luma:rounded-3xl"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-luma:rounded-3xl"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AspectRatio21x9() {
|
||||
return (
|
||||
<Example title="21:9" className="items-center justify-center">
|
||||
<AspectRatio
|
||||
ratio={21 / 9}
|
||||
className="rounded-lg bg-muted style-luma:rounded-3xl"
|
||||
>
|
||||
<Image
|
||||
src="https://avatar.vercel.sh/shadcn1"
|
||||
alt="Photo"
|
||||
fill
|
||||
className="h-full w-full rounded-lg object-cover grayscale dark:brightness-20 style-luma:rounded-3xl"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
1646
apps/v4/registry/bases/aria/examples/attachment-example.tsx
Normal file
1646
apps/v4/registry/bases/aria/examples/attachment-example.tsx
Normal file
File diff suppressed because it is too large
Load Diff
511
apps/v4/registry/bases/aria/examples/avatar-example.tsx
Normal file
511
apps/v4/registry/bases/aria/examples/avatar-example.tsx
Normal file
@@ -0,0 +1,511 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarBadge,
|
||||
AvatarFallback,
|
||||
AvatarGroup,
|
||||
AvatarGroupCount,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/aria/ui/avatar"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/aria/ui/empty"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function AvatarExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<AvatarSizes />
|
||||
<AvatarWithBadge />
|
||||
<AvatarWithBadgeIcon />
|
||||
<AvatarGroupExample />
|
||||
<AvatarGroupWithCount />
|
||||
<AvatarGroupWithIconCount />
|
||||
<AvatarInEmpty />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarWithBadge() {
|
||||
return (
|
||||
<Example title="Badge">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/jorgezreik.png"
|
||||
alt="@jorgezreik"
|
||||
/>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/jorgezreik.png"
|
||||
alt="@jorgezreik"
|
||||
/>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/jorgezreik.png"
|
||||
alt="@jorgezreik"
|
||||
/>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarFallback>JZ</AvatarFallback>
|
||||
<AvatarBadge />
|
||||
</Avatar>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarWithBadgeIcon() {
|
||||
return (
|
||||
<Example title="Badge with Icon">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/pranathip.png"
|
||||
alt="@pranathip"
|
||||
/>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/pranathip.png"
|
||||
alt="@pranathip"
|
||||
/>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/pranathip.png"
|
||||
alt="@pranathip"
|
||||
/>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarFallback>PP</AvatarFallback>
|
||||
<AvatarBadge>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</AvatarBadge>
|
||||
</Avatar>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarGroupExample() {
|
||||
return (
|
||||
<Example title="Group">
|
||||
<AvatarGroup>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</AvatarGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarGroupWithCount() {
|
||||
return (
|
||||
<Example title="Group with Count">
|
||||
<AvatarGroup>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>+3</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>+3</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>+3</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarGroupWithIconCount() {
|
||||
return (
|
||||
<Example title="Group with Icon Count">
|
||||
<AvatarGroup>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="sm">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/shadcn.png"
|
||||
alt="@shadcn"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function AvatarInEmpty() {
|
||||
return (
|
||||
<Example title="In Empty">
|
||||
<Empty className="w-full flex-none border">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia>
|
||||
<AvatarGroup>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/shadcn.png"
|
||||
alt="@shadcn"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar size="lg">
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No Team Members</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Invite your team to collaborate on this project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
Invite Members
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
339
apps/v4/registry/bases/aria/examples/badge-example.tsx
Normal file
339
apps/v4/registry/bases/aria/examples/badge-example.tsx
Normal file
@@ -0,0 +1,339 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Badge } from "@/registry/bases/aria/ui/badge"
|
||||
import { Spinner } from "@/registry/bases/aria/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function BadgeExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1">
|
||||
<BadgeVariants />
|
||||
<BadgeWithIconLeft />
|
||||
<BadgeWithIconRight />
|
||||
<BadgeWithSpinner />
|
||||
<BadgeAsLink />
|
||||
<BadgeLongText />
|
||||
<BadgeCustomColors />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeVariants() {
|
||||
return (
|
||||
<Example title="Variants">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>Default</Badge>
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
<Badge variant="destructive">Destructive</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
<Badge variant="ghost">Ghost</Badge>
|
||||
<Badge variant="link">Link</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeWithIconLeft() {
|
||||
return (
|
||||
<Example title="Icon Left" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Default
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Secondary
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Destructive
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Outline
|
||||
</Badge>
|
||||
<Badge variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Ghost
|
||||
</Badge>
|
||||
<Badge variant="link">
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheck"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadge02Icon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Link
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeWithIconRight() {
|
||||
return (
|
||||
<Example title="Icon Right" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>
|
||||
Default
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
Secondary
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
Destructive
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
Outline
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="ghost">
|
||||
Ghost
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
<Badge variant="link">
|
||||
Link
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeWithSpinner() {
|
||||
return (
|
||||
<Example title="With Spinner" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge>
|
||||
<Spinner data-icon="inline-start" />
|
||||
Default
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Secondary
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Destructive
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Outline
|
||||
</Badge>
|
||||
<Badge variant="ghost">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Ghost
|
||||
</Badge>
|
||||
<Badge variant="link">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Link
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeAsLink() {
|
||||
return (
|
||||
<Example title="asChild">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge
|
||||
render={(props) => (
|
||||
<a {...props} href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRightIcon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
/>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
render={(props) => (
|
||||
<a {...props} href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRightIcon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
/>
|
||||
<Badge
|
||||
variant="destructive"
|
||||
render={(props) => (
|
||||
<a {...props} href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRightIcon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
/>
|
||||
<Badge
|
||||
variant="ghost"
|
||||
render={(props) => (
|
||||
<a {...props} href="#">
|
||||
Link{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeLongText() {
|
||||
return (
|
||||
<Example title="Long Text">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge variant="secondary">
|
||||
A badge with a lot of text to see how it wraps
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BadgeCustomColors() {
|
||||
return (
|
||||
<Example title="Custom Colors" className="max-w-fit">
|
||||
<div className="flex flex-wrap gap-2 style-sera:gap-6">
|
||||
<Badge className="bg-blue-600 text-blue-50 dark:bg-blue-600 dark:text-blue-50">
|
||||
Blue
|
||||
</Badge>
|
||||
<Badge className="bg-green-600 text-green-50 dark:bg-green-600 dark:text-green-50">
|
||||
Green
|
||||
</Badge>
|
||||
<Badge className="bg-sky-600 text-sky-50 dark:bg-sky-600 dark:text-sky-50">
|
||||
Sky
|
||||
</Badge>
|
||||
<Badge className="bg-purple-600 text-purple-50 dark:bg-purple-600 dark:text-purple-50">
|
||||
Purple
|
||||
</Badge>
|
||||
<Badge className="bg-blue-50 text-blue-700 dark:bg-blue-950 dark:text-blue-300">
|
||||
Blue
|
||||
</Badge>
|
||||
<Badge className="bg-green-50 text-green-700 dark:bg-green-950 dark:text-green-300">
|
||||
Green
|
||||
</Badge>
|
||||
<Badge className="bg-sky-50 text-sky-700 dark:bg-sky-950 dark:text-sky-300">
|
||||
Sky
|
||||
</Badge>
|
||||
<Badge className="bg-purple-50 text-purple-700 dark:bg-purple-950 dark:text-purple-300">
|
||||
Purple
|
||||
</Badge>
|
||||
<Badge className="bg-red-50 text-red-700 dark:bg-red-950 dark:text-red-300">
|
||||
Red
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
130
apps/v4/registry/bases/aria/examples/breadcrumb-example.tsx
Normal file
130
apps/v4/registry/bases/aria/examples/breadcrumb-example.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbEllipsis,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
} from "@/registry/bases/aria/ui/breadcrumb"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
|
||||
export default function BreadcrumbExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<BreadcrumbBasic />
|
||||
<BreadcrumbWithDropdown />
|
||||
<BreadcrumbWithLink />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function BreadcrumbBasic() {
|
||||
return (
|
||||
<Example title="Basic" className="items-center justify-center">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Components</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BreadcrumbWithDropdown() {
|
||||
return (
|
||||
<Example title="With Dropdown" className="items-center justify-center">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Home</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<DropdownMenuTrigger>
|
||||
<Button size="icon-sm" variant="ghost">
|
||||
<BreadcrumbEllipsis />
|
||||
<span className="sr-only">Toggle menu</span>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom start">
|
||||
<DropdownMenuItem>Documentation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Themes</DropdownMenuItem>
|
||||
<DropdownMenuItem>GitHub</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink href="#">Components</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BreadcrumbWithLink() {
|
||||
return (
|
||||
<Example title="With Link" className="items-center justify-center">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink
|
||||
href="#"
|
||||
render={(props) =>
|
||||
"href" in props ? <Link {...props} /> : <span {...props} />
|
||||
}
|
||||
>
|
||||
Home
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbEllipsis />
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink
|
||||
href="#"
|
||||
render={(props) =>
|
||||
"href" in props ? <Link {...props} /> : <span {...props} />
|
||||
}
|
||||
>
|
||||
Components
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
522
apps/v4/registry/bases/aria/examples/bubble-example.tsx
Normal file
522
apps/v4/registry/bases/aria/examples/bubble-example.tsx
Normal file
@@ -0,0 +1,522 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Bubble,
|
||||
BubbleContent,
|
||||
BubbleGroup,
|
||||
BubbleReactions,
|
||||
} from "@/registry/bases/aria/ui/bubble"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { Collapsible } from "@/registry/bases/aria/ui/collapsible"
|
||||
import { Marker, MarkerContent } from "@/registry/bases/aria/ui/marker"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function BubbleExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<BubbleSizes />
|
||||
<BubbleVariants />
|
||||
<BubbleAlignment />
|
||||
<BubbleGrouped />
|
||||
<BubbleCollapsible />
|
||||
<BubbleButtonLinks />
|
||||
<BubbleWithReactions />
|
||||
<BubbleReactionsButtons />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleVariants() {
|
||||
return (
|
||||
<Example title="Variants">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Default bubbles use the primary color for the active user side of a
|
||||
chat.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
Secondary bubbles are the standard neutral surface for assistant and
|
||||
conversation content.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
Muted bubbles lower the emphasis for quiet system notes or for
|
||||
displaying supporting content.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted" align="end">
|
||||
<BubbleContent>
|
||||
Tinted bubbles use a softer primary tint when primary fill is too
|
||||
strong.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="outline">
|
||||
<BubbleContent>
|
||||
Outline bubbles can be used to frame message content and give it a
|
||||
border.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="destructive">
|
||||
<BubbleContent>
|
||||
Destructive bubbles flag errors or failed actions in a conversation.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">
|
||||
{`Ghost bubbles work for assistant text and other content that should not be framed.
|
||||
|
||||
This is perfect for assistant messages that should not have a frame and can take the full width of the container.
|
||||
|
||||
Ghost bubbles are full width and can take the full width of the container.
|
||||
`}
|
||||
</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent>This is a one line bubble.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
This bubble has multiple lines. It should wrap to the next line and
|
||||
you should see a different radius on the corners.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
<p>This bubble has multiple lines.</p>
|
||||
<p>
|
||||
It should wrap to the next line and you should see a different
|
||||
radius on the corners.
|
||||
</p>
|
||||
<p>Here is some more text to see how it wraps.</p>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleGrouped() {
|
||||
return (
|
||||
<Example title="Grouped">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<BubbleGroup>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>I finished the audit pass.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
The registry output looks clean, but I found one stale route.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>Want me to remove it now?</BubbleContent>
|
||||
</Bubble>
|
||||
</BubbleGroup>
|
||||
<BubbleGroup>
|
||||
<Bubble variant="tinted" align="end">
|
||||
<BubbleContent>Yes, clean that up.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted" align="end">
|
||||
<BubbleContent>Then rerun the registry build.</BubbleContent>
|
||||
</Bubble>
|
||||
</BubbleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const text = `The accessibility review found two focus states that were visually too subtle in dark mode.
|
||||
|
||||
I checked the dialog, menu, and drawer paths because each one renders focusable controls inside a layered surface.
|
||||
|
||||
The dialog and drawer are fine. The menu needs the hover and focus tokens split so keyboard focus stays visible when the pointer is not involved.
|
||||
|
||||
I also recommend keeping the change in the style file instead of the primitive so the other themes can choose their own focus treatment later.`
|
||||
|
||||
const previewLength = 180
|
||||
|
||||
function BubbleCollapsible() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
const isLong = text.length > previewLength
|
||||
const preview = `${text.slice(0, previewLength)}...`
|
||||
|
||||
return (
|
||||
<Example title="Collapsible">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Collapsible isExpanded={open} onExpandedChange={setOpen}>
|
||||
<Bubble variant="muted" align="end">
|
||||
<BubbleContent className="whitespace-pre-line">
|
||||
<div>{open || !isLong ? text : preview}</div>
|
||||
{isLong ? (
|
||||
<Button
|
||||
slot="trigger"
|
||||
variant="link"
|
||||
className="gap-1 p-0 text-muted-foreground"
|
||||
>
|
||||
{open ? "Show less" : "Show more"}
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
data-icon="inline-end"
|
||||
className="group-data-panel-open/button:rotate-180"
|
||||
/>
|
||||
</Button>
|
||||
) : null}
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</Collapsible>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">
|
||||
{`Ghost bubbles work for assistant text and other content that should not be framed.
|
||||
|
||||
This is perfect for assistant messages that should not have a frame and can take the full width of the container.
|
||||
|
||||
Use this for content that needs the whole row.`}
|
||||
</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleWithReactions() {
|
||||
return (
|
||||
<Example title="Reaction Placement">
|
||||
<div className="flex w-full max-w-md flex-col gap-12">
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=bottom align=end</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble>
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reaction: thumbs up"
|
||||
>
|
||||
<span>👍</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary" align="end">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes, and 8 more"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
<span>+8</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=bottom align=start</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reaction: fire"
|
||||
>
|
||||
<span>🔥</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="bottom"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=top align=start</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reaction: fire"
|
||||
>
|
||||
<span>🔥</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset is
|
||||
easier to inspect.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="start"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>side=bottom align=end</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reaction: thumbs up"
|
||||
>
|
||||
<span>👍</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
A longer message that wraps across lines so the reaction offset.
|
||||
</BubbleContent>
|
||||
<BubbleReactions
|
||||
side="top"
|
||||
align="end"
|
||||
role="img"
|
||||
aria-label="Reactions: thumbs up, surprised, fire, eyes"
|
||||
className="px-1.5 py-0.5"
|
||||
>
|
||||
<span>👍</span>
|
||||
<span>😮</span>
|
||||
<span>🔥</span>
|
||||
<span>👀</span>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleReactionsButtons() {
|
||||
return (
|
||||
<Example title="Reactions Buttons">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="xs"
|
||||
onClick={() =>
|
||||
toast("You clicked the button in the bubble reaction")
|
||||
}
|
||||
>
|
||||
Button
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble align="end">
|
||||
<BubbleContent>This is a one line message.</BubbleContent>
|
||||
<BubbleReactions align="start">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon-xs"
|
||||
onClick={() => toast("Confetti!")}
|
||||
>
|
||||
🎉
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
We are going to the movies first then dinner. Are you in?
|
||||
</BubbleContent>
|
||||
<BubbleReactions className="gap-1 bg-background">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon-xs"
|
||||
aria-label="Thumbs up"
|
||||
onClick={() => toast("You agree!")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsUpIcon"
|
||||
tabler="IconThumbUp"
|
||||
hugeicons="ThumbsUpIcon"
|
||||
phosphor="ThumbsUpIcon"
|
||||
remixicon="RiThumbUpLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="icon-xs"
|
||||
aria-label="Thumbs down"
|
||||
onClick={() => toast("You disagree!")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsDownIcon"
|
||||
tabler="IconThumbDown"
|
||||
hugeicons="ThumbsDownIcon"
|
||||
phosphor="ThumbsDownIcon"
|
||||
remixicon="RiThumbDownLine"
|
||||
/>
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function BubbleAlignment() {
|
||||
return (
|
||||
<Example title="Alignment">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>This bubble is aligned to the start.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble align="end">
|
||||
<BubbleContent>This bubble is aligned to the end.</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
This multiline bubble is aligned to the start. The corners should
|
||||
adjust when the text wraps to show the grouped side of the
|
||||
conversation.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble align="end">
|
||||
<BubbleContent>
|
||||
This multiline bubble is aligned to the end. It should sit on the
|
||||
opposite side with the matching corner radius for wrapped text.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const quickReplies = [
|
||||
{
|
||||
label: "I need help with my account.",
|
||||
message: "I need help with my account.",
|
||||
},
|
||||
{
|
||||
label: "I forgot my password.",
|
||||
message: "I forgot my password.",
|
||||
},
|
||||
{
|
||||
label:
|
||||
"I have another question. I'd like to talk to a human. Can you help me?",
|
||||
message: "I have another question.",
|
||||
},
|
||||
]
|
||||
|
||||
function BubbleButtonLinks() {
|
||||
return (
|
||||
<Example title="Button & Links">
|
||||
<div className="flex w-full max-w-md flex-col gap-8">
|
||||
<Bubble>
|
||||
<BubbleContent render={(props) => <a href="#" {...props} />}>
|
||||
This bubble is a link.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="secondary">
|
||||
<BubbleContent
|
||||
render={(props) => <button type="button" {...props} />}
|
||||
>
|
||||
This one is a button you can click.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent
|
||||
render={(props) => <button type="button" {...props} />}
|
||||
>
|
||||
You can also do tinted buttons. Even ones that are multilines.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>Chat Suggestions</MarkerContent>
|
||||
</Marker>
|
||||
<Bubble>
|
||||
<BubbleContent>How can I help you today?</BubbleContent>
|
||||
</Bubble>
|
||||
<BubbleGroup>
|
||||
{quickReplies.map((reply) => (
|
||||
<Bubble key={reply.label} variant="outline" align="end">
|
||||
<BubbleContent
|
||||
className="border-dashed border-primary"
|
||||
render={(props) => (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => toast(reply.message)}
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
>
|
||||
{reply.label}
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
))}
|
||||
</BubbleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
1000
apps/v4/registry/bases/aria/examples/button-example.tsx
Normal file
1000
apps/v4/registry/bases/aria/examples/button-example.tsx
Normal file
File diff suppressed because it is too large
Load Diff
753
apps/v4/registry/bases/aria/examples/button-group-example.tsx
Normal file
753
apps/v4/registry/bases/aria/examples/button-group-example.tsx
Normal file
@@ -0,0 +1,753 @@
|
||||
"use client"
|
||||
|
||||
import { Focusable } from "react-aria-components"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button, buttonVariants } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
ButtonGroup,
|
||||
ButtonGroupText,
|
||||
} from "@/registry/bases/aria/ui/button-group"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import { Field, FieldGroup } from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { Label } from "@/registry/bases/aria/ui/label"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
import { Tooltip, TooltipTrigger } from "@/registry/bases/aria/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ButtonGroupExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ButtonGroupBasic />
|
||||
<ButtonGroupWithInput />
|
||||
<ButtonGroupWithText />
|
||||
<ButtonGroupWithDropdown />
|
||||
<ButtonGroupWithSelect />
|
||||
<ButtonGroupWithIcons />
|
||||
<ButtonGroupWithInputGroup />
|
||||
<ButtonGroupWithFields />
|
||||
<ButtonGroupWithLike />
|
||||
<ButtonGroupWithSelectAndInput />
|
||||
<ButtonGroupNested />
|
||||
<ButtonGroupPagination />
|
||||
<ButtonGroupPaginationSplit />
|
||||
<ButtonGroupNavigation />
|
||||
<ButtonGroupTextAlignment />
|
||||
<ButtonGroupVertical />
|
||||
<ButtonGroupVerticalNested />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Button</Button>
|
||||
<Button variant="outline">Another Button</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithInput() {
|
||||
return (
|
||||
<Example title="With Input">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Button</Button>
|
||||
<Input placeholder="Type something here..." />
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Input placeholder="Type something here..." />
|
||||
<Button variant="outline">Button</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithText() {
|
||||
return (
|
||||
<Example title="With Text">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<ButtonGroupText>Text</ButtonGroupText>
|
||||
<Button variant="outline">Another Button</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<ButtonGroupText
|
||||
render={(props) => <Label htmlFor="input-text" {...props} />}
|
||||
>
|
||||
GPU Size
|
||||
</ButtonGroupText>
|
||||
<Input
|
||||
id="input-text"
|
||||
placeholder="Type something here..."
|
||||
className="style-luma:border-border"
|
||||
/>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithDropdown() {
|
||||
return (
|
||||
<Example title="With Dropdown">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Update</Button>
|
||||
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom end">
|
||||
<DropdownMenuItem>Disable</DropdownMenuItem>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Uninstall
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Follow</Button>
|
||||
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom end" className="w-50">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="VolumeX"
|
||||
tabler="IconVolume"
|
||||
hugeicons="VolumeOffIcon"
|
||||
phosphor="SpeakerSlashIcon"
|
||||
remixicon="RiVolumeMuteLine"
|
||||
/>
|
||||
Mute Conversation
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
Mark as Read
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="AlertTriangleIcon"
|
||||
tabler="IconAlertTriangle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
Report Conversation
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserRoundXIcon"
|
||||
tabler="IconUserX"
|
||||
hugeicons="UserRemove01Icon"
|
||||
phosphor="UserMinusIcon"
|
||||
remixicon="RiUserUnfollowLine"
|
||||
/>
|
||||
Block User
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="Share03Icon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
Share Conversation
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy Conversation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete Conversation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const currencyItems = [
|
||||
{ label: "$", value: "$" },
|
||||
{ label: "€", value: "€" },
|
||||
{ label: "£", value: "£" },
|
||||
]
|
||||
|
||||
function ButtonGroupWithSelect() {
|
||||
return (
|
||||
<Example title="With Select">
|
||||
<Field>
|
||||
<Label htmlFor="amount">Amount</Label>
|
||||
<ButtonGroup>
|
||||
<Select aria-label="Currency" defaultValue={currencyItems[0].value}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{currencyItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Input placeholder="Enter amount to send" />
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="FlipHorizontalIcon"
|
||||
tabler="IconFlipHorizontal"
|
||||
hugeicons="FlipHorizontalIcon"
|
||||
phosphor="ArrowsHorizontalIcon"
|
||||
remixicon="RiArrowLeftRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="FlipVerticalIcon"
|
||||
tabler="IconFlipVertical"
|
||||
hugeicons="FlipVerticalIcon"
|
||||
phosphor="ArrowsVerticalIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="RotateCwIcon"
|
||||
tabler="IconRotateClockwise2"
|
||||
hugeicons="Rotate01Icon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithInputGroup() {
|
||||
return (
|
||||
<Example title="With Input Group">
|
||||
<div className="flex flex-col gap-4">
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Type to search..." />
|
||||
<InputGroupAddon
|
||||
align="inline-start"
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithFields() {
|
||||
return (
|
||||
<Example title="With Fields">
|
||||
<FieldGroup className="grid grid-cols-3 gap-4">
|
||||
<Field className="col-span-2">
|
||||
<Label htmlFor="width">Width</Label>
|
||||
<ButtonGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="width" />
|
||||
<InputGroupAddon className="text-muted-foreground">
|
||||
W
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon
|
||||
align="inline-end"
|
||||
className="text-muted-foreground"
|
||||
>
|
||||
px
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="MinusIcon"
|
||||
tabler="IconMinus"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupWithLike() {
|
||||
return (
|
||||
<Example title="With Like">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="HeartIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="Notification02Icon"
|
||||
phosphor="HeartIcon"
|
||||
remixicon="RiHeartLine"
|
||||
data-icon="inline-start"
|
||||
/>{" "}
|
||||
Like
|
||||
</Button>
|
||||
<span
|
||||
data-slot="button"
|
||||
className={buttonVariants({
|
||||
variant: "outline",
|
||||
size: "icon",
|
||||
className: "w-12",
|
||||
})}
|
||||
>
|
||||
1.2K
|
||||
</span>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const durationItems = [
|
||||
{ label: "Hours", value: "hours" },
|
||||
{ label: "Days", value: "days" },
|
||||
{ label: "Weeks", value: "weeks" },
|
||||
]
|
||||
|
||||
function ButtonGroupWithSelectAndInput() {
|
||||
return (
|
||||
<Example title="With Select and Input">
|
||||
<ButtonGroup>
|
||||
<Select aria-label="Duration" defaultValue={durationItems[0].value}>
|
||||
<SelectTrigger id="duration">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent placement="bottom start">
|
||||
<SelectGroup>
|
||||
{durationItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Input />
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupNested() {
|
||||
return (
|
||||
<Example title="Nested">
|
||||
<ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Send a message..." />
|
||||
<TooltipTrigger>
|
||||
<Focusable>
|
||||
<InputGroupAddon align="inline-end" role="button">
|
||||
<IconPlaceholder
|
||||
lucide="AudioLinesIcon"
|
||||
tabler="IconHeadphones"
|
||||
hugeicons="AudioWave01Icon"
|
||||
phosphor="MicrophoneIcon"
|
||||
remixicon="RiMicLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</Focusable>
|
||||
<Tooltip>Voice Mode</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</InputGroup>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupPagination() {
|
||||
return (
|
||||
<Example title="Pagination">
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft02Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Previous
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
1
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
2
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
3
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
4
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
5
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Next
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
data-icon="inline-end"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupPaginationSplit() {
|
||||
return (
|
||||
<Example title="Pagination Split">
|
||||
<ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="sm">
|
||||
1
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
2
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
3
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
4
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
5
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupNavigation() {
|
||||
return (
|
||||
<Example title="Navigation">
|
||||
<ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup aria-label="Single navigation button">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupTextAlignment() {
|
||||
return (
|
||||
<Example title="Text Alignment">
|
||||
<Field>
|
||||
<Label id="alignment-label">Text Alignment</Label>
|
||||
<ButtonGroup aria-labelledby="alignment-label">
|
||||
<Button variant="outline" size="sm">
|
||||
Left
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Center
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Right
|
||||
</Button>
|
||||
<Button variant="outline" size="sm">
|
||||
Justify
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<div className="flex gap-6">
|
||||
<ButtonGroup
|
||||
orientation="vertical"
|
||||
aria-label="Media controls"
|
||||
className="h-fit"
|
||||
>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="MinusIcon"
|
||||
tabler="IconMinus"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonGroupVerticalNested() {
|
||||
return (
|
||||
<Example title="Vertical Nested">
|
||||
<ButtonGroup orientation="vertical" aria-label="Design tools palette">
|
||||
<ButtonGroup orientation="vertical">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="Share03Icon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup orientation="vertical">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FlipHorizontalIcon"
|
||||
tabler="IconFlipHorizontal"
|
||||
hugeicons="FlipHorizontalIcon"
|
||||
phosphor="ArrowsHorizontalIcon"
|
||||
remixicon="RiArrowLeftRightLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FlipVerticalIcon"
|
||||
tabler="IconFlipVertical"
|
||||
hugeicons="FlipVerticalIcon"
|
||||
phosphor="ArrowsVerticalIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="RotateCwIcon"
|
||||
tabler="IconRotateClockwise2"
|
||||
hugeicons="Rotate01Icon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</ButtonGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
475
apps/v4/registry/bases/aria/examples/calendar-example.tsx
Normal file
475
apps/v4/registry/bases/aria/examples/calendar-example.tsx
Normal file
@@ -0,0 +1,475 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import {
|
||||
CalendarDate,
|
||||
getLocalTimeZone,
|
||||
isSameDay,
|
||||
isWeekend,
|
||||
today,
|
||||
} from "@internationalized/date"
|
||||
import { I18nProvider, useLocale, type DateRange } from "react-aria-components"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { Calendar, RangeCalendar } from "@/registry/bases/aria/ui/calendar"
|
||||
import { Card, CardContent, CardFooter } from "@/registry/bases/aria/ui/card"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { Popover, PopoverTrigger } from "@/registry/bases/aria/ui/popover"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function CalendarExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CalendarSingle />
|
||||
<CalendarMultiple />
|
||||
<CalendarBookedDates />
|
||||
<CalendarRange />
|
||||
<CalendarRangeMultipleMonths />
|
||||
<CalendarWithTime />
|
||||
<CalendarWithPresets />
|
||||
<CalendarCustomDays />
|
||||
<DatePickerSimple />
|
||||
<DataPickerWithDropdowns />
|
||||
<DatePickerWithRange />
|
||||
<CalendarInCard />
|
||||
<CalendarInPopover />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarInCard() {
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarInPopover() {
|
||||
return (
|
||||
<Example title="In Popover">
|
||||
<PopoverTrigger>
|
||||
<Button variant="outline" className="px-2.5 font-normal">
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Open Calendar
|
||||
</Button>
|
||||
<Popover className="w-auto p-0" placement="bottom start">
|
||||
<Calendar />
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarSingle() {
|
||||
const [date, setDate] = React.useState<CalendarDate | undefined>(
|
||||
new CalendarDate(new Date().getFullYear(), new Date().getMonth() + 1, 12)
|
||||
)
|
||||
return (
|
||||
<Example title="Single">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar value={date} onChange={setDate} captionLayout="dropdown" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarMultiple() {
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar selectionMode="multiple" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarRange() {
|
||||
const [dateRange, setDateRange] = React.useState<DateRange | undefined>({
|
||||
start: new CalendarDate(new Date().getFullYear(), 1, 12),
|
||||
end: new CalendarDate(new Date().getFullYear(), 1, 12).add({ days: 30 }),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example
|
||||
title="Range"
|
||||
containerClassName="lg:col-span-full 2xl:col-span-full"
|
||||
className="p-12"
|
||||
>
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<RangeCalendar
|
||||
value={dateRange}
|
||||
onChange={setDateRange}
|
||||
numberOfMonths={2}
|
||||
maxValue={today(getLocalTimeZone())}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarRangeMultipleMonths() {
|
||||
const [range, setRange] = React.useState<DateRange | undefined>({
|
||||
start: new CalendarDate(new Date().getFullYear(), 4, 12),
|
||||
end: new CalendarDate(new Date().getFullYear(), 4, 12).add({ days: 60 }),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example
|
||||
title="Range Multiple Months"
|
||||
containerClassName="lg:col-span-full 2xl:col-span-full"
|
||||
className="p-12"
|
||||
>
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<I18nProvider locale="es">
|
||||
<RangeCalendar
|
||||
value={range}
|
||||
onChange={setRange}
|
||||
numberOfMonths={3}
|
||||
weeksInMonth={6}
|
||||
/>
|
||||
</I18nProvider>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarBookedDates() {
|
||||
const [date, setDate] = React.useState<CalendarDate | undefined>(
|
||||
new CalendarDate(new Date().getFullYear(), 2, 3)
|
||||
)
|
||||
const bookedDates = Array.from(
|
||||
{ length: 15 },
|
||||
(_, i) => new CalendarDate(new Date().getFullYear(), 2, 12 + i)
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="Booked Dates">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<Calendar
|
||||
value={date}
|
||||
onChange={setDate}
|
||||
isDateUnavailable={(date) =>
|
||||
bookedDates.some((d) => isSameDay(date, d))
|
||||
}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarWithTime() {
|
||||
const [date, setDate] = React.useState<CalendarDate | undefined>(
|
||||
new CalendarDate(new Date().getFullYear(), new Date().getMonth() + 1, 12)
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Time">
|
||||
<Card size="sm" className="mx-auto w-fit">
|
||||
<CardContent>
|
||||
<Calendar value={date} onChange={setDate} className="p-0" />
|
||||
</CardContent>
|
||||
<CardFooter className="border-t bg-card">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="time-from">Start Time</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="time-from"
|
||||
type="time"
|
||||
step="1"
|
||||
defaultValue="10:30:00"
|
||||
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="Clock2Icon"
|
||||
tabler="IconClockHour2"
|
||||
hugeicons="Clock03Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="time-to">End Time</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="time-to"
|
||||
type="time"
|
||||
step="1"
|
||||
defaultValue="12:30:00"
|
||||
className="appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none"
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="Clock2Icon"
|
||||
tabler="IconClockHour2"
|
||||
hugeicons="Clock03Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarCustomDays() {
|
||||
const { locale } = useLocale()
|
||||
const [range, setRange] = React.useState<DateRange | undefined>({
|
||||
start: new CalendarDate(new Date().getFullYear(), 12, 8),
|
||||
end: new CalendarDate(new Date().getFullYear(), 12, 8).add({ days: 10 }),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example title="Custom Days">
|
||||
<Card className="mx-auto w-fit p-0">
|
||||
<CardContent className="p-0">
|
||||
<RangeCalendar
|
||||
value={range}
|
||||
onChange={setRange}
|
||||
numberOfMonths={1}
|
||||
captionLayout="dropdown"
|
||||
className="[--cell-size:--spacing(10)] md:[--cell-size:--spacing(12)]"
|
||||
headerFormat={{ month: "long" }}
|
||||
renderCell={({ isOutsideMonth, date, defaultChildren }) => (
|
||||
<>
|
||||
{defaultChildren}
|
||||
{!isOutsideMonth && (
|
||||
<span>{isWeekend(date, locale) ? "$120" : "$100"}</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CalendarWithPresets() {
|
||||
const [date, setDate] = React.useState<CalendarDate | undefined>(
|
||||
new CalendarDate(new Date().getFullYear(), 2, 12)
|
||||
)
|
||||
const [currentMonth, setCurrentMonth] = React.useState<CalendarDate>(
|
||||
new CalendarDate(new Date().getFullYear(), new Date().getMonth() + 1, 1)
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Presets">
|
||||
<Card className="mx-auto w-fit max-w-[300px]" size="sm">
|
||||
<CardContent>
|
||||
<Calendar
|
||||
value={date}
|
||||
onChange={setDate}
|
||||
focusedValue={currentMonth}
|
||||
onFocusChange={setCurrentMonth}
|
||||
weeksInMonth={6}
|
||||
className="p-0 [--cell-size:--spacing(9.5)]"
|
||||
/>
|
||||
</CardContent>
|
||||
<CardFooter className="flex flex-wrap gap-2 border-t">
|
||||
{[
|
||||
{ label: "Today", value: 0 },
|
||||
{ label: "Tomorrow", value: 1 },
|
||||
{ label: "In 3 days", value: 3 },
|
||||
{ label: "In a week", value: 7 },
|
||||
{ label: "In 2 weeks", value: 14 },
|
||||
].map((preset) => (
|
||||
<Button
|
||||
key={preset.value}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex-1"
|
||||
onPress={() => {
|
||||
const newDate = today(getLocalTimeZone()).add({
|
||||
days: preset.value,
|
||||
})
|
||||
setDate(newDate)
|
||||
setCurrentMonth(newDate)
|
||||
}}
|
||||
>
|
||||
{preset.label}
|
||||
</Button>
|
||||
))}
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DatePickerSimple() {
|
||||
const [date, setDate] = React.useState<CalendarDate>()
|
||||
|
||||
return (
|
||||
<Example title="Date Picker Simple">
|
||||
<Field className="mx-auto w-72">
|
||||
<FieldLabel htmlFor="date-picker-simple">Date</FieldLabel>
|
||||
<PopoverTrigger>
|
||||
<Button
|
||||
variant="outline"
|
||||
id="date-picker-simple"
|
||||
className="justify-start px-2.5 font-normal"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
{date ? (
|
||||
date
|
||||
.toDate(getLocalTimeZone())
|
||||
.toLocaleDateString(undefined, { dateStyle: "long" })
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
</Button>
|
||||
<Popover className="w-auto p-0" placement="bottom start">
|
||||
<Calendar value={date} onChange={setDate} />
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DatePickerWithRange() {
|
||||
const [date, setDate] = React.useState<DateRange | undefined>({
|
||||
start: new CalendarDate(new Date().getFullYear(), 1, 20),
|
||||
end: new CalendarDate(new Date().getFullYear(), 1, 20).add({ days: 20 }),
|
||||
})
|
||||
|
||||
return (
|
||||
<Example title="Date Picker Range">
|
||||
<Field className="mx-auto w-72">
|
||||
<FieldLabel htmlFor="date-picker-range">Date Picker Range</FieldLabel>
|
||||
<PopoverTrigger>
|
||||
<Button
|
||||
variant="outline"
|
||||
id="date-picker-range"
|
||||
className="justify-start px-2.5 font-normal"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
{date?.start && date.end ? (
|
||||
new Intl.DateTimeFormat(undefined, {
|
||||
dateStyle: "long",
|
||||
}).formatRange(
|
||||
date.start.toDate(getLocalTimeZone()),
|
||||
date.end.toDate(getLocalTimeZone())
|
||||
)
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
</Button>
|
||||
<Popover className="w-auto p-0" placement="bottom start">
|
||||
<RangeCalendar value={date} onChange={setDate} numberOfMonths={2} />
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DataPickerWithDropdowns() {
|
||||
const [date, setDate] = React.useState<CalendarDate>()
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Date Picker with Dropdowns">
|
||||
<Field className="mx-auto w-72">
|
||||
<FieldLabel htmlFor="date-picker-with-dropdowns-desktop">
|
||||
Date
|
||||
</FieldLabel>
|
||||
<PopoverTrigger isOpen={open} onOpenChange={setOpen}>
|
||||
<Button
|
||||
variant="outline"
|
||||
id="date-picker-with-dropdowns-desktop"
|
||||
className="justify-start px-2.5 font-normal"
|
||||
>
|
||||
{date ? (
|
||||
date
|
||||
.toDate(getLocalTimeZone())
|
||||
.toLocaleDateString(undefined, { dateStyle: "long" })
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDownIcon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
data-icon="inline-start"
|
||||
className="ml-auto"
|
||||
/>
|
||||
</Button>
|
||||
<Popover className="w-auto p-0" placement="bottom start">
|
||||
<Calendar
|
||||
value={date}
|
||||
onChange={setDate}
|
||||
captionLayout="dropdown"
|
||||
/>
|
||||
<div className="flex gap-2 border-t p-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="w-full"
|
||||
onPress={() => setOpen(false)}
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
</div>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
490
apps/v4/registry/bases/aria/examples/card-example.tsx
Normal file
490
apps/v4/registry/bases/aria/examples/card-example.tsx
Normal file
@@ -0,0 +1,490 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarGroup,
|
||||
AvatarGroupCount,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/aria/ui/avatar"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/aria/ui/toggle-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const spacingOptions = [
|
||||
{
|
||||
className: "[--card-spacing:--spacing(4)]",
|
||||
label: "16px",
|
||||
value: "4",
|
||||
},
|
||||
{
|
||||
className: "[--card-spacing:--spacing(5)]",
|
||||
label: "20px",
|
||||
value: "5",
|
||||
},
|
||||
{
|
||||
className: "[--card-spacing:--spacing(6)]",
|
||||
label: "24px",
|
||||
value: "6",
|
||||
},
|
||||
{
|
||||
className: "[--card-spacing:--spacing(8)]",
|
||||
label: "32px",
|
||||
value: "8",
|
||||
},
|
||||
]
|
||||
|
||||
export default function CardExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CardDefault />
|
||||
<CardSmall />
|
||||
<CardContentEdgeToEdge />
|
||||
<CardCustomSpacing />
|
||||
<CardHeaderWithBorder />
|
||||
<CardFooterWithBorder />
|
||||
<CardHeaderWithBorderSmall />
|
||||
<CardFooterWithBorderSmall />
|
||||
<CardWithImage />
|
||||
<CardWithImageSmall />
|
||||
<CardLogin />
|
||||
<CardMeetingNotes />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CardContentEdgeToEdge() {
|
||||
return (
|
||||
<Example title="Content Edge to Edge">
|
||||
<Card className="mx-auto w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Terms of Service</CardTitle>
|
||||
<CardDescription>
|
||||
Review the terms before accepting the agreement.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="-mb-(--card-spacing) px-0">
|
||||
<div className="max-h-48 space-y-4 overflow-y-scroll border-t bg-muted/50 px-(--card-spacing) py-4 text-sm leading-relaxed">
|
||||
<p>
|
||||
These terms govern your use of the workspace, including access to
|
||||
shared documents, project files, and collaboration tools.
|
||||
</p>
|
||||
<p>
|
||||
You are responsible for the content you upload and for ensuring
|
||||
that your team has the appropriate permissions to view or edit it.
|
||||
</p>
|
||||
<p>
|
||||
We may update features or limits as the service evolves. When
|
||||
those changes materially affect your workflow, we will notify your
|
||||
workspace administrators.
|
||||
</p>
|
||||
<p>
|
||||
By continuing, you agree to keep your account credentials secure
|
||||
and to follow your organization's acceptable use policies.
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
<CardFooter className="justify-end gap-2">
|
||||
<Button variant="outline">Decline</Button>
|
||||
<Button>Accept</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardCustomSpacing() {
|
||||
const [spacing, setSpacing] = React.useState("4")
|
||||
const selectedSpacing = spacingOptions.find(
|
||||
(option) => option.value === spacing
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="Custom Spacing">
|
||||
<div className="mx-auto grid w-full max-w-sm gap-4">
|
||||
<ToggleGroup
|
||||
selectedKeys={[spacing]}
|
||||
onSelectionChange={(keys) => {
|
||||
const key = Array.from(keys)[0]
|
||||
if (key) {
|
||||
setSpacing(String(key))
|
||||
}
|
||||
}}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="justify-center"
|
||||
>
|
||||
{spacingOptions.map((option) => (
|
||||
<ToggleGroupItem key={option.value} id={option.value}>
|
||||
{option.label}
|
||||
</ToggleGroupItem>
|
||||
))}
|
||||
</ToggleGroup>
|
||||
<Card className={selectedSpacing?.className}>
|
||||
<CardHeader>
|
||||
<CardTitle>Release Health</CardTitle>
|
||||
<CardDescription>
|
||||
Track readiness across launch signals.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid gap-2 rounded-lg bg-muted/50 p-3 text-sm style-lyra:rounded-none style-sera:rounded-none">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-muted-foreground">Checks passed</span>
|
||||
<span className="font-medium">24 / 26</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-muted-foreground">Open blockers</span>
|
||||
<span className="font-medium">2</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardLogin() {
|
||||
return (
|
||||
<Example title="Login">
|
||||
<Card className="mx-auto w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Login to your account</CardTitle>
|
||||
<CardDescription>
|
||||
Enter your email below to login to your account
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="email">Email</FieldLabel>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="m@example.com"
|
||||
required
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<div className="flex items-center">
|
||||
<FieldLabel htmlFor="password">Password</FieldLabel>
|
||||
<a
|
||||
href="#"
|
||||
className="ml-auto inline-block underline-offset-4 hover:underline"
|
||||
>
|
||||
Forgot your password?
|
||||
</a>
|
||||
</div>
|
||||
<Input id="password" type="password" required />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<Button type="submit" className="w-full">
|
||||
Login
|
||||
</Button>
|
||||
<Button variant="outline" className="w-full">
|
||||
Login with Google
|
||||
</Button>
|
||||
<div className="mt-4 text-center">
|
||||
Don't have an account?{" "}
|
||||
<a href="#" className="underline underline-offset-4">
|
||||
Sign up
|
||||
</a>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardMeetingNotes() {
|
||||
return (
|
||||
<Example title="Meeting Notes">
|
||||
<Card className="mx-auto w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Meeting Notes</CardTitle>
|
||||
<CardDescription>
|
||||
Transcript from the meeting with the client.
|
||||
</CardDescription>
|
||||
<CardAction>
|
||||
<Button variant="outline" size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="CaptionsIcon"
|
||||
tabler="IconTextCaption"
|
||||
hugeicons="TextCheckIcon"
|
||||
phosphor="TextTIcon"
|
||||
remixicon="RiTextWrap"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Transcribe
|
||||
</Button>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>
|
||||
Client requested dashboard redesign with focus on mobile
|
||||
responsiveness.
|
||||
</p>
|
||||
<ol className="mt-4 flex list-decimal flex-col gap-2 pl-6">
|
||||
<li>New analytics widgets for daily/weekly metrics</li>
|
||||
<li>Simplified navigation menu</li>
|
||||
<li>Dark mode support</li>
|
||||
<li>Timeline: 6 weeks</li>
|
||||
<li>Follow-up meeting scheduled for next Tuesday</li>
|
||||
</ol>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<AvatarGroup>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/maxleiter.png"
|
||||
alt="@maxleiter"
|
||||
/>
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
<AvatarGroupCount>+8</AvatarGroupCount>
|
||||
</AvatarGroup>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardWithImage() {
|
||||
return (
|
||||
<Example title="With Image">
|
||||
<Card size="default" className="relative mx-auto w-full max-w-sm pt-0">
|
||||
<div className="absolute inset-0 z-30 aspect-video bg-primary opacity-50 mix-blend-color" />
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
||||
alt="Photo by mymind on Unsplash"
|
||||
title="Photo by mymind on Unsplash"
|
||||
className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
|
||||
/>
|
||||
<CardHeader>
|
||||
<CardTitle>Beautiful Landscape</CardTitle>
|
||||
<CardDescription>
|
||||
A stunning view that captures the essence of natural beauty.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<Button className="w-full">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="Add01Icon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardWithImageSmall() {
|
||||
return (
|
||||
<Example title="With Image (Small)">
|
||||
<Card size="sm" className="relative mx-auto w-full max-w-sm pt-0">
|
||||
<div className="absolute inset-0 z-30 aspect-video bg-primary opacity-50 mix-blend-color" />
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
||||
alt="Photo by mymind on Unsplash"
|
||||
title="Photo by mymind on Unsplash"
|
||||
className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
|
||||
/>
|
||||
<CardHeader>
|
||||
<CardTitle>Beautiful Landscape</CardTitle>
|
||||
<CardDescription>
|
||||
A stunning view that captures the essence of natural beauty.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<Button size="sm" className="w-full">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="Add01Icon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardHeaderWithBorder() {
|
||||
return (
|
||||
<Example title="Header with Border">
|
||||
<Card className="mx-auto w-full max-w-sm">
|
||||
<CardHeader className="border-b">
|
||||
<CardTitle>Header with Border</CardTitle>
|
||||
<CardDescription>
|
||||
This is a card with a header that has a bottom border.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>
|
||||
The header has a border-b class applied, creating a visual
|
||||
separation between the header and content sections.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardFooterWithBorder() {
|
||||
return (
|
||||
<Example title="Footer with Border">
|
||||
<Card className="mx-auto w-full max-w-sm">
|
||||
<CardContent>
|
||||
<p>
|
||||
The footer has a border-t class applied, creating a visual
|
||||
separation between the content and footer sections.
|
||||
</p>
|
||||
</CardContent>
|
||||
<CardFooter className="border-t">
|
||||
<Button variant="outline" className="w-full">
|
||||
Footer with Border
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardDefault() {
|
||||
return (
|
||||
<Example title="Default Size">
|
||||
<Card size="default" className="mx-auto w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Default Card</CardTitle>
|
||||
<CardDescription>
|
||||
This card uses the default size variant.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>
|
||||
The card component supports a size prop that defaults to
|
||||
"default" for standard spacing and sizing.
|
||||
</p>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button variant="outline" className="w-full">
|
||||
Action
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardSmall() {
|
||||
return (
|
||||
<Example title="Small Size">
|
||||
<Card size="sm" className="mx-auto w-full max-w-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Small Card</CardTitle>
|
||||
<CardDescription>
|
||||
This card uses the small size variant.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>
|
||||
The card component supports a size prop that can be set to
|
||||
"sm" for a more compact appearance.
|
||||
</p>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button variant="outline" size="sm" className="w-full">
|
||||
Action
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardHeaderWithBorderSmall() {
|
||||
return (
|
||||
<Example title="Header with Border (Small)">
|
||||
<Card size="sm" className="mx-auto w-full max-w-sm">
|
||||
<CardHeader className="border-b">
|
||||
<CardTitle>Header with Border</CardTitle>
|
||||
<CardDescription>
|
||||
This is a small card with a header that has a bottom border.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>
|
||||
The header has a border-b class applied, creating a visual
|
||||
separation between the header and content sections.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CardFooterWithBorderSmall() {
|
||||
return (
|
||||
<Example title="Footer with Border (Small)">
|
||||
<Card size="sm" className="mx-auto w-full max-w-sm">
|
||||
<CardContent>
|
||||
<p>
|
||||
The footer has a border-t class applied, creating a visual
|
||||
separation between the content and footer sections.
|
||||
</p>
|
||||
</CardContent>
|
||||
<CardFooter className="border-t">
|
||||
<Button variant="outline" size="sm" className="w-full">
|
||||
Footer with Border
|
||||
</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
99
apps/v4/registry/bases/aria/examples/carousel-example.tsx
Normal file
99
apps/v4/registry/bases/aria/examples/carousel-example.tsx
Normal file
@@ -0,0 +1,99 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Card, CardContent } from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/registry/bases/aria/ui/carousel"
|
||||
|
||||
export default function CarouselExample() {
|
||||
return (
|
||||
<ExampleWrapper className="lg:grid-cols-1">
|
||||
<CarouselBasic />
|
||||
<CarouselMultiple />
|
||||
<CarouselWithGap />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Carousel className="mx-auto max-w-xs sm:max-w-sm">
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index}>
|
||||
<div className="p-1 style-luma:p-2.5">
|
||||
<Card>
|
||||
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||
<span className="text-4xl font-semibold">{index + 1}</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious className="hidden sm:inline-flex" />
|
||||
<CarouselNext className="hidden sm:inline-flex" />
|
||||
</Carousel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselMultiple() {
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Carousel
|
||||
className="mx-auto max-w-xs sm:max-w-sm"
|
||||
opts={{
|
||||
align: "start",
|
||||
}}
|
||||
>
|
||||
<CarouselContent>
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index} className="sm:basis-1/2 lg:basis-1/3">
|
||||
<div className="p-1 style-luma:p-2.5">
|
||||
<Card>
|
||||
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||
<span className="text-3xl font-semibold">{index + 1}</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious className="hidden sm:inline-flex" />
|
||||
<CarouselNext className="hidden sm:inline-flex" />
|
||||
</Carousel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CarouselWithGap() {
|
||||
return (
|
||||
<Example title="With Gap">
|
||||
<Carousel className="mx-auto max-w-xs sm:max-w-sm">
|
||||
<CarouselContent className="-ml-1">
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<CarouselItem key={index} className="pl-1 md:basis-1/2">
|
||||
<div className="p-1 style-luma:p-2.5">
|
||||
<Card>
|
||||
<CardContent className="flex aspect-square items-center justify-center p-6">
|
||||
<span className="text-2xl font-semibold">{index + 1}</span>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<CarouselPrevious className="hidden sm:inline-flex" />
|
||||
<CarouselNext className="hidden sm:inline-flex" />
|
||||
</Carousel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
582
apps/v4/registry/bases/aria/examples/chart-example.tsx
Normal file
582
apps/v4/registry/bases/aria/examples/chart-example.tsx
Normal file
@@ -0,0 +1,582 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import {
|
||||
Area,
|
||||
AreaChart,
|
||||
Bar,
|
||||
BarChart,
|
||||
CartesianGrid,
|
||||
Label,
|
||||
Line,
|
||||
LineChart,
|
||||
Pie,
|
||||
PieChart,
|
||||
PolarAngleAxis,
|
||||
PolarGrid,
|
||||
PolarRadiusAxis,
|
||||
Radar,
|
||||
RadarChart,
|
||||
RadialBar,
|
||||
RadialBarChart,
|
||||
XAxis,
|
||||
} from "recharts"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
type ChartConfig,
|
||||
} from "@/registry/bases/aria/ui/chart"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const areaChartData = [
|
||||
{ month: "January", desktop: 186 },
|
||||
{ month: "February", desktop: 305 },
|
||||
{ month: "March", desktop: 237 },
|
||||
{ month: "April", desktop: 73 },
|
||||
{ month: "May", desktop: 209 },
|
||||
{ month: "June", desktop: 214 },
|
||||
]
|
||||
|
||||
const areaChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
export default function ChartExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ChartAreaExample />
|
||||
<ChartBarExample />
|
||||
<ChartLineExample />
|
||||
<ChartPieExample />
|
||||
<ChartRadialExample />
|
||||
<ChartRadarExample />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ChartAreaExample() {
|
||||
return (
|
||||
<Example title="Area Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Area Chart</CardTitle>
|
||||
<CardDescription>
|
||||
Showing total visitors for the last 6 months
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={areaChartConfig}>
|
||||
<AreaChart
|
||||
accessibilityLayer
|
||||
data={areaChartData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="line" />}
|
||||
/>
|
||||
<Area
|
||||
dataKey="desktop"
|
||||
type="natural"
|
||||
fill="var(--color-desktop)"
|
||||
fillOpacity={0.4}
|
||||
stroke="var(--color-desktop)"
|
||||
/>
|
||||
</AreaChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="flex w-full items-start gap-2">
|
||||
<div className="grid gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 leading-none text-muted-foreground">
|
||||
January - June 2024
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const barChartData = [
|
||||
{ month: "January", desktop: 186, mobile: 80 },
|
||||
{ month: "February", desktop: 305, mobile: 200 },
|
||||
{ month: "March", desktop: 237, mobile: 120 },
|
||||
{ month: "April", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "June", desktop: 214, mobile: 140 },
|
||||
]
|
||||
|
||||
const barChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
mobile: {
|
||||
label: "Mobile",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartBarExample() {
|
||||
return (
|
||||
<Example title="Bar Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Bar Chart - Multiple</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={barChartConfig}>
|
||||
<BarChart accessibilityLayer data={barChartData}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="dashed" />}
|
||||
/>
|
||||
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
|
||||
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col items-start gap-2">
|
||||
<div className="flex gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const lineChartData = [
|
||||
{ month: "January", desktop: 186, mobile: 80 },
|
||||
{ month: "February", desktop: 305, mobile: 200 },
|
||||
{ month: "March", desktop: 237, mobile: 120 },
|
||||
{ month: "April", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "June", desktop: 214, mobile: 140 },
|
||||
]
|
||||
|
||||
const lineChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
mobile: {
|
||||
label: "Mobile",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartLineExample() {
|
||||
return (
|
||||
<Example title="Line Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Line Chart - Multiple</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={lineChartConfig}>
|
||||
<LineChart
|
||||
accessibilityLayer
|
||||
data={lineChartData}
|
||||
margin={{
|
||||
left: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid vertical={false} />
|
||||
<XAxis
|
||||
dataKey="month"
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={(value) => value.slice(0, 3)}
|
||||
/>
|
||||
<ChartTooltip cursor={false} content={<ChartTooltipContent />} />
|
||||
<Line
|
||||
dataKey="desktop"
|
||||
type="monotone"
|
||||
stroke="var(--color-desktop)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
<Line
|
||||
dataKey="mobile"
|
||||
type="monotone"
|
||||
stroke="var(--color-mobile)"
|
||||
strokeWidth={2}
|
||||
dot={false}
|
||||
/>
|
||||
</LineChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<div className="flex w-full items-start gap-2">
|
||||
<div className="grid gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const pieChartData = [
|
||||
{ browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
|
||||
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
|
||||
{ browser: "firefox", visitors: 287, fill: "var(--color-firefox)" },
|
||||
{ browser: "edge", visitors: 173, fill: "var(--color-edge)" },
|
||||
{ browser: "other", visitors: 190, fill: "var(--color-other)" },
|
||||
]
|
||||
|
||||
const pieChartConfig = {
|
||||
visitors: {
|
||||
label: "Visitors",
|
||||
},
|
||||
chrome: {
|
||||
label: "Chrome",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
safari: {
|
||||
label: "Safari",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
firefox: {
|
||||
label: "Firefox",
|
||||
color: "var(--chart-3)",
|
||||
},
|
||||
edge: {
|
||||
label: "Edge",
|
||||
color: "var(--chart-4)",
|
||||
},
|
||||
other: {
|
||||
label: "Other",
|
||||
color: "var(--chart-5)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartPieExample() {
|
||||
const totalVisitors = React.useMemo(() => {
|
||||
return pieChartData.reduce((acc, curr) => acc + curr.visitors, 0)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Example title="Pie Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader className="items-center pb-0">
|
||||
<CardTitle>Pie Chart - Donut with Text</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 pb-0">
|
||||
<ChartContainer
|
||||
config={pieChartConfig}
|
||||
className="mx-auto aspect-square max-h-[250px]"
|
||||
>
|
||||
<PieChart>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent hideLabel />}
|
||||
/>
|
||||
<Pie
|
||||
data={pieChartData}
|
||||
dataKey="visitors"
|
||||
nameKey="browser"
|
||||
innerRadius={60}
|
||||
strokeWidth={5}
|
||||
>
|
||||
<Label
|
||||
content={({ viewBox }) => {
|
||||
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
||||
return (
|
||||
<text
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
className="fill-foreground text-3xl font-bold"
|
||||
>
|
||||
{totalVisitors.toLocaleString()}
|
||||
</tspan>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) + 24}
|
||||
className="fill-muted-foreground"
|
||||
>
|
||||
Visitors
|
||||
</tspan>
|
||||
</text>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Pie>
|
||||
</PieChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const radarChartData = [
|
||||
{ month: "January", desktop: 186, mobile: 80 },
|
||||
{ month: "February", desktop: 305, mobile: 200 },
|
||||
{ month: "March", desktop: 237, mobile: 120 },
|
||||
{ month: "April", desktop: 73, mobile: 190 },
|
||||
{ month: "May", desktop: 209, mobile: 130 },
|
||||
{ month: "June", desktop: 214, mobile: 140 },
|
||||
]
|
||||
|
||||
const radarChartConfig = {
|
||||
desktop: {
|
||||
label: "Desktop",
|
||||
color: "var(--chart-1)",
|
||||
},
|
||||
mobile: {
|
||||
label: "Mobile",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartRadarExample() {
|
||||
return (
|
||||
<Example title="Radar Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader className="items-center pb-4">
|
||||
<CardTitle>Radar Chart - Multiple</CardTitle>
|
||||
<CardDescription>
|
||||
Showing total visitors for the last 6 months
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="pb-0">
|
||||
<ChartContainer
|
||||
config={radarChartConfig}
|
||||
className="mx-auto aspect-square max-h-[250px]"
|
||||
>
|
||||
<RadarChart data={radarChartData}>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent indicator="line" />}
|
||||
/>
|
||||
<PolarAngleAxis dataKey="month" />
|
||||
<PolarGrid />
|
||||
<Radar
|
||||
dataKey="desktop"
|
||||
fill="var(--color-desktop)"
|
||||
fillOpacity={0.6}
|
||||
/>
|
||||
<Radar dataKey="mobile" fill="var(--color-mobile)" />
|
||||
</RadarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 leading-none text-muted-foreground">
|
||||
January - June 2024
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const radialChartData = [
|
||||
{ browser: "safari", visitors: 1260, fill: "var(--color-safari)" },
|
||||
]
|
||||
|
||||
const radialChartConfig = {
|
||||
visitors: {
|
||||
label: "Visitors",
|
||||
},
|
||||
safari: {
|
||||
label: "Safari",
|
||||
color: "var(--chart-2)",
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
|
||||
function ChartRadialExample() {
|
||||
return (
|
||||
<Example title="Radial Chart">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Radial Chart - Shape</CardTitle>
|
||||
<CardDescription>January - June 2024</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="flex-1 pb-0">
|
||||
<ChartContainer
|
||||
config={radialChartConfig}
|
||||
className="mx-auto aspect-square max-h-[210px]"
|
||||
>
|
||||
<RadialBarChart
|
||||
data={radialChartData}
|
||||
endAngle={100}
|
||||
innerRadius={64}
|
||||
outerRadius={94}
|
||||
>
|
||||
<PolarGrid
|
||||
gridType="circle"
|
||||
radialLines={false}
|
||||
stroke="none"
|
||||
className="first:fill-muted last:fill-background"
|
||||
polarRadius={[86, 74]}
|
||||
/>
|
||||
<RadialBar dataKey="visitors" background />
|
||||
<PolarRadiusAxis tick={false} tickLine={false} axisLine={false}>
|
||||
<Label
|
||||
content={({ viewBox }) => {
|
||||
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
|
||||
return (
|
||||
<text
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={viewBox.cy}
|
||||
className="fill-foreground text-4xl font-bold"
|
||||
>
|
||||
{radialChartData[0].visitors.toLocaleString()}
|
||||
</tspan>
|
||||
<tspan
|
||||
x={viewBox.cx}
|
||||
y={(viewBox.cy || 0) + 24}
|
||||
className="fill-muted-foreground"
|
||||
>
|
||||
Visitors
|
||||
</tspan>
|
||||
</text>
|
||||
)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</PolarRadiusAxis>
|
||||
</RadialBarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<div className="flex items-center gap-2 leading-none font-medium">
|
||||
Trending up by 5.2% this month{" "}
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="ChartUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
className="size-4"
|
||||
/>
|
||||
</div>
|
||||
<div className="leading-none text-muted-foreground">
|
||||
Showing total visitors for the last 6 months
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
221
apps/v4/registry/bases/aria/examples/checkbox-example.tsx
Normal file
221
apps/v4/registry/bases/aria/examples/checkbox-example.tsx
Normal file
@@ -0,0 +1,221 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Checkbox } from "@/registry/bases/aria/ui/checkbox"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/registry/bases/aria/ui/table"
|
||||
|
||||
export default function CheckboxExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CheckboxBasic />
|
||||
<CheckboxWithDescription />
|
||||
<CheckboxInvalid />
|
||||
<CheckboxDisabled />
|
||||
<CheckboxWithTitle />
|
||||
<CheckboxInTable />
|
||||
<CheckboxGroup />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="terms" />
|
||||
<FieldLabel htmlFor="terms">Accept terms and conditions</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="terms-2" defaultSelected />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="terms-2">Accept terms and conditions</FieldLabel>
|
||||
<FieldDescription>
|
||||
By clicking this checkbox, you agree to the terms and conditions.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<Checkbox id="terms-3" isInvalid />
|
||||
<FieldLabel htmlFor="terms-3">Accept terms and conditions</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="toggle" isDisabled />
|
||||
<FieldLabel htmlFor="toggle">Enable notifications</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxWithTitle() {
|
||||
return (
|
||||
<Example title="With Title">
|
||||
<FieldGroup>
|
||||
<FieldLabel htmlFor="toggle-2">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="toggle-2" defaultSelected />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable notifications</FieldTitle>
|
||||
<FieldDescription>
|
||||
You can enable or disable notifications at any time.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="toggle-4">
|
||||
<Field orientation="horizontal" data-disabled>
|
||||
<Checkbox id="toggle-4" isDisabled />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable notifications</FieldTitle>
|
||||
<FieldDescription>
|
||||
You can enable or disable notifications at any time.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
id: "1",
|
||||
name: "Sarah Chen",
|
||||
email: "sarah.chen@example.com",
|
||||
role: "Admin",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "Marcus Rodriguez",
|
||||
email: "marcus.rodriguez@example.com",
|
||||
role: "User",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "Priya Patel",
|
||||
email: "priya.patel@example.com",
|
||||
role: "User",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "David Kim",
|
||||
email: "david.kim@example.com",
|
||||
role: "Editor",
|
||||
},
|
||||
]
|
||||
|
||||
function CheckboxInTable() {
|
||||
return (
|
||||
<Example title="In Table">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead className="w-8">
|
||||
<Checkbox slot="selection" />
|
||||
</TableHead>
|
||||
<TableHead isRowHeader>Name</TableHead>
|
||||
<TableHead>Email</TableHead>
|
||||
<TableHead>Role</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{tableData.map((row) => (
|
||||
<TableRow key={row.id}>
|
||||
<TableCell>
|
||||
<Checkbox id={`row-${row.id}`} slot="selection" />
|
||||
</TableCell>
|
||||
<TableCell className="font-medium">{row.name}</TableCell>
|
||||
<TableCell>{row.email}</TableCell>
|
||||
<TableCell>{row.role}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxGroup() {
|
||||
return (
|
||||
<Example title="Group">
|
||||
<Field>
|
||||
<FieldLabel>Show these items on the desktop:</FieldLabel>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-hard-disks-ljj" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-hard-disks-ljj"
|
||||
className="font-normal"
|
||||
>
|
||||
Hard disks
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-external-disks-1yg" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-external-disks-1yg"
|
||||
className="font-normal"
|
||||
>
|
||||
External disks
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-cds-dvds-fzt" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-cds-dvds-fzt"
|
||||
className="font-normal"
|
||||
>
|
||||
CDs, DVDs, and iPods
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="finder-pref-9k2-connected-servers-6l2" />
|
||||
<FieldLabel
|
||||
htmlFor="finder-pref-9k2-connected-servers-6l2"
|
||||
className="font-normal"
|
||||
>
|
||||
Connected servers
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
240
apps/v4/registry/bases/aria/examples/collapsible-example.tsx
Normal file
240
apps/v4/registry/bases/aria/examples/collapsible-example.tsx
Normal file
@@ -0,0 +1,240 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button, buttonVariants } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/registry/bases/aria/ui/collapsible"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/registry/bases/aria/ui/tabs"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function CollapsibleExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CollapsibleFileTree />
|
||||
<CollapsibleSettings />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
type FileTreeItem = { name: string } | { name: string; items: FileTreeItem[] }
|
||||
|
||||
function CollapsibleFileTree() {
|
||||
const fileTree: FileTreeItem[] = [
|
||||
{
|
||||
name: "components",
|
||||
items: [
|
||||
{
|
||||
name: "ui",
|
||||
items: [
|
||||
{ name: "button.tsx" },
|
||||
{ name: "card.tsx" },
|
||||
{ name: "dialog.tsx" },
|
||||
{ name: "input.tsx" },
|
||||
{ name: "select.tsx" },
|
||||
{ name: "table.tsx" },
|
||||
],
|
||||
},
|
||||
{ name: "login-form.tsx" },
|
||||
{ name: "register-form.tsx" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "lib",
|
||||
items: [{ name: "utils.ts" }, { name: "cn.ts" }, { name: "api.ts" }],
|
||||
},
|
||||
{
|
||||
name: "hooks",
|
||||
items: [
|
||||
{ name: "use-media-query.ts" },
|
||||
{ name: "use-debounce.ts" },
|
||||
{ name: "use-local-storage.ts" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "types",
|
||||
items: [{ name: "index.d.ts" }, { name: "api.d.ts" }],
|
||||
},
|
||||
{
|
||||
name: "public",
|
||||
items: [
|
||||
{ name: "favicon.ico" },
|
||||
{ name: "logo.svg" },
|
||||
{ name: "images" },
|
||||
],
|
||||
},
|
||||
{ name: "app.tsx" },
|
||||
{ name: "layout.tsx" },
|
||||
{ name: "globals.css" },
|
||||
{ name: "package.json" },
|
||||
{ name: "tsconfig.json" },
|
||||
{ name: "README.md" },
|
||||
{ name: ".gitignore" },
|
||||
]
|
||||
|
||||
const renderItem = (fileItem: FileTreeItem) => {
|
||||
if ("items" in fileItem) {
|
||||
return (
|
||||
<Collapsible key={fileItem.name}>
|
||||
<CollapsibleTrigger
|
||||
className={buttonVariants({
|
||||
variant: "ghost",
|
||||
size: "sm",
|
||||
className:
|
||||
"group w-full justify-start transition-none hover:bg-accent hover:text-accent-foreground",
|
||||
})}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="transition-transform group-aria-expanded:rotate-90"
|
||||
/>
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="Folder01Icon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
{fileItem.name}
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="mt-1 ml-5 style-lyra:ml-4">
|
||||
<div className="flex flex-col gap-1">
|
||||
{fileItem.items.map((child) => renderItem(child))}
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Button
|
||||
key={fileItem.name}
|
||||
variant="link"
|
||||
size="sm"
|
||||
className="w-full justify-start gap-2 text-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
<span>{fileItem.name}</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Example title="File Tree" className="items-center">
|
||||
<Card className="mx-auto w-full max-w-[16rem] gap-2" size="sm">
|
||||
<CardHeader>
|
||||
<Tabs defaultSelectedKey="explorer">
|
||||
<TabsList className="w-full">
|
||||
<TabsTrigger id="explorer">Explorer</TabsTrigger>
|
||||
<TabsTrigger id="settings">Outline</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-1">
|
||||
{fileTree.map((item) => renderItem(item))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CollapsibleSettings() {
|
||||
const [isOpen, setIsOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Settings" className="items-center">
|
||||
<Card className="mx-auto w-full max-w-xs" size="sm">
|
||||
<CardHeader>
|
||||
<CardTitle>Radius</CardTitle>
|
||||
<CardDescription>
|
||||
Set the corner radius of the element.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Collapsible
|
||||
isExpanded={isOpen}
|
||||
onExpandedChange={setIsOpen}
|
||||
className="flex items-start gap-2"
|
||||
>
|
||||
<FieldGroup className="grid w-full grid-cols-2 gap-2">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-x" className="sr-only">
|
||||
Radius X
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-y" className="sr-only">
|
||||
Radius Y
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
<CollapsibleContent className="col-span-full grid grid-cols-subgrid gap-2">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-x" className="sr-only">
|
||||
Radius X
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="radius-y" className="sr-only">
|
||||
Radius Y
|
||||
</FieldLabel>
|
||||
<Input id="radius" placeholder="0" defaultValue={0} />
|
||||
</Field>
|
||||
</CollapsibleContent>
|
||||
</FieldGroup>
|
||||
<CollapsibleTrigger
|
||||
className={buttonVariants({ variant: "outline", size: "icon" })}
|
||||
>
|
||||
{isOpen ? (
|
||||
<IconPlaceholder
|
||||
lucide="MinimizeIcon"
|
||||
tabler="IconMinimize"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
) : (
|
||||
<IconPlaceholder
|
||||
lucide="MaximizeIcon"
|
||||
tabler="IconMaximize"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
)}
|
||||
</CollapsibleTrigger>
|
||||
</Collapsible>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
1295
apps/v4/registry/bases/aria/examples/combobox-example.tsx
Normal file
1295
apps/v4/registry/bases/aria/examples/combobox-example.tsx
Normal file
File diff suppressed because it is too large
Load Diff
605
apps/v4/registry/bases/aria/examples/command-example.tsx
Normal file
605
apps/v4/registry/bases/aria/examples/command-example.tsx
Normal file
@@ -0,0 +1,605 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { Card, CardContent } from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
CommandSeparator,
|
||||
CommandShortcut,
|
||||
} from "@/registry/bases/aria/ui/command"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function CommandExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CommandInline />
|
||||
<CommandBasic />
|
||||
<CommandWithShortcuts />
|
||||
<CommandWithGroups />
|
||||
<CommandManyItems />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandInline() {
|
||||
return (
|
||||
<Example title="Inline">
|
||||
<Card className="w-full p-0">
|
||||
<CardContent className="p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList
|
||||
renderEmptyState={() => (
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
)}
|
||||
>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem textValue="Calendar">
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
/>
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Search Emoji">
|
||||
<IconPlaceholder
|
||||
lucide="SmileIcon"
|
||||
tabler="IconMoodSmile"
|
||||
hugeicons="SmileIcon"
|
||||
phosphor="SmileyIcon"
|
||||
remixicon="RiEmotionLine"
|
||||
/>
|
||||
<span>Search Emoji</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Calculator">
|
||||
<IconPlaceholder
|
||||
lucide="CalculatorIcon"
|
||||
tabler="IconCalculator"
|
||||
hugeicons="CalculatorIcon"
|
||||
phosphor="CalculatorIcon"
|
||||
remixicon="RiCalculatorLine"
|
||||
/>
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem textValue="Profile">
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Billing">
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Settings">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandBasic() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onPress={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList
|
||||
renderEmptyState={() => (
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
)}
|
||||
>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>Calendar</CommandItem>
|
||||
<CommandItem>Search Emoji</CommandItem>
|
||||
<CommandItem>Calculator</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandWithShortcuts() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="With Shortcuts">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onPress={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList
|
||||
renderEmptyState={() => (
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
)}
|
||||
>
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem textValue="Profile">
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Billing">
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Settings">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandWithGroups() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="With Groups">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onPress={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList
|
||||
renderEmptyState={() => (
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
)}
|
||||
>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem textValue="Calendar">
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
/>
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Search Emoji">
|
||||
<IconPlaceholder
|
||||
lucide="SmileIcon"
|
||||
tabler="IconMoodSmile"
|
||||
hugeicons="SmileIcon"
|
||||
phosphor="SmileyIcon"
|
||||
remixicon="RiEmotionLine"
|
||||
/>
|
||||
<span>Search Emoji</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Calculator">
|
||||
<IconPlaceholder
|
||||
lucide="CalculatorIcon"
|
||||
tabler="IconCalculator"
|
||||
hugeicons="CalculatorIcon"
|
||||
phosphor="CalculatorIcon"
|
||||
remixicon="RiCalculatorLine"
|
||||
/>
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Settings">
|
||||
<CommandItem textValue="Profile">
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Billing">
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Settings">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CommandManyItems() {
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
return (
|
||||
<Example title="Many Groups & Items">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Button
|
||||
onPress={() => setOpen(true)}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Open Menu
|
||||
</Button>
|
||||
<CommandDialog open={open} onOpenChange={setOpen}>
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList
|
||||
renderEmptyState={() => (
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
)}
|
||||
>
|
||||
<CommandGroup heading="Navigation">
|
||||
<CommandItem textValue="Home">
|
||||
<IconPlaceholder
|
||||
lucide="HomeIcon"
|
||||
tabler="IconHome"
|
||||
hugeicons="HomeIcon"
|
||||
phosphor="HouseIcon"
|
||||
remixicon="RiHomeLine"
|
||||
/>
|
||||
<span>Home</span>
|
||||
<CommandShortcut>⌘H</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Inbox">
|
||||
<IconPlaceholder
|
||||
lucide="InboxIcon"
|
||||
tabler="IconInbox"
|
||||
hugeicons="InboxIcon"
|
||||
phosphor="TrayIcon"
|
||||
remixicon="RiInboxLine"
|
||||
/>
|
||||
<span>Inbox</span>
|
||||
<CommandShortcut>⌘I</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Documents">
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="File02Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
<span>Documents</span>
|
||||
<CommandShortcut>⌘D</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Folders">
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="FolderIcon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
<span>Folders</span>
|
||||
<CommandShortcut>⌘F</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Actions">
|
||||
<CommandItem textValue="New File">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
<span>New File</span>
|
||||
<CommandShortcut>⌘N</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="New Folder">
|
||||
<IconPlaceholder
|
||||
lucide="FolderPlusIcon"
|
||||
tabler="IconFolderPlus"
|
||||
hugeicons="FolderAddIcon"
|
||||
phosphor="FolderPlusIcon"
|
||||
remixicon="RiFolderAddLine"
|
||||
/>
|
||||
<span>New Folder</span>
|
||||
<CommandShortcut>⇧⌘N</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Copy">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
<span>Copy</span>
|
||||
<CommandShortcut>⌘C</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Cut">
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
<span>Cut</span>
|
||||
<CommandShortcut>⌘X</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Paste">
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
<span>Paste</span>
|
||||
<CommandShortcut>⌘V</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Delete">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
<span>Delete</span>
|
||||
<CommandShortcut>⌫</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="View">
|
||||
<CommandItem textValue="Grid View">
|
||||
<IconPlaceholder
|
||||
lucide="LayoutGridIcon"
|
||||
tabler="IconLayoutGrid"
|
||||
hugeicons="GridIcon"
|
||||
phosphor="GridFourIcon"
|
||||
remixicon="RiGridLine"
|
||||
/>
|
||||
<span>Grid View</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="List View">
|
||||
<IconPlaceholder
|
||||
lucide="ListIcon"
|
||||
tabler="IconList"
|
||||
hugeicons="Menu05Icon"
|
||||
phosphor="ListIcon"
|
||||
remixicon="RiListUnordered"
|
||||
/>
|
||||
<span>List View</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Zoom In">
|
||||
<IconPlaceholder
|
||||
lucide="ZoomInIcon"
|
||||
tabler="IconZoomIn"
|
||||
hugeicons="ZoomInAreaIcon"
|
||||
phosphor="MagnifyingGlassPlusIcon"
|
||||
remixicon="RiZoomInLine"
|
||||
/>
|
||||
<span>Zoom In</span>
|
||||
<CommandShortcut>⌘+</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Zoom Out">
|
||||
<IconPlaceholder
|
||||
lucide="ZoomOutIcon"
|
||||
tabler="IconZoomOut"
|
||||
hugeicons="ZoomOutAreaIcon"
|
||||
phosphor="MagnifyingGlassMinusIcon"
|
||||
remixicon="RiSearchEyeLine"
|
||||
/>
|
||||
<span>Zoom Out</span>
|
||||
<CommandShortcut>⌘-</CommandShortcut>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Account">
|
||||
<CommandItem textValue="Profile">
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
<span>Profile</span>
|
||||
<CommandShortcut>⌘P</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Billing">
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
<span>Billing</span>
|
||||
<CommandShortcut>⌘B</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Settings">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
<span>Settings</span>
|
||||
<CommandShortcut>⌘S</CommandShortcut>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Notifications">
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
<span>Notifications</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Help & Support">
|
||||
<IconPlaceholder
|
||||
lucide="HelpCircleIcon"
|
||||
tabler="IconHelpCircle"
|
||||
hugeicons="HelpCircleIcon"
|
||||
phosphor="QuestionIcon"
|
||||
remixicon="RiQuestionLine"
|
||||
/>
|
||||
<span>Help & Support</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
<CommandSeparator />
|
||||
<CommandGroup heading="Tools">
|
||||
<CommandItem textValue="Calculator">
|
||||
<IconPlaceholder
|
||||
lucide="CalculatorIcon"
|
||||
tabler="IconCalculator"
|
||||
hugeicons="CalculatorIcon"
|
||||
phosphor="CalculatorIcon"
|
||||
remixicon="RiCalculatorLine"
|
||||
/>
|
||||
<span>Calculator</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Calendar">
|
||||
<IconPlaceholder
|
||||
lucide="CalendarIcon"
|
||||
tabler="IconCalendar"
|
||||
hugeicons="CalendarIcon"
|
||||
phosphor="CalendarBlankIcon"
|
||||
remixicon="RiCalendarLine"
|
||||
/>
|
||||
<span>Calendar</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Image Editor">
|
||||
<IconPlaceholder
|
||||
lucide="ImageIcon"
|
||||
tabler="IconPhoto"
|
||||
hugeicons="ImageIcon"
|
||||
phosphor="ImageIcon"
|
||||
remixicon="RiImageLine"
|
||||
/>
|
||||
<span>Image Editor</span>
|
||||
</CommandItem>
|
||||
<CommandItem textValue="Code Editor">
|
||||
<IconPlaceholder
|
||||
lucide="CodeIcon"
|
||||
tabler="IconCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
<span>Code Editor</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</CommandDialog>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
634
apps/v4/registry/bases/aria/examples/component-example.tsx
Normal file
634
apps/v4/registry/bases/aria/examples/component-example.tsx
Normal file
@@ -0,0 +1,634 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type { Selection } from "react-aria-components"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogMedia,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/alert-dialog"
|
||||
import { Badge } from "@/registry/bases/aria/ui/badge"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
Combobox,
|
||||
ComboboxContent,
|
||||
ComboboxEmpty,
|
||||
ComboboxInput,
|
||||
ComboboxItem,
|
||||
ComboboxList,
|
||||
} from "@/registry/bases/aria/ui/combobox"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
import { Textarea } from "@/registry/bases/aria/ui/textarea"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function ComponentExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<CardExample />
|
||||
<FormExample />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function CardExample() {
|
||||
return (
|
||||
<Example title="Card" className="items-center justify-center">
|
||||
<Card className="relative w-full max-w-sm overflow-hidden pt-0">
|
||||
<div className="absolute inset-0 z-30 aspect-video bg-primary opacity-50 mix-blend-color" />
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
|
||||
alt="Photo by mymind on Unsplash"
|
||||
title="Photo by mymind on Unsplash"
|
||||
className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
|
||||
/>
|
||||
<CardHeader>
|
||||
<CardTitle>Observability Plus is replacing Monitoring</CardTitle>
|
||||
<CardDescription>
|
||||
Switch to the improved way to explore your data, with natural
|
||||
language. Monitoring will no longer be available on the Pro plan in
|
||||
November, 2025
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<AlertDialogTrigger>
|
||||
<Button>
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Show Dialog
|
||||
</Button>
|
||||
<AlertDialog size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogMedia>
|
||||
<IconPlaceholder
|
||||
lucide="BluetoothIcon"
|
||||
tabler="IconBluetooth"
|
||||
hugeicons="BluetoothIcon"
|
||||
phosphor="BluetoothIcon"
|
||||
remixicon="RiBluetoothLine"
|
||||
/>
|
||||
</AlertDialogMedia>
|
||||
<AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to this
|
||||
device?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
<Badge variant="secondary" className="ml-auto">
|
||||
Warning
|
||||
</Badge>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const frameworks = [
|
||||
"Next.js",
|
||||
"SvelteKit",
|
||||
"Nuxt.js",
|
||||
"Remix",
|
||||
"Astro",
|
||||
] as const
|
||||
|
||||
const roleItems = [
|
||||
{ label: "Developer", value: "developer" },
|
||||
{ label: "Designer", value: "designer" },
|
||||
{ label: "Manager", value: "manager" },
|
||||
{ label: "Other", value: "other" },
|
||||
]
|
||||
|
||||
function FormExample() {
|
||||
const [notifications, setNotifications] = React.useState<Selection>(
|
||||
new Set(["email", "push"])
|
||||
)
|
||||
const [view, setView] = React.useState<Selection>(new Set(["sidebar"]))
|
||||
const [theme, setTheme] = React.useState("light")
|
||||
|
||||
return (
|
||||
<Example title="Form">
|
||||
<Card className="w-full max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle>User Information</CardTitle>
|
||||
<CardDescription>Please fill in your details below</CardDescription>
|
||||
<CardAction>
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="ghost" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="MoreVerticalIcon"
|
||||
tabler="IconDotsVertical"
|
||||
hugeicons="MoreVerticalCircle01Icon"
|
||||
phosphor="DotsThreeVerticalIcon"
|
||||
remixicon="RiMore2Line"
|
||||
/>
|
||||
<span className="sr-only">More options</span>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom end" className="w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>File</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
New File
|
||||
<DropdownMenuShortcut>⌘N</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="FolderIcon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
New Folder
|
||||
<DropdownMenuShortcut>⇧⌘N</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="FolderOpenIcon"
|
||||
tabler="IconFolderOpen"
|
||||
hugeicons="FolderOpenIcon"
|
||||
phosphor="FolderOpenIcon"
|
||||
remixicon="RiFolderOpenLine"
|
||||
/>
|
||||
Open Recent
|
||||
</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Recent Projects</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Alpha
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Beta
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
More Projects
|
||||
</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Gamma
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileCodeIcon"
|
||||
tabler="IconFileCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Project Delta
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FolderSearchIcon"
|
||||
tabler="IconFolderSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
Browse...
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="SaveIcon"
|
||||
tabler="IconDeviceFloppy"
|
||||
hugeicons="FloppyDiskIcon"
|
||||
phosphor="FloppyDiskIcon"
|
||||
remixicon="RiSaveLine"
|
||||
/>
|
||||
Save
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="DownloadIcon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
Export
|
||||
<DropdownMenuShortcut>⇧⌘E</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={notifications}
|
||||
onSelectionChange={setNotifications}
|
||||
>
|
||||
<DropdownMenuLabel>View</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="sidebar">
|
||||
<IconPlaceholder
|
||||
lucide="EyeIcon"
|
||||
tabler="IconEye"
|
||||
hugeicons="EyeIcon"
|
||||
phosphor="EyeIcon"
|
||||
remixicon="RiEyeLine"
|
||||
/>
|
||||
Show Sidebar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="status-bar">
|
||||
<IconPlaceholder
|
||||
lucide="LayoutIcon"
|
||||
tabler="IconLayout"
|
||||
hugeicons="LayoutIcon"
|
||||
phosphor="LayoutIcon"
|
||||
remixicon="RiLayoutLine"
|
||||
/>
|
||||
Show Status Bar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="PaletteIcon"
|
||||
tabler="IconPalette"
|
||||
hugeicons="PaintBoardIcon"
|
||||
phosphor="PaletteIcon"
|
||||
remixicon="RiPaletteLine"
|
||||
/>
|
||||
Theme
|
||||
</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup
|
||||
selectionMode="single"
|
||||
selectedKeys={[theme]}
|
||||
onSelectionChange={(keys) =>
|
||||
setTheme(
|
||||
keys === "all"
|
||||
? "system"
|
||||
: (keys.values().next().value as string)
|
||||
)
|
||||
}
|
||||
>
|
||||
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="light">
|
||||
<IconPlaceholder
|
||||
lucide="SunIcon"
|
||||
tabler="IconSun"
|
||||
hugeicons="SunIcon"
|
||||
phosphor="SunIcon"
|
||||
remixicon="RiSunLine"
|
||||
/>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="dark">
|
||||
<IconPlaceholder
|
||||
lucide="MoonIcon"
|
||||
tabler="IconMoon"
|
||||
hugeicons="MoonIcon"
|
||||
phosphor="MoonIcon"
|
||||
remixicon="RiMoonLine"
|
||||
/>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="system">
|
||||
<IconPlaceholder
|
||||
lucide="MonitorIcon"
|
||||
tabler="IconDeviceDesktop"
|
||||
hugeicons="ComputerIcon"
|
||||
phosphor="MonitorIcon"
|
||||
remixicon="RiComputerLine"
|
||||
/>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
Settings
|
||||
</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Preferences</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="KeyboardIcon"
|
||||
tabler="IconKeyboard"
|
||||
hugeicons="KeyboardIcon"
|
||||
phosphor="KeyboardIcon"
|
||||
remixicon="RiKeyboardLine"
|
||||
/>
|
||||
Keyboard Shortcuts
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="LanguagesIcon"
|
||||
tabler="IconLanguage"
|
||||
hugeicons="LanguageCircleIcon"
|
||||
phosphor="TranslateIcon"
|
||||
remixicon="RiTranslate"
|
||||
/>
|
||||
Language
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Notifications
|
||||
</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={notifications}
|
||||
onSelectionChange={setNotifications}
|
||||
>
|
||||
<DropdownMenuLabel>
|
||||
Notification Types
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="push">
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Push Notifications
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="email">
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
Email Notifications
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShieldIcon"
|
||||
tabler="IconShield"
|
||||
hugeicons="ShieldIcon"
|
||||
phosphor="ShieldIcon"
|
||||
remixicon="RiShieldLine"
|
||||
/>
|
||||
Privacy & Security
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="HelpCircleIcon"
|
||||
tabler="IconHelpCircle"
|
||||
hugeicons="HelpCircleIcon"
|
||||
phosphor="QuestionIcon"
|
||||
remixicon="RiQuestionLine"
|
||||
/>
|
||||
Help & Support
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
Documentation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Sign Out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form>
|
||||
<FieldGroup>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-name">Name</FieldLabel>
|
||||
<Input
|
||||
id="small-form-name"
|
||||
placeholder="Enter your name"
|
||||
required
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-role">Role</FieldLabel>
|
||||
<Select defaultValue={null}>
|
||||
<SelectTrigger id="small-form-role">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{roleItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</div>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-framework">
|
||||
Framework
|
||||
</FieldLabel>
|
||||
<Combobox allowsEmptyCollection>
|
||||
<ComboboxInput
|
||||
id="small-form-framework"
|
||||
placeholder="Select a framework"
|
||||
required
|
||||
/>
|
||||
<ComboboxContent>
|
||||
<ComboboxList
|
||||
renderEmptyState={() => (
|
||||
<ComboboxEmpty>No frameworks found.</ComboboxEmpty>
|
||||
)}
|
||||
>
|
||||
{frameworks.map((item) => (
|
||||
<ComboboxItem key={item} id={item}>
|
||||
{item}
|
||||
</ComboboxItem>
|
||||
))}
|
||||
</ComboboxList>
|
||||
</ComboboxContent>
|
||||
</Combobox>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="small-form-comments">Comments</FieldLabel>
|
||||
<Textarea
|
||||
id="small-form-comments"
|
||||
placeholder="Add any additional comments"
|
||||
/>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Button type="submit">Submit</Button>
|
||||
<Button variant="outline" type="button">
|
||||
Cancel
|
||||
</Button>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
675
apps/v4/registry/bases/aria/examples/context-menu-example.tsx
Normal file
675
apps/v4/registry/bases/aria/examples/context-menu-example.tsx
Normal file
@@ -0,0 +1,675 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { Pressable, type Selection } from "react-aria-components"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
ContextMenu,
|
||||
ContextMenuGroup,
|
||||
ContextMenuItem,
|
||||
ContextMenuLabel,
|
||||
ContextMenuSeparator,
|
||||
ContextMenuShortcut,
|
||||
ContextMenuSub,
|
||||
ContextMenuSubContent,
|
||||
ContextMenuSubTrigger,
|
||||
ContextMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/context-menu"
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ContextMenuExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ContextMenuBasic />
|
||||
<ContextMenuWithIcons />
|
||||
<ContextMenuWithSides />
|
||||
<ContextMenuWithShortcuts />
|
||||
<ContextMenuWithSubmenu />
|
||||
<ContextMenuWithGroups />
|
||||
<ContextMenuWithCheckboxes />
|
||||
<ContextMenuWithRadio />
|
||||
<ContextMenuWithDestructive />
|
||||
<ContextMenuInDialog />
|
||||
<ContextMenuWithInset />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Back</ContextMenuItem>
|
||||
<ContextMenuItem isDisabled>Forward</ContextMenuItem>
|
||||
<ContextMenuItem>Reload</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
Paste
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithShortcuts() {
|
||||
return (
|
||||
<Example title="With Shortcuts">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
Back
|
||||
<ContextMenuShortcut>⌘[</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem isDisabled>
|
||||
Forward
|
||||
<ContextMenuShortcut>⌘]</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Reload
|
||||
<ContextMenuShortcut>⌘R</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
Save
|
||||
<ContextMenuShortcut>⌘S</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Save As...
|
||||
<ContextMenuShortcut>⇧⌘S</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithSubmenu() {
|
||||
return (
|
||||
<Example title="With Submenu">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
Copy
|
||||
<ContextMenuShortcut>⌘C</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Cut
|
||||
<ContextMenuShortcut>⌘X</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger>More Tools</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Save Page...</ContextMenuItem>
|
||||
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
||||
<ContextMenuItem>Name Window...</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Developer Tools</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">Delete</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithGroups() {
|
||||
return (
|
||||
<Example title="With Groups, Labels & Separators">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>File</ContextMenuLabel>
|
||||
<ContextMenuItem>
|
||||
New File
|
||||
<ContextMenuShortcut>⌘N</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Open File
|
||||
<ContextMenuShortcut>⌘O</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Save
|
||||
<ContextMenuShortcut>⌘S</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>Edit</ContextMenuLabel>
|
||||
<ContextMenuItem>
|
||||
Undo
|
||||
<ContextMenuShortcut>⌘Z</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Redo
|
||||
<ContextMenuShortcut>⇧⌘Z</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
Cut
|
||||
<ContextMenuShortcut>⌘X</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Copy
|
||||
<ContextMenuShortcut>⌘C</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
Paste
|
||||
<ContextMenuShortcut>⌘V</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">
|
||||
Delete
|
||||
<ContextMenuShortcut>⌫</ContextMenuShortcut>
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithCheckboxes() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState<Selection>(
|
||||
new Set(["bookmarks-bar", "developer-tools"])
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Checkboxes">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<ContextMenuItem id="bookmarks-bar">
|
||||
Show Bookmarks Bar
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>Show Full URLs</ContextMenuItem>
|
||||
<ContextMenuItem id="developer-tools">
|
||||
Show Developer Tools
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithRadio() {
|
||||
const [user, setUser] = React.useState("pedro")
|
||||
const [theme, setTheme] = React.useState("light")
|
||||
|
||||
return (
|
||||
<Example title="With Radio Group">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>People</ContextMenuLabel>
|
||||
<ContextMenuGroup
|
||||
selectionMode="single"
|
||||
selectedKeys={[user]}
|
||||
onSelectionChange={(keys) =>
|
||||
setUser(
|
||||
keys === "all"
|
||||
? "pedro"
|
||||
: (keys.values().next().value as string)
|
||||
)
|
||||
}
|
||||
>
|
||||
<ContextMenuItem id="pedro">Pedro Duarte</ContextMenuItem>
|
||||
<ContextMenuItem id="colm">Colm Tuite</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>Theme</ContextMenuLabel>
|
||||
<ContextMenuGroup
|
||||
selectionMode="single"
|
||||
selectedKeys={theme}
|
||||
onSelectionChange={(keys) =>
|
||||
setTheme(
|
||||
keys === "all"
|
||||
? "light"
|
||||
: (keys.values().next().value as string)
|
||||
)
|
||||
}
|
||||
>
|
||||
<ContextMenuItem id="light">Light</ContextMenuItem>
|
||||
<ContextMenuItem id="dark">Dark</ContextMenuItem>
|
||||
<ContextMenuItem id="system">System</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithDestructive() {
|
||||
return (
|
||||
<Example title="With Destructive Items">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="PencilIcon"
|
||||
tabler="IconPencil"
|
||||
hugeicons="EditIcon"
|
||||
phosphor="PencilIcon"
|
||||
remixicon="RiPencilLine"
|
||||
/>
|
||||
Edit
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="ShareIcon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
Share
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ArchiveIcon"
|
||||
tabler="IconArchive"
|
||||
hugeicons="Archive02Icon"
|
||||
phosphor="ArchiveIcon"
|
||||
remixicon="RiArchiveLine"
|
||||
/>
|
||||
Archive
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithSides() {
|
||||
return (
|
||||
<Example title="With Sides" containerClassName="col-span-2">
|
||||
<div className="flex flex-wrap justify-center gap-2">
|
||||
{(
|
||||
[
|
||||
{ label: "start", placement: "start top" },
|
||||
{ label: "left", placement: "left top" },
|
||||
{ label: "top", placement: "top start" },
|
||||
{ label: "bottom", placement: "bottom start" },
|
||||
{ label: "right", placement: "right top" },
|
||||
{ label: "end", placement: "end top" },
|
||||
] as const
|
||||
).map(({ label, placement }) => (
|
||||
<ContextMenuTrigger key={placement}>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] items-center justify-center rounded-lg border p-4 text-sm capitalize"
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu placement={placement}>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Back</ContextMenuItem>
|
||||
<ContextMenuItem>Forward</ContextMenuItem>
|
||||
<ContextMenuItem>Reload</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Context Menu Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Right click on the area below to see the context menu.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
Paste
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger>More Options</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Save Page...</ContextMenuItem>
|
||||
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
||||
<ContextMenuItem>Name Window...</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Developer Tools</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ContextMenuWithInset() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState<Selection>(
|
||||
new Set(["bookmarks"])
|
||||
)
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
|
||||
return (
|
||||
<Example title="With Inset">
|
||||
<ContextMenuTrigger>
|
||||
<Pressable>
|
||||
<div
|
||||
role="button"
|
||||
className="flex aspect-[2/0.5] w-full items-center justify-center rounded-lg border text-sm"
|
||||
>
|
||||
Right click here
|
||||
</div>
|
||||
</Pressable>
|
||||
<ContextMenu className="w-44">
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuLabel>Actions</ContextMenuLabel>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem inset>Paste</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<ContextMenuLabel inset>Appearance</ContextMenuLabel>
|
||||
<ContextMenuItem inset id="bookmarks">
|
||||
Bookmarks
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem inset id="urls">
|
||||
Full URLs
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuGroup
|
||||
selectionMode="single"
|
||||
selectedKeys={[theme]}
|
||||
onSelectionChange={(keys) =>
|
||||
setTheme(
|
||||
keys === "all"
|
||||
? "system"
|
||||
: (keys.values().next().value as string)
|
||||
)
|
||||
}
|
||||
>
|
||||
<ContextMenuLabel inset>Theme</ContextMenuLabel>
|
||||
<ContextMenuItem inset id="light">
|
||||
Light
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem inset id="dark">
|
||||
Dark
|
||||
</ContextMenuItem>
|
||||
<ContextMenuItem inset id="system">
|
||||
System
|
||||
</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
<ContextMenuSeparator />
|
||||
<ContextMenuSub>
|
||||
<ContextMenuSubTrigger inset>More Options</ContextMenuSubTrigger>
|
||||
<ContextMenuSubContent>
|
||||
<ContextMenuGroup>
|
||||
<ContextMenuItem>Save Page...</ContextMenuItem>
|
||||
<ContextMenuItem>Create Shortcut...</ContextMenuItem>
|
||||
</ContextMenuGroup>
|
||||
</ContextMenuSubContent>
|
||||
</ContextMenuSub>
|
||||
</ContextMenu>
|
||||
</ContextMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
406
apps/v4/registry/bases/aria/examples/demo.tsx
Normal file
406
apps/v4/registry/bases/aria/examples/demo.tsx
Normal file
@@ -0,0 +1,406 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/alert-dialog"
|
||||
import { Badge } from "@/registry/bases/aria/ui/badge"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { ButtonGroup } from "@/registry/bases/aria/ui/button-group"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import { Checkbox } from "@/registry/bases/aria/ui/checkbox"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import { Field, FieldGroup } from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
InputGroupText,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/aria/ui/item"
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@/registry/bases/aria/ui/radio-group"
|
||||
import { Slider } from "@/registry/bases/aria/ui/slider"
|
||||
import { Switch } from "@/registry/bases/aria/ui/switch"
|
||||
import { Textarea } from "@/registry/bases/aria/ui/textarea"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export function Demo() {
|
||||
const [sliderValue, setSliderValue] = React.useState<number[]>([500])
|
||||
const handleSliderValueChange = React.useCallback(
|
||||
(value: number | readonly number[]) => {
|
||||
if (typeof value === "number") {
|
||||
setSliderValue([value])
|
||||
} else {
|
||||
setSliderValue([...value])
|
||||
}
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen w-full flex-col items-center justify-center bg-muted p-4 sm:p-6 lg:p-12 dark:bg-background">
|
||||
<div className="grid max-w-3xl gap-4 sm:grid-cols-2">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Style Overview</CardTitle>
|
||||
<CardDescription className="line-clamp-2">
|
||||
Designers love packing quirky glyphs into test phrases. This is
|
||||
a preview of the typography styles.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-6 gap-3">
|
||||
{[
|
||||
"--background",
|
||||
"--foreground",
|
||||
"--primary",
|
||||
"--secondary",
|
||||
"--muted",
|
||||
"--accent",
|
||||
"--border",
|
||||
"--chart-1",
|
||||
"--chart-2",
|
||||
"--chart-3",
|
||||
"--chart-4",
|
||||
"--chart-5",
|
||||
].map((variant) => (
|
||||
<div
|
||||
key={variant}
|
||||
className="flex flex-col flex-wrap items-center gap-2"
|
||||
>
|
||||
<div
|
||||
className="relative aspect-square w-full rounded-lg bg-(--color) after:absolute after:inset-0 after:rounded-lg after:border after:border-border after:mix-blend-darken dark:after:mix-blend-lighten"
|
||||
style={
|
||||
{
|
||||
"--color": `var(${variant})`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
<div className="hidden max-w-14 truncate font-mono text-[0.60rem] md:block">
|
||||
{variant}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<div className="grid grid-cols-8 place-items-center gap-4">
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="CircleAlertIcon"
|
||||
tabler="IconExclamationCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="WarningCircleIcon"
|
||||
remixicon="RiErrorWarningLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="Delete02Icon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="Share03Icon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ShoppingBagIcon"
|
||||
tabler="IconShoppingBag"
|
||||
hugeicons="ShoppingBag01Icon"
|
||||
phosphor="BagIcon"
|
||||
remixicon="RiShoppingBagLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="Loader2Icon"
|
||||
tabler="IconLoader"
|
||||
hugeicons="Loading03Icon"
|
||||
phosphor="SpinnerIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="MinusIcon"
|
||||
tabler="IconMinus"
|
||||
hugeicons="MinusSignIcon"
|
||||
phosphor="MinusIcon"
|
||||
remixicon="RiSubtractLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft02Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</Card>
|
||||
<Card className="flex size-8 items-center justify-center p-0 shadow-none *:[svg]:size-4">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="Settings01Icon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Card className="w-full">
|
||||
<CardContent className="flex flex-col gap-6">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button>Button</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="outline">Outline</Button>
|
||||
<Button variant="ghost">Ghost</Button>
|
||||
</div>
|
||||
<Item variant="outline">
|
||||
<ItemContent>
|
||||
<ItemTitle>Two-factor authentication</ItemTitle>
|
||||
<ItemDescription className="text-pretty xl:hidden 2xl:block">
|
||||
Verify via email or phone number.
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
<ItemActions className="hidden md:flex">
|
||||
<Button size="sm" variant="secondary">
|
||||
Enable
|
||||
</Button>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
</div>
|
||||
<Slider
|
||||
value={sliderValue}
|
||||
onChange={handleSliderValueChange}
|
||||
maxValue={1000}
|
||||
minValue={0}
|
||||
step={10}
|
||||
className="flex-1"
|
||||
aria-label="Slider"
|
||||
/>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<InputGroup>
|
||||
<InputGroupInput placeholder="Name" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field className="flex-1">
|
||||
<Textarea placeholder="Message" className="resize-none" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex gap-2">
|
||||
<Badge>Badge</Badge>
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
</div>
|
||||
<RadioGroup
|
||||
defaultValue="apple"
|
||||
className="ml-auto flex w-fit gap-3"
|
||||
>
|
||||
<RadioGroupItem value="apple" />
|
||||
<RadioGroupItem value="banana" />
|
||||
</RadioGroup>
|
||||
<div className="flex gap-3">
|
||||
<Checkbox defaultSelected />
|
||||
<Checkbox />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<AlertDialogTrigger>
|
||||
<Button variant="outline">
|
||||
<span className="hidden md:block">Alert Dialog</span>
|
||||
<span className="block md:hidden">Dialog</span>
|
||||
</Button>
|
||||
<AlertDialog size="sm">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
Allow accessory to connect?
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to allow the USB accessory to connect to
|
||||
this device and your data?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Don't allow</AlertDialogCancel>
|
||||
<AlertDialogAction>Allow</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialog>
|
||||
</AlertDialogTrigger>
|
||||
<ButtonGroup>
|
||||
<Button variant="outline">Button Group</Button>
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ChevronUpIcon"
|
||||
tabler="IconChevronUp"
|
||||
hugeicons="ArrowUp01Icon"
|
||||
phosphor="CaretUpIcon"
|
||||
remixicon="RiArrowUpSLine"
|
||||
/>
|
||||
</Button>
|
||||
<DropdownMenu placement="top end" className="w-fit">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Quick Actions</DropdownMenuLabel>
|
||||
<DropdownMenuItem>Mute Conversation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Mark as Read</DropdownMenuItem>
|
||||
<DropdownMenuItem>Block User</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Conversation</DropdownMenuLabel>
|
||||
<DropdownMenuItem>Share Conversation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Copy Conversation</DropdownMenuItem>
|
||||
<DropdownMenuItem>Report Conversation</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete Conversation
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</ButtonGroup>
|
||||
<Switch defaultSelected className="ml-auto" />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
565
apps/v4/registry/bases/aria/examples/dialog-example.tsx
Normal file
565
apps/v4/registry/bases/aria/examples/dialog-example.tsx
Normal file
@@ -0,0 +1,565 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { Checkbox } from "@/registry/bases/aria/ui/checkbox"
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldSeparator,
|
||||
FieldSet,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { Kbd } from "@/registry/bases/aria/ui/kbd"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/aria/ui/native-select"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
import { Switch } from "@/registry/bases/aria/ui/switch"
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/registry/bases/aria/ui/tabs"
|
||||
import { Textarea } from "@/registry/bases/aria/ui/textarea"
|
||||
import { Tooltip, TooltipTrigger } from "@/registry/bases/aria/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function DialogExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<DialogWithForm />
|
||||
<DialogScrollableContent />
|
||||
<DialogWithStickyFooter />
|
||||
<DialogNoCloseButton />
|
||||
<DialogChatSettings />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogWithForm() {
|
||||
return (
|
||||
<Example title="With Form" className="items-center justify-center">
|
||||
<DialogTrigger>
|
||||
<form>
|
||||
<Button variant="outline">Edit Profile</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit profile</DialogTitle>
|
||||
<DialogDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done. Your profile will be updated immediately.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="name-1">Name</FieldLabel>
|
||||
<Input id="name-1" name="name" defaultValue="Pedro Duarte" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="username-1">Username</FieldLabel>
|
||||
<Input
|
||||
id="username-1"
|
||||
name="username"
|
||||
defaultValue="@peduarte"
|
||||
/>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<DialogFooter>
|
||||
<DialogClose variant="outline">Cancel</DialogClose>
|
||||
<Button type="submit">Save changes</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</form>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogScrollableContent() {
|
||||
return (
|
||||
<Example title="Scrollable Content" className="items-center justify-center">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Scrollable Content</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Scrollable Content</DialogTitle>
|
||||
<DialogDescription>
|
||||
This is a dialog with scrollable content.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="no-scrollbar max-h-[70vh] overflow-y-auto style-vega:-mx-6 style-vega:px-6 style-nova:-mx-4 style-nova:px-4 style-lyra:-mx-4 style-lyra:px-4 style-maia:-mx-6 style-maia:px-6 style-mira:-mx-4 style-mira:px-4 style-luma:-mx-6 style-luma:px-6 style-rhea:-mx-6 style-rhea:px-6">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
|
||||
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogWithStickyFooter() {
|
||||
return (
|
||||
<Example title="With Sticky Footer" className="items-center justify-center">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Sticky Footer</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Scrollable Content</DialogTitle>
|
||||
<DialogDescription>
|
||||
This is a dialog with scrollable content.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="no-scrollbar max-h-[70vh] overflow-y-auto style-vega:-mx-6 style-vega:px-6 style-nova:-mx-4 style-nova:px-4 style-lyra:-mx-4 style-lyra:px-4 style-maia:-mx-6 style-maia:px-6 style-mira:-mx-4 style-mira:px-4 style-luma:-mx-6 style-luma:px-6 style-rhea:-mx-6 style-rhea:px-6">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
||||
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
||||
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
|
||||
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
|
||||
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
|
||||
sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose variant="outline">Close</DialogClose>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DialogNoCloseButton() {
|
||||
return (
|
||||
<Example title="No Close Button" className="items-center justify-center">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">No Close Button</Button>
|
||||
<Dialog showCloseButton={false}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>No Close Button</DialogTitle>
|
||||
<DialogDescription>
|
||||
This dialog doesn't have a close button in the top-right
|
||||
corner.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<DialogClose variant="outline">Close</DialogClose>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const spokenLanguages = [
|
||||
{ label: "Auto", value: "auto" },
|
||||
{ label: "English", value: "en" },
|
||||
{ label: "Spanish", value: "es" },
|
||||
{ label: "French", value: "fr" },
|
||||
{ label: "German", value: "de" },
|
||||
{ label: "Italian", value: "it" },
|
||||
{ label: "Portuguese", value: "pt" },
|
||||
{ label: "Russian", value: "ru" },
|
||||
{ label: "Chinese", value: "zh" },
|
||||
{ label: "Japanese", value: "ja" },
|
||||
{ label: "Korean", value: "ko" },
|
||||
{ label: "Arabic", value: "ar" },
|
||||
{ label: "Hindi", value: "hi" },
|
||||
{ label: "Bengali", value: "bn" },
|
||||
{ label: "Telugu", value: "te" },
|
||||
{ label: "Marathi", value: "mr" },
|
||||
{ label: "Kannada", value: "kn" },
|
||||
{ label: "Malayalam", value: "ml" },
|
||||
]
|
||||
|
||||
const voices = [
|
||||
{ label: "Samantha", value: "samantha" },
|
||||
{ label: "Alex", value: "alex" },
|
||||
{ label: "Fred", value: "fred" },
|
||||
{ label: "Victoria", value: "victoria" },
|
||||
{ label: "Tom", value: "tom" },
|
||||
{ label: "Karen", value: "karen" },
|
||||
{ label: "Sam", value: "sam" },
|
||||
{ label: "Daniel", value: "daniel" },
|
||||
]
|
||||
|
||||
const themes = [
|
||||
{ label: "Light", value: "light" },
|
||||
{ label: "Dark", value: "dark" },
|
||||
{ label: "System", value: "system" },
|
||||
]
|
||||
|
||||
const accents = [
|
||||
{ label: "Default", value: "default" },
|
||||
{ label: "Red", value: "red" },
|
||||
{ label: "Blue", value: "blue" },
|
||||
{ label: "Green", value: "green" },
|
||||
{ label: "Purple", value: "purple" },
|
||||
{ label: "Pink", value: "pink" },
|
||||
]
|
||||
|
||||
function DialogChatSettings() {
|
||||
const [tab, setTab] = React.useState("general")
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
const [accentColor, setAccentColor] = React.useState("default")
|
||||
const [spokenLanguage, setSpokenLanguage] = React.useState("en")
|
||||
const [voice, setVoice] = React.useState("samantha")
|
||||
|
||||
return (
|
||||
<Example title="Chat Settings" className="items-center justify-center">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Chat Settings</Button>
|
||||
<Dialog className="min-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Chat Settings</DialogTitle>
|
||||
<DialogDescription>
|
||||
Customize your chat settings: theme, accent color, spoken
|
||||
language, voice, personality, and custom instructions.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4">
|
||||
<NativeSelect
|
||||
value={tab}
|
||||
onChange={(e) => setTab(e.target.value)}
|
||||
className="w-full md:hidden"
|
||||
>
|
||||
<NativeSelectOption value="general">General</NativeSelectOption>
|
||||
<NativeSelectOption value="notifications">
|
||||
Notifications
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="personalization">
|
||||
Personalization
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="security">Security</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<Tabs
|
||||
selectedKey={tab}
|
||||
onSelectionChange={(key) => setTab(String(key))}
|
||||
>
|
||||
<TabsList className="hidden w-full md:flex">
|
||||
<TabsTrigger id="general">General</TabsTrigger>
|
||||
<TabsTrigger id="notifications">Notifications</TabsTrigger>
|
||||
<TabsTrigger id="personalization">Personalization</TabsTrigger>
|
||||
<TabsTrigger id="security">Security</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border **:data-[slot=select-trigger]:min-w-[125px] style-vega:min-h-[550px] style-vega:rounded-lg style-vega:p-6 style-nova:min-h-[460px] style-nova:rounded-lg style-nova:p-4 style-lyra:min-h-[450px] style-lyra:rounded-none style-lyra:p-4 style-maia:min-h-[550px] style-maia:rounded-xl style-maia:p-6 style-mira:min-h-[450px] style-mira:rounded-md style-mira:p-4 style-luma:min-h-[550px] style-luma:rounded-xl style-luma:p-6 style-rhea:min-h-[480px] style-rhea:rounded-2xl style-rhea:p-6">
|
||||
<TabsContent id="general">
|
||||
<FieldSet>
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="theme">Theme</FieldLabel>
|
||||
<Select
|
||||
value={theme}
|
||||
onChange={(value) => setTheme(String(value))}
|
||||
>
|
||||
<SelectTrigger id="theme">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent placement="bottom end">
|
||||
<SelectGroup>
|
||||
{themes.map((theme) => (
|
||||
<SelectItem key={theme.value} id={theme.value}>
|
||||
{theme.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="accent-color">
|
||||
Accent Color
|
||||
</FieldLabel>
|
||||
<Select
|
||||
value={accentColor}
|
||||
onChange={(value) => setAccentColor(String(value))}
|
||||
>
|
||||
<SelectTrigger id="accent-color">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent placement="bottom end">
|
||||
<SelectGroup>
|
||||
{accents.map((accent) => (
|
||||
<SelectItem
|
||||
key={accent.value}
|
||||
id={accent.value}
|
||||
>
|
||||
{accent.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="responsive">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="spoken-language">
|
||||
Spoken Language
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
For best results, select the language you mainly
|
||||
speak. If it's not listed, it may still be
|
||||
supported via auto-detection.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Select
|
||||
value={spokenLanguage}
|
||||
onChange={(value) => setSpokenLanguage(String(value))}
|
||||
>
|
||||
<SelectTrigger id="spoken-language">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent placement="bottom end">
|
||||
<SelectGroup>
|
||||
{spokenLanguages.map((language) => (
|
||||
<SelectItem
|
||||
key={language.value}
|
||||
id={language.value}
|
||||
>
|
||||
{language.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="voice">Voice</FieldLabel>
|
||||
<Select
|
||||
value={voice}
|
||||
onChange={(value) => setVoice(String(value))}
|
||||
>
|
||||
<SelectTrigger id="voice">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent placement="bottom end">
|
||||
<SelectGroup>
|
||||
{voices.map((voice) => (
|
||||
<SelectItem key={voice.value} id={voice.value}>
|
||||
{voice.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
</TabsContent>
|
||||
<TabsContent id="notifications">
|
||||
<FieldGroup>
|
||||
<FieldSet>
|
||||
<FieldLabel>Responses</FieldLabel>
|
||||
<FieldDescription>
|
||||
Get notified when ChatGPT responds to requests that take
|
||||
time, like research or image generation.
|
||||
</FieldDescription>
|
||||
<FieldGroup data-slot="checkbox-group">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="push" defaultSelected isDisabled />
|
||||
<FieldLabel htmlFor="push" className="font-normal">
|
||||
Push notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
<FieldSeparator />
|
||||
<FieldSet>
|
||||
<FieldLabel>Tasks</FieldLabel>
|
||||
<FieldDescription>
|
||||
Get notified when tasks you've created have
|
||||
updates. <a href="#">Manage tasks</a>
|
||||
</FieldDescription>
|
||||
<FieldGroup data-slot="checkbox-group">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="push-tasks" />
|
||||
<FieldLabel
|
||||
htmlFor="push-tasks"
|
||||
className="font-normal"
|
||||
>
|
||||
Push notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="email-tasks" />
|
||||
<FieldLabel
|
||||
htmlFor="email-tasks"
|
||||
className="font-normal"
|
||||
>
|
||||
Email notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
</TabsContent>
|
||||
<TabsContent id="personalization">
|
||||
<FieldGroup>
|
||||
<Field orientation="responsive">
|
||||
<FieldLabel htmlFor="nickname">Nickname</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="nickname"
|
||||
placeholder="Broski"
|
||||
className="@md/field-group:max-w-[200px]"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<TooltipTrigger>
|
||||
<InputGroupButton size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
<Tooltip className="flex items-center gap-2">
|
||||
Used to identify you in the chat. <Kbd>N</Kbd>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field
|
||||
orientation="responsive"
|
||||
className="@md/field-group:flex-col @2xl/field-group:flex-row"
|
||||
>
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="about">More about you</FieldLabel>
|
||||
<FieldDescription>
|
||||
Tell us more about yourself. This will be used to help
|
||||
us personalize your experience.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Textarea
|
||||
id="about"
|
||||
placeholder="I'm a software engineer..."
|
||||
className="min-h-[120px] @md/field-group:min-w-full @2xl/field-group:min-w-[300px]"
|
||||
/>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<FieldLabel>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="customization">
|
||||
Enable customizations
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Enable customizations to make ChatGPT more
|
||||
personalized.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="customization" defaultSelected />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</FieldGroup>
|
||||
</TabsContent>
|
||||
<TabsContent id="security">
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="2fa">
|
||||
Multi-factor authentication
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Enable multi-factor authentication to secure your
|
||||
account. If you do not have a two-factor
|
||||
authentication device, you can use a one-time code
|
||||
sent to your email.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="2fa" />
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldTitle>Log out</FieldTitle>
|
||||
<FieldDescription>
|
||||
Log out of your account on this device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Button variant="outline" size="sm">
|
||||
Log Out
|
||||
</Button>
|
||||
</Field>
|
||||
<FieldSeparator />
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldTitle>Log out of all devices</FieldTitle>
|
||||
<FieldDescription>
|
||||
This will log you out of all devices, including the
|
||||
current session. It may take up to 30 minutes for the
|
||||
changes to take effect.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Button variant="outline" size="sm">
|
||||
Log Out All
|
||||
</Button>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
484
apps/v4/registry/bases/aria/examples/drawer-example.tsx
Normal file
484
apps/v4/registry/bases/aria/examples/drawer-example.tsx
Normal file
@@ -0,0 +1,484 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from "@/registry/bases/aria/ui/drawer"
|
||||
|
||||
const PARAGRAPHS = [
|
||||
"Your changes are saved automatically as you type.",
|
||||
"Delivery usually takes three to five business days, depending on your location and the shipping method you selected at checkout.",
|
||||
"We use your email address for account notifications and order updates. You can change this anytime from your profile settings.",
|
||||
"Two-factor authentication adds an extra layer of security to your account. When enabled, you'll need to enter a code from your authenticator app in addition to your password. We recommend enabling it if you store payment methods or sensitive information.",
|
||||
"By continuing, you agree to our Terms of Service and Privacy Policy. We collect usage data to improve the product, personalize your experience, and troubleshoot issues. You can export or delete your data at any time from the account settings page. Third-party integrations may have their own policies, and you should review them before connecting external services.",
|
||||
"Refunds are processed within five to ten business days after we receive your return. Items must be unused and in their original packaging to qualify. Shipping costs are non-refundable unless the return is due to our error or a defective product. Once approved, the refund is issued to your original payment method; credit card refunds may take an additional billing cycle to appear on your statement. If you paid with store credit, the balance is restored to your account immediately. Contact support if you haven't received your refund after two weeks.",
|
||||
"Last updated March 12, 2026.",
|
||||
"Upgrade to Pro for unlimited projects, priority support, and advanced analytics. Cancel anytime from billing settings.",
|
||||
"You haven't verified your email yet. Check your inbox for a confirmation link—we sent it when you signed up. The link expires after 24 hours, but you can request a new one below.",
|
||||
"API requests are rate-limited to 1,000 calls per hour on the free plan. Exceeding the limit returns a 429 response with a Retry-After header. Upgrade to a paid plan for higher limits and dedicated support. Webhook deliveries are retried up to three times with exponential backoff if your endpoint returns a non-2xx status.",
|
||||
"No payment method on file.",
|
||||
"Our design team rebuilt the checkout flow last quarter after interviews with forty-two customers. The biggest friction point was surprise fees at the final step, so we moved shipping and tax estimates earlier in the process. Early tests show a twelve percent drop in cart abandonment. We're still rolling out the update region by region, and you may see the old flow until your account is migrated.",
|
||||
]
|
||||
|
||||
export default function DrawerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<DrawerDemo />
|
||||
<DrawerSwipeHandleExample />
|
||||
<DrawerPosition />
|
||||
<DrawerCustomWidthAndHeight />
|
||||
<DrawerScrollable />
|
||||
<DrawerSnapPoints />
|
||||
<DrawerNested />
|
||||
<DrawerNonModal />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function DrawerDemo() {
|
||||
return (
|
||||
<Example title="Demo">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Drawer>
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Open Drawer
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<div className="p-4">
|
||||
<div className="h-80 w-full bg-muted" />
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Drawer>
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Header
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Edit profile</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="p-4">
|
||||
<div className="h-80 w-full bg-muted" />
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Drawer>
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Footer
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<div className="p-4">
|
||||
<div className="h-80 w-full bg-muted" />
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Button>Submit</Button>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Cancel
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Drawer>
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Header and Footer
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Edit profile</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="p-4">
|
||||
<div className="h-80 w-full bg-muted" />
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Button>Submit</Button>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Cancel
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Drawer>
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Edge to Edge
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<div className="h-80 w-full bg-blue-200" />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DrawerSwipeHandleExample() {
|
||||
return (
|
||||
<Example title="Swipe Handle">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{DRAWER_SIDES.map((side) => (
|
||||
<Drawer key={side} swipeDirection={side} showSwipeHandle>
|
||||
<DrawerTrigger
|
||||
render={<Button variant="outline" className="capitalize" />}
|
||||
>
|
||||
{side}
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle className="capitalize">Drawer</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Drawer with a swipe handle.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 p-4">
|
||||
<div className="bg-muted group-data-[swipe-axis=x]/drawer-popup:size-full group-data-[swipe-axis=y]/drawer-popup:h-80 group-data-[swipe-axis=y]/drawer-popup:w-full" />
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DrawerCustomWidthAndHeight() {
|
||||
return (
|
||||
<Example title="Custom Width and Height">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Drawer swipeDirection="down">
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Down
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="data-[swipe-direction=down]:h-64">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Down drawer</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Drawer with a custom height.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 scroll-fade scrollbar-thin overflow-y-auto p-4">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
{PARAGRAPHS[index % PARAGRAPHS.length]}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Drawer swipeDirection="up">
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Up
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="data-[swipe-direction=up]:h-[50vh]">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Up drawer</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Drawer with a custom height.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 scroll-fade overflow-y-auto p-4">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
{PARAGRAPHS[index % PARAGRAPHS.length]}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Drawer swipeDirection="left">
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Left
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="data-[swipe-direction=left]:w-xl">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Left drawer</DrawerTitle>
|
||||
<DrawerDescription>Drawer with a custom width.</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 scroll-fade overflow-y-auto p-4">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
{PARAGRAPHS[index % PARAGRAPHS.length]}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Drawer swipeDirection="right">
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Right
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="data-[swipe-direction=right]:w-xs">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Right drawer</DrawerTitle>
|
||||
<DrawerDescription>Drawer with a custom width.</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 scroll-fade overflow-y-auto p-4">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
{PARAGRAPHS[index % PARAGRAPHS.length]}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const DRAWER_SIDES = ["up", "right", "down", "left"] as const
|
||||
|
||||
function DrawerPosition() {
|
||||
return (
|
||||
<Example title="Position">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{DRAWER_SIDES.map((side) => (
|
||||
<Drawer key={side} swipeDirection={side}>
|
||||
<DrawerTrigger
|
||||
render={<Button variant="outline" className="capitalize" />}
|
||||
>
|
||||
{side}
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Move Goal</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Set your daily activity goal.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 p-4">
|
||||
<div className="bg-muted group-data-[swipe-axis=x]/drawer-popup:size-full group-data-[swipe-axis=y]/drawer-popup:h-80 group-data-[swipe-axis=y]/drawer-popup:w-full" />
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Button>Submit</Button>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Cancel
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DrawerScrollable() {
|
||||
return (
|
||||
<Example title="Scrollable Content">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{DRAWER_SIDES.map((side) => (
|
||||
<Drawer key={side} swipeDirection={side}>
|
||||
<DrawerTrigger
|
||||
render={<Button variant="outline" className="capitalize" />}
|
||||
>
|
||||
{side}
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Move Goal</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Set your daily activity goal.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 scroll-fade overflow-y-auto p-4">
|
||||
{Array.from({ length: 20 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
{PARAGRAPHS[index % PARAGRAPHS.length]}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Button>Submit</Button>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Cancel
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const SNAP_POINTS = ["31rem", 1]
|
||||
|
||||
function DrawerSnapPoints() {
|
||||
return (
|
||||
<Example title="Snap Points">
|
||||
<Drawer snapPoints={SNAP_POINTS} showSwipeHandle>
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Open Snap Drawer
|
||||
</DrawerTrigger>
|
||||
<DrawerContent className="max-h-[calc(100dvh-1rem)]">
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Snap points</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Drag the drawer to snap between a compact peek and a near
|
||||
full-height view.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="grid flex-1 scroll-fade gap-3 overflow-y-auto p-4">
|
||||
{Array.from({ length: 16 }).map((_, index) => (
|
||||
<div key={index} className="h-12 bg-muted" />
|
||||
))}
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DrawerNested() {
|
||||
return (
|
||||
<Example title="Nested">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{DRAWER_SIDES.map((side) => (
|
||||
<Drawer key={side} swipeDirection={side} showSwipeHandle>
|
||||
<DrawerTrigger
|
||||
render={<Button variant="outline" className="capitalize" />}
|
||||
>
|
||||
{side}
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle className="capitalize">{side} drawer</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Open another drawer from the same direction.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 p-4">
|
||||
<div className="bg-muted group-data-[swipe-axis=x]/drawer-popup:size-full group-data-[swipe-axis=y]/drawer-popup:h-80 group-data-[swipe-axis=y]/drawer-popup:w-full" />
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Drawer swipeDirection={side}>
|
||||
<DrawerTrigger render={<Button />}>
|
||||
Open nested drawer
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Nested drawer</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
The parent drawer stays mounted behind this one.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 p-4">
|
||||
<div className="bg-muted group-data-[swipe-axis=x]/drawer-popup:size-full group-data-[swipe-axis=y]/drawer-popup:h-80 group-data-[swipe-axis=y]/drawer-popup:w-full" />
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<Drawer swipeDirection={side}>
|
||||
<DrawerTrigger render={<Button />}>
|
||||
Open third drawer
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Third drawer</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
This is the frontmost drawer in the stack.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 p-4">
|
||||
<div className="bg-muted group-data-[swipe-axis=x]/drawer-popup:size-full group-data-[swipe-axis=y]/drawer-popup:h-80 group-data-[swipe-axis=y]/drawer-popup:w-full" />
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DrawerNonModal() {
|
||||
return (
|
||||
<Example title="Non Modal">
|
||||
<Drawer modal={false} disablePointerDismissal swipeDirection="right">
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
Non Modal
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Non Modal Drawer</DrawerTitle>
|
||||
</DrawerHeader>
|
||||
<div className="flex-1 p-4">
|
||||
<div className="bg-muted group-data-[swipe-axis=x]/drawer-popup:size-full group-data-[swipe-axis=y]/drawer-popup:h-80 group-data-[swipe-axis=y]/drawer-popup:w-full" />
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
941
apps/v4/registry/bases/aria/examples/dropdown-menu-example.tsx
Normal file
941
apps/v4/registry/bases/aria/examples/dropdown-menu-example.tsx
Normal file
@@ -0,0 +1,941 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type { Selection } from "react-aria-components"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/aria/ui/avatar"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function DropdownMenuExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<DropdownMenuBasic />
|
||||
<DropdownMenuComplex />
|
||||
<DropdownMenuSides />
|
||||
<DropdownMenuWithIcons />
|
||||
<DropdownMenuWithShortcuts />
|
||||
<DropdownMenuWithSubmenu />
|
||||
<DropdownMenuWithCheckboxes />
|
||||
<DropdownMenuWithCheckboxesIcons />
|
||||
<DropdownMenuWithRadio />
|
||||
<DropdownMenuWithRadioIcons />
|
||||
<DropdownMenuWithDestructive />
|
||||
<DropdownMenuWithAvatar />
|
||||
<DropdownMenuInDialog />
|
||||
<DropdownMenuWithInset />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>GitHub</DropdownMenuItem>
|
||||
<DropdownMenuItem>Support</DropdownMenuItem>
|
||||
<DropdownMenuItem isDisabled>API</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuSides() {
|
||||
return (
|
||||
<Example title="Sides" containerClassName="col-span-2">
|
||||
<div className="flex flex-wrap justify-center gap-2">
|
||||
{(
|
||||
[
|
||||
{ label: "start", placement: "start top" },
|
||||
{ label: "left", placement: "left top" },
|
||||
{ label: "top", placement: "top start" },
|
||||
{ label: "bottom", placement: "bottom start" },
|
||||
{ label: "right", placement: "right top" },
|
||||
{ label: "end", placement: "end top" },
|
||||
] as const
|
||||
).map(({ label, placement }) => (
|
||||
<DropdownMenuTrigger key={placement}>
|
||||
<Button variant="outline" className="w-fit capitalize">
|
||||
{label}
|
||||
</Button>
|
||||
<DropdownMenu placement={placement}>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Log out
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithShortcuts() {
|
||||
return (
|
||||
<Example title="With Shortcuts">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
Keyboard shortcuts
|
||||
<DropdownMenuShortcut>⌘K</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
Log out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithSubmenu() {
|
||||
return (
|
||||
<Example title="With Submenu">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Team</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>Invite users</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem>Email</DropdownMenuItem>
|
||||
<DropdownMenuItem>Message</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>More...</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuItem>
|
||||
New Team
|
||||
<DropdownMenuShortcut>⌘+T</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithCheckboxes() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState<Selection>(
|
||||
new Set(["status-bar"])
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Checkboxes">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Checkboxes
|
||||
</Button>
|
||||
<DropdownMenu className="min-w-40">
|
||||
<DropdownMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<DropdownMenuLabel>Appearance</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="status-bar">
|
||||
<IconPlaceholder
|
||||
lucide="LayoutIcon"
|
||||
tabler="IconLayout"
|
||||
hugeicons="LayoutIcon"
|
||||
phosphor="LayoutIcon"
|
||||
remixicon="RiLayoutLine"
|
||||
/>
|
||||
Status Bar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="activity-bar" isDisabled>
|
||||
<IconPlaceholder
|
||||
lucide="ActivityIcon"
|
||||
tabler="IconActivity"
|
||||
hugeicons="ActivityIcon"
|
||||
phosphor="ActivityIcon"
|
||||
remixicon="RiPulseLine"
|
||||
/>
|
||||
Activity Bar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="panel">
|
||||
<IconPlaceholder
|
||||
lucide="PanelLeftIcon"
|
||||
tabler="IconLayoutSidebar"
|
||||
hugeicons="LayoutLeftIcon"
|
||||
phosphor="SidebarIcon"
|
||||
remixicon="RiSideBarLine"
|
||||
/>
|
||||
Panel
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithRadio() {
|
||||
const [position, setPosition] = React.useState("bottom")
|
||||
|
||||
return (
|
||||
<Example title="With Radio Group">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Radio Group
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuGroup
|
||||
selectionMode="single"
|
||||
selectedKeys={[position]}
|
||||
onSelectionChange={(keys) =>
|
||||
setPosition(
|
||||
keys === "all"
|
||||
? "bottom"
|
||||
: (keys.values().next().value as string)
|
||||
)
|
||||
}
|
||||
>
|
||||
<DropdownMenuLabel>Panel Position</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="top">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUp01Icon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
/>
|
||||
Top
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="bottom">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowDownIcon"
|
||||
tabler="IconArrowDown"
|
||||
hugeicons="ArrowDown01Icon"
|
||||
phosphor="ArrowDownIcon"
|
||||
remixicon="RiArrowDownLine"
|
||||
/>
|
||||
Bottom
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="right" isDisabled>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
Right
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithCheckboxesIcons() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState<Selection>(
|
||||
new Set(["email", "push"])
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="Checkboxes with Icons">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Notifications
|
||||
</Button>
|
||||
<DropdownMenu className="min-w-56">
|
||||
<DropdownMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<DropdownMenuLabel>Notification Preferences</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="email">
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
Email notifications
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="sms">
|
||||
<IconPlaceholder
|
||||
lucide="MessageSquareIcon"
|
||||
tabler="IconMessage"
|
||||
hugeicons="MessageIcon"
|
||||
phosphor="ChatCircleIcon"
|
||||
remixicon="RiChat1Line"
|
||||
/>
|
||||
SMS notifications
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="push">
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Push notifications
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithRadioIcons() {
|
||||
const [paymentMethod, setPaymentMethod] = React.useState("card")
|
||||
|
||||
return (
|
||||
<Example title="Radio with Icons">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Payment Method
|
||||
</Button>
|
||||
<DropdownMenu className="min-w-56">
|
||||
<DropdownMenuGroup
|
||||
selectionMode="single"
|
||||
selectedKeys={[paymentMethod]}
|
||||
onSelectionChange={(keys) =>
|
||||
setPaymentMethod(
|
||||
keys === "all" ? "card" : (keys.values().next().value as string)
|
||||
)
|
||||
}
|
||||
>
|
||||
<DropdownMenuLabel>Select Payment Method</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="card">
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Credit Card
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="paypal">
|
||||
<IconPlaceholder
|
||||
lucide="WalletIcon"
|
||||
tabler="IconWallet"
|
||||
hugeicons="WalletIcon"
|
||||
phosphor="WalletIcon"
|
||||
remixicon="RiWalletLine"
|
||||
/>
|
||||
PayPal
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="bank">
|
||||
<IconPlaceholder
|
||||
lucide="Building2Icon"
|
||||
tabler="IconBuildingBank"
|
||||
hugeicons="BankIcon"
|
||||
phosphor="BankIcon"
|
||||
remixicon="RiBankLine"
|
||||
/>
|
||||
Bank Transfer
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithDestructive() {
|
||||
return (
|
||||
<Example title="With Destructive Items">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Actions
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="PencilIcon"
|
||||
tabler="IconPencil"
|
||||
hugeicons="EditIcon"
|
||||
phosphor="PencilIcon"
|
||||
remixicon="RiPencilLine"
|
||||
/>
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ShareIcon"
|
||||
tabler="IconShare"
|
||||
hugeicons="ShareIcon"
|
||||
phosphor="ShareIcon"
|
||||
remixicon="RiShareLine"
|
||||
/>
|
||||
Share
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ArchiveIcon"
|
||||
tabler="IconArchive"
|
||||
hugeicons="Archive02Icon"
|
||||
phosphor="ArchiveIcon"
|
||||
remixicon="RiArchiveLine"
|
||||
/>
|
||||
Archive
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithAvatar() {
|
||||
const menuContent = (
|
||||
<>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="BadgeCheckIcon"
|
||||
tabler="IconRosetteDiscountCheck"
|
||||
hugeicons="CheckmarkBadgeIcon"
|
||||
phosphor="CheckCircleIcon"
|
||||
remixicon="RiCheckboxCircleLine"
|
||||
/>
|
||||
Account
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="BellIcon"
|
||||
tabler="IconBell"
|
||||
hugeicons="NotificationIcon"
|
||||
phosphor="BellIcon"
|
||||
remixicon="RiNotificationLine"
|
||||
/>
|
||||
Notifications
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Sign Out
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="With Avatar">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<DropdownMenuTrigger>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-12 justify-start px-2 md:max-w-[200px] style-sera:font-normal style-sera:tracking-normal style-sera:normal-case"
|
||||
>
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="Shadcn" />
|
||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-semibold">shadcn</span>
|
||||
<span className="truncate text-xs text-muted-foreground">
|
||||
shadcn@example.com
|
||||
</span>
|
||||
</div>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</Button>
|
||||
<DropdownMenu className="w-(--anchor-width) min-w-56">
|
||||
{menuContent}
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="ghost" size="icon" className="rounded-full">
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" alt="shadcn" />
|
||||
<AvatarFallback>LR</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
<DropdownMenu placement="top end">{menuContent}</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Dropdown Menu Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Click the button below to see the dropdown menu.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open Menu
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ClipboardPasteIcon"
|
||||
tabler="IconClipboard"
|
||||
hugeicons="ClipboardIcon"
|
||||
phosphor="ClipboardIcon"
|
||||
remixicon="RiClipboardLine"
|
||||
/>
|
||||
Paste
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>More Options</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem>Save Page...</DropdownMenuItem>
|
||||
<DropdownMenuItem>Create Shortcut...</DropdownMenuItem>
|
||||
<DropdownMenuItem>Name Window...</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Developer Tools</DropdownMenuItem>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuWithInset() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState<Selection>(
|
||||
new Set(["bookmarks"])
|
||||
)
|
||||
const [theme, setTheme] = React.useState("system")
|
||||
|
||||
return (
|
||||
<Example title="With Inset">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open
|
||||
</Button>
|
||||
<DropdownMenu className="w-44">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Actions</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
Copy
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="ScissorsIcon"
|
||||
tabler="IconCut"
|
||||
hugeicons="ScissorIcon"
|
||||
phosphor="ScissorsIcon"
|
||||
remixicon="RiScissorsLine"
|
||||
/>
|
||||
Cut
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem inset>Paste</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<DropdownMenuLabel inset>Appearance</DropdownMenuLabel>
|
||||
<DropdownMenuItem inset id="bookmarks">
|
||||
Bookmarks
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem inset id="urls">
|
||||
Full URLs
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup
|
||||
selectionMode="single"
|
||||
selectedKeys={[theme]}
|
||||
onSelectionChange={(keys) =>
|
||||
setTheme(
|
||||
keys === "all"
|
||||
? "system"
|
||||
: (keys.values().next().value as string)
|
||||
)
|
||||
}
|
||||
>
|
||||
<DropdownMenuLabel inset>Theme</DropdownMenuLabel>
|
||||
<DropdownMenuItem inset id="light">
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem inset id="dark">
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem inset id="system">
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger inset>More Options</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Save Page...</DropdownMenuItem>
|
||||
<DropdownMenuItem>Create Shortcut...</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function DropdownMenuComplex() {
|
||||
const [selectedKeys, setSelectedKeys] = React.useState<Selection>(
|
||||
new Set(["sidebar"])
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="Complex">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Complex Menu
|
||||
</Button>
|
||||
<DropdownMenu className="w-56">
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="CreditCardIcon"
|
||||
tabler="IconCreditCard"
|
||||
hugeicons="CreditCardIcon"
|
||||
phosphor="CreditCardIcon"
|
||||
remixicon="RiBankCardLine"
|
||||
/>
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup
|
||||
selectionMode="multiple"
|
||||
selectedKeys={selectedKeys}
|
||||
onSelectionChange={setSelectedKeys}
|
||||
>
|
||||
<DropdownMenuLabel>View</DropdownMenuLabel>
|
||||
<DropdownMenuItem id="sidebar">
|
||||
<IconPlaceholder
|
||||
lucide="PanelLeftIcon"
|
||||
tabler="IconLayoutSidebar"
|
||||
hugeicons="LayoutLeftIcon"
|
||||
phosphor="SidebarIcon"
|
||||
remixicon="RiSideBarLine"
|
||||
/>
|
||||
Sidebar
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem id="status-bar">
|
||||
<IconPlaceholder
|
||||
lucide="LayoutIcon"
|
||||
tabler="IconLayout"
|
||||
hugeicons="LayoutIcon"
|
||||
phosphor="LayoutIcon"
|
||||
remixicon="RiLayoutLine"
|
||||
/>
|
||||
Status Bar
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
<IconPlaceholder
|
||||
lucide="UsersIcon"
|
||||
tabler="IconUsers"
|
||||
hugeicons="UserGroupIcon"
|
||||
phosphor="UsersIcon"
|
||||
remixicon="RiTeamLine"
|
||||
/>
|
||||
Invite Users
|
||||
</DropdownMenuSubTrigger>
|
||||
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
Email
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="MessageSquareIcon"
|
||||
tabler="IconMessage"
|
||||
hugeicons="MessageIcon"
|
||||
phosphor="ChatCircleIcon"
|
||||
remixicon="RiChat1Line"
|
||||
/>
|
||||
Message
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="PlusCircleIcon"
|
||||
tabler="IconCirclePlus"
|
||||
hugeicons="AddCircleIcon"
|
||||
phosphor="PlusCircleIcon"
|
||||
remixicon="RiAddCircleLine"
|
||||
/>
|
||||
More...
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>
|
||||
<IconPlaceholder
|
||||
lucide="HelpCircleIcon"
|
||||
tabler="IconHelpCircle"
|
||||
hugeicons="HelpCircleIcon"
|
||||
phosphor="QuestionIcon"
|
||||
remixicon="RiQuestionLine"
|
||||
/>
|
||||
Support
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem variant="destructive">
|
||||
<IconPlaceholder
|
||||
lucide="LogOutIcon"
|
||||
tabler="IconLogout"
|
||||
hugeicons="LogoutIcon"
|
||||
phosphor="SignOutIcon"
|
||||
remixicon="RiLogoutBoxLine"
|
||||
/>
|
||||
Sign Out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
244
apps/v4/registry/bases/aria/examples/empty-example.tsx
Normal file
244
apps/v4/registry/bases/aria/examples/empty-example.tsx
Normal file
@@ -0,0 +1,244 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button, LinkButton } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/aria/ui/empty"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { Kbd } from "@/registry/bases/aria/ui/kbd"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function EmptyExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<EmptyBasic />
|
||||
<EmptyWithMutedBackground />
|
||||
<EmptyWithBorder />
|
||||
<EmptyWithIcon />
|
||||
<EmptyWithMutedBackgroundAlt />
|
||||
<EmptyInCard />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>No projects yet</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
You haven't created any projects yet. Get started by creating
|
||||
your first project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<div className="flex gap-2">
|
||||
<LinkButton href="#">Create project</LinkButton>
|
||||
<Button variant="outline">Import project</Button>
|
||||
</div>
|
||||
<LinkButton variant="link" href="#" className="text-muted-foreground">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</LinkButton>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithMutedBackground() {
|
||||
return (
|
||||
<Example title="With Muted Background">
|
||||
<Empty className="bg-muted">
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>No results found</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
No results found for your search. Try adjusting your search terms.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button>Try again</Button>
|
||||
<LinkButton variant="link" href="#" className="text-muted-foreground">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</LinkButton>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithBorder() {
|
||||
return (
|
||||
<Example title="With Border">
|
||||
<Empty className="border">
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>404 - Not Found</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
The page you're looking for doesn't exist. Try searching
|
||||
for what you need below.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<InputGroup className="w-3/4">
|
||||
<InputGroupInput placeholder="Try searching for pages..." />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>/</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<EmptyDescription>
|
||||
Need help? <a href="#">Contact support</a>
|
||||
</EmptyDescription>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithIcon() {
|
||||
return (
|
||||
<Example title="With Icon">
|
||||
<Empty className="border">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="Folder01Icon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>Nothing to see here</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
No posts have been created yet. Get started by{" "}
|
||||
<a href="#">creating your first post</a>.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="PlusIcon"
|
||||
tabler="IconPlus"
|
||||
hugeicons="PlusSignIcon"
|
||||
phosphor="PlusIcon"
|
||||
remixicon="RiAddLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
New Post
|
||||
</Button>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyWithMutedBackgroundAlt() {
|
||||
return (
|
||||
<Example title="With Muted Background Alt">
|
||||
<Empty className="bg-muted/50">
|
||||
<EmptyHeader>
|
||||
<EmptyTitle>404 - Not Found</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
The page you're looking for doesn't exist. Try searching
|
||||
for what you need below.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<InputGroup className="w-3/4">
|
||||
<InputGroupInput placeholder="Try searching for pages..." />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>/</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<EmptyDescription>
|
||||
Need help? <a href="#">Contact support</a>
|
||||
</EmptyDescription>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyInCard() {
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FolderIcon"
|
||||
tabler="IconFolder"
|
||||
hugeicons="Folder01Icon"
|
||||
phosphor="FolderIcon"
|
||||
remixicon="RiFolderLine"
|
||||
/>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No projects yet</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
You haven't created any projects yet. Get started by creating
|
||||
your first project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<div className="flex gap-2">
|
||||
<LinkButton href="#">Create project</LinkButton>
|
||||
<Button variant="outline">Import project</Button>
|
||||
</div>
|
||||
<LinkButton variant="link" href="#" className="text-muted-foreground">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpRightIcon"
|
||||
tabler="IconArrowUpRight"
|
||||
hugeicons="ArrowUpRight01Icon"
|
||||
phosphor="ArrowUpRightIcon"
|
||||
remixicon="RiArrowRightUpLine"
|
||||
/>
|
||||
</LinkButton>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
997
apps/v4/registry/bases/aria/examples/field-example.tsx
Normal file
997
apps/v4/registry/bases/aria/examples/field-example.tsx
Normal file
@@ -0,0 +1,997 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { REGEXP_ONLY_DIGITS } from "input-otp"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Badge } from "@/registry/bases/aria/ui/badge"
|
||||
import { Checkbox } from "@/registry/bases/aria/ui/checkbox"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
FieldSet,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
InputOTP,
|
||||
InputOTPGroup,
|
||||
InputOTPSeparator,
|
||||
InputOTPSlot,
|
||||
} from "@/registry/bases/aria/ui/input-otp"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOptGroup,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/aria/ui/native-select"
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@/registry/bases/aria/ui/radio-group"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
import { Slider } from "@/registry/bases/aria/ui/slider"
|
||||
import { Switch } from "@/registry/bases/aria/ui/switch"
|
||||
import { Textarea } from "@/registry/bases/aria/ui/textarea"
|
||||
|
||||
export default function FieldExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<InputFields />
|
||||
<TextareaFields />
|
||||
<SelectFields />
|
||||
<CheckboxFields />
|
||||
<RadioFields />
|
||||
<SwitchFields />
|
||||
<SliderFields />
|
||||
<NativeSelectFields />
|
||||
<InputOTPFields />
|
||||
<HorizontalFields />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputFields() {
|
||||
return (
|
||||
<Example title="Input Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-basic">Basic Input</FieldLabel>
|
||||
<Input id="input-basic" placeholder="Enter text" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-with-desc">
|
||||
Input with Description
|
||||
</FieldLabel>
|
||||
<Input id="input-with-desc" placeholder="Enter your username" />
|
||||
<FieldDescription>
|
||||
Choose a unique username for your account.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-desc-first">Email Address</FieldLabel>
|
||||
<FieldDescription>
|
||||
We'll never share your email with anyone.
|
||||
</FieldDescription>
|
||||
<Input
|
||||
id="input-desc-first"
|
||||
type="email"
|
||||
placeholder="email@example.com"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-required">
|
||||
Required Field <span className="text-destructive">*</span>
|
||||
</FieldLabel>
|
||||
<Input
|
||||
id="input-required"
|
||||
placeholder="This field is required"
|
||||
required
|
||||
/>
|
||||
<FieldDescription>This field must be filled out.</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-disabled">Disabled Input</FieldLabel>
|
||||
<Input id="input-disabled" placeholder="Cannot edit" disabled />
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-badge">
|
||||
Input with Badge{" "}
|
||||
<Badge variant="secondary" className="ml-auto">
|
||||
Recommended
|
||||
</Badge>
|
||||
</FieldLabel>
|
||||
<Input id="input-badge" placeholder="Enter value" />
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="input-invalid">Invalid Input</FieldLabel>
|
||||
<Input
|
||||
id="input-invalid"
|
||||
placeholder="This field has an error"
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="input-disabled-field">Disabled Field</FieldLabel>
|
||||
<Input id="input-disabled-field" placeholder="Cannot edit" disabled />
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaFields() {
|
||||
return (
|
||||
<Example title="Textarea Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-basic">Basic Textarea</FieldLabel>
|
||||
<Textarea id="textarea-basic" placeholder="Enter your message" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-comments">Comments</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-comments"
|
||||
placeholder="Share your thoughts..."
|
||||
className="min-h-[100px]"
|
||||
/>
|
||||
<FieldDescription>Maximum 500 characters allowed.</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-bio">Bio</FieldLabel>
|
||||
<FieldDescription>
|
||||
Tell us about yourself in a few sentences.
|
||||
</FieldDescription>
|
||||
<Textarea
|
||||
id="textarea-bio"
|
||||
placeholder="I am a..."
|
||||
className="min-h-[120px]"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-desc-after">Message</FieldLabel>
|
||||
<Textarea id="textarea-desc-after" placeholder="Enter your message" />
|
||||
<FieldDescription>
|
||||
Enter your message so it is long enough to test the layout.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="textarea-invalid">Invalid Textarea</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-invalid"
|
||||
placeholder="This field has an error"
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="textarea-disabled-field">
|
||||
Disabled Field
|
||||
</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-disabled-field"
|
||||
placeholder="Cannot edit"
|
||||
disabled
|
||||
/>
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectFields() {
|
||||
const basicItems = [
|
||||
{ label: "Option 1", value: "option1" },
|
||||
{ label: "Option 2", value: "option2" },
|
||||
{ label: "Option 3", value: "option3" },
|
||||
]
|
||||
const countryItems = [
|
||||
{ label: "United States", value: "us" },
|
||||
{ label: "United Kingdom", value: "uk" },
|
||||
{ label: "Canada", value: "ca" },
|
||||
]
|
||||
const timezoneItems = [
|
||||
{ label: "UTC", value: "utc" },
|
||||
{ label: "Eastern Time", value: "est" },
|
||||
{ label: "Pacific Time", value: "pst" },
|
||||
]
|
||||
const invalidItems = [
|
||||
{ label: "Option 1", value: "option1" },
|
||||
{ label: "Option 2", value: "option2" },
|
||||
{ label: "Option 3", value: "option3" },
|
||||
]
|
||||
const disabledItems = [
|
||||
{ label: "Option 1", value: "option1" },
|
||||
{ label: "Option 2", value: "option2" },
|
||||
{ label: "Option 3", value: "option3" },
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="Select Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-basic">Basic Select</FieldLabel>
|
||||
<Select placeholder="Choose an option">
|
||||
<SelectTrigger id="select-basic">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{basicItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-country">Country</FieldLabel>
|
||||
<Select placeholder="Select your country">
|
||||
<SelectTrigger id="select-country">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{countryItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
Select the country where you currently reside.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-timezone">Timezone</FieldLabel>
|
||||
<FieldDescription>
|
||||
Choose your local timezone for accurate scheduling.
|
||||
</FieldDescription>
|
||||
<Select placeholder="Select timezone">
|
||||
<SelectTrigger id="select-timezone">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{timezoneItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="select-invalid">Invalid Select</FieldLabel>
|
||||
<Select placeholder="This field has an error" isInvalid>
|
||||
<SelectTrigger id="select-invalid">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{invalidItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="select-disabled-field">
|
||||
Disabled Field
|
||||
</FieldLabel>
|
||||
<Select placeholder="Cannot select" isDisabled>
|
||||
<SelectTrigger id="select-disabled-field">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{disabledItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectFields() {
|
||||
return (
|
||||
<Example title="Native Select Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-basic">
|
||||
Basic Native Select
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-basic">
|
||||
<NativeSelectOption value="">Choose an option</NativeSelectOption>
|
||||
<NativeSelectOption value="option1">Option 1</NativeSelectOption>
|
||||
<NativeSelectOption value="option2">Option 2</NativeSelectOption>
|
||||
<NativeSelectOption value="option3">Option 3</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-country">Country</FieldLabel>
|
||||
<NativeSelect id="native-select-country">
|
||||
<NativeSelectOption value="">
|
||||
Select your country
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>
|
||||
Select the country where you currently reside.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-timezone">Timezone</FieldLabel>
|
||||
<FieldDescription>
|
||||
Choose your local timezone for accurate scheduling.
|
||||
</FieldDescription>
|
||||
<NativeSelect id="native-select-timezone">
|
||||
<NativeSelectOption value="">Select timezone</NativeSelectOption>
|
||||
<NativeSelectOption value="utc">UTC</NativeSelectOption>
|
||||
<NativeSelectOption value="est">Eastern Time</NativeSelectOption>
|
||||
<NativeSelectOption value="pst">Pacific Time</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-grouped">
|
||||
Grouped Options
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-grouped">
|
||||
<NativeSelectOption value="">Select a region</NativeSelectOption>
|
||||
<NativeSelectOptGroup label="North America">
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
<NativeSelectOption value="mx">Mexico</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
<NativeSelectOptGroup label="Europe">
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="fr">France</NativeSelectOption>
|
||||
<NativeSelectOption value="de">Germany</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
</NativeSelect>
|
||||
<FieldDescription>
|
||||
Native select with grouped options using optgroup.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="native-select-invalid">
|
||||
Invalid Native Select
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-invalid" aria-invalid>
|
||||
<NativeSelectOption value="">
|
||||
This field has an error
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="option1">Option 1</NativeSelectOption>
|
||||
<NativeSelectOption value="option2">Option 2</NativeSelectOption>
|
||||
<NativeSelectOption value="option3">Option 3</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>
|
||||
This field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="native-select-disabled-field">
|
||||
Disabled Field
|
||||
</FieldLabel>
|
||||
<NativeSelect id="native-select-disabled-field" disabled>
|
||||
<NativeSelectOption value="">Cannot select</NativeSelectOption>
|
||||
<NativeSelectOption value="option1">Option 1</NativeSelectOption>
|
||||
<NativeSelectOption value="option2">Option 2</NativeSelectOption>
|
||||
<NativeSelectOption value="option3">Option 3</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>This field is currently disabled.</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function CheckboxFields() {
|
||||
return (
|
||||
<Example title="Checkbox Fields">
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="checkbox-basic" defaultSelected />
|
||||
<FieldLabel htmlFor="checkbox-basic">
|
||||
I agree to the terms and conditions
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="checkbox-right">
|
||||
Accept terms and conditions
|
||||
</FieldLabel>
|
||||
<Checkbox id="checkbox-right" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="checkbox-with-desc" />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="checkbox-with-desc">
|
||||
Subscribe to newsletter
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Receive weekly updates about new features and promotions.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
<FieldLabel htmlFor="checkbox-with-title">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="checkbox-with-title" />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable Touch ID</FieldTitle>
|
||||
<FieldDescription>
|
||||
Enable Touch ID to quickly unlock your device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Preferences</FieldLegend>
|
||||
<FieldDescription>
|
||||
Select all that apply to customize your experience.
|
||||
</FieldDescription>
|
||||
<FieldGroup className="gap-3">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="pref-dark" />
|
||||
<FieldLabel htmlFor="pref-dark">Dark mode</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="pref-compact" />
|
||||
<FieldLabel htmlFor="pref-compact">Compact view</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="pref-notifications" />
|
||||
<FieldLabel htmlFor="pref-notifications">
|
||||
Enable notifications
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</FieldSet>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<Checkbox id="checkbox-invalid" isInvalid />
|
||||
<FieldLabel htmlFor="checkbox-invalid">Invalid checkbox</FieldLabel>
|
||||
</Field>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<Checkbox id="checkbox-disabled-field" isDisabled />
|
||||
<FieldLabel htmlFor="checkbox-disabled-field">
|
||||
Disabled checkbox
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioFields() {
|
||||
return (
|
||||
<Example title="Radio Fields">
|
||||
<FieldGroup>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Subscription Plan</FieldLegend>
|
||||
<RadioGroup defaultValue="free">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="free" id="radio-free" />
|
||||
<FieldLabel htmlFor="radio-free">Free Plan</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="pro" id="radio-pro" />
|
||||
<FieldLabel htmlFor="radio-pro">Pro Plan</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="enterprise" id="radio-enterprise" />
|
||||
<FieldLabel htmlFor="radio-enterprise">Enterprise</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Battery Level</FieldLegend>
|
||||
<FieldDescription>
|
||||
Choose your preferred battery level.
|
||||
</FieldDescription>
|
||||
<RadioGroup>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="high" id="battery-high" />
|
||||
<FieldLabel htmlFor="battery-high">High</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="medium" id="battery-medium" />
|
||||
<FieldLabel htmlFor="battery-medium">Medium</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="low" id="battery-low" />
|
||||
<FieldLabel htmlFor="battery-low">Low</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
<RadioGroup className="gap-6">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option1" id="radio-content-1" />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="radio-content-1">Enable Touch ID</FieldLabel>
|
||||
<FieldDescription>
|
||||
Enable Touch ID to quickly unlock your device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
<RadioGroup className="gap-3">
|
||||
<FieldLabel htmlFor="radio-title-1">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="title1" id="radio-title-1" />
|
||||
<FieldContent>
|
||||
<FieldTitle>Enable Touch ID</FieldTitle>
|
||||
<FieldDescription>
|
||||
Enable Touch ID to quickly unlock your device.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Invalid Radio Group</FieldLegend>
|
||||
<RadioGroup isInvalid>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<RadioGroupItem value="invalid1" id="radio-invalid-1" />
|
||||
<FieldLabel htmlFor="radio-invalid-1">
|
||||
Invalid Option 1
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<RadioGroupItem value="invalid2" id="radio-invalid-2" />
|
||||
<FieldLabel htmlFor="radio-invalid-2">
|
||||
Invalid Option 2
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
<FieldSet>
|
||||
<FieldLegend variant="label">Disabled Radio Group</FieldLegend>
|
||||
<RadioGroup isDisabled>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<RadioGroupItem value="disabled1" id="radio-disabled-1" />
|
||||
<FieldLabel htmlFor="radio-disabled-1">
|
||||
Disabled Option 1
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<RadioGroupItem value="disabled2" id="radio-disabled-2" />
|
||||
<FieldLabel htmlFor="radio-disabled-2">
|
||||
Disabled Option 2
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchFields() {
|
||||
return (
|
||||
<Example title="Switch Fields">
|
||||
<FieldGroup>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-airplane">Airplane Mode</FieldLabel>
|
||||
<FieldDescription>
|
||||
Turn on airplane mode to disable all connections.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-airplane" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="switch-dark">Dark Mode</FieldLabel>
|
||||
<Switch id="switch-dark" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-marketing" />
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-marketing">Marketing Emails</FieldLabel>
|
||||
<FieldDescription>
|
||||
Receive emails about new products, features, and more.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>Privacy Settings</FieldLabel>
|
||||
<FieldDescription>Manage your privacy preferences.</FieldDescription>
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-profile" defaultSelected />
|
||||
<FieldLabel htmlFor="switch-profile">
|
||||
Make profile visible to others
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-email" />
|
||||
<FieldLabel htmlFor="switch-email">
|
||||
Show email on profile
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</Field>
|
||||
<Field data-invalid orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-invalid">Invalid Switch</FieldLabel>
|
||||
<FieldDescription>
|
||||
This switch has validation errors.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-invalid" />
|
||||
</Field>
|
||||
<Field data-disabled orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="switch-disabled-field">
|
||||
Disabled Switch
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
This switch is currently disabled.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-disabled-field" isDisabled />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderFields() {
|
||||
const [volume, setVolume] = useState([50])
|
||||
const [brightness, setBrightness] = useState([75])
|
||||
const [temperature, setTemperature] = useState([0.3, 0.7])
|
||||
const [priceRange, setPriceRange] = useState([25, 75])
|
||||
const [colorBalance, setColorBalance] = useState([10, 20, 70])
|
||||
|
||||
return (
|
||||
<Example title="Slider Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-volume">Volume</FieldLabel>
|
||||
<Slider
|
||||
id="slider-volume"
|
||||
value={volume}
|
||||
onChange={setVolume}
|
||||
maxValue={100}
|
||||
step={1}
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-brightness">Screen Brightness</FieldLabel>
|
||||
<Slider
|
||||
id="slider-brightness"
|
||||
value={brightness}
|
||||
onChange={setBrightness}
|
||||
maxValue={100}
|
||||
step={5}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Current brightness: {brightness[0]}%
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-quality">Video Quality</FieldLabel>
|
||||
<FieldDescription>
|
||||
Higher quality uses more bandwidth.
|
||||
</FieldDescription>
|
||||
<Slider
|
||||
id="slider-quality"
|
||||
defaultValue={[720]}
|
||||
maxValue={1080}
|
||||
minValue={360}
|
||||
step={360}
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-temperature">
|
||||
Temperature Range
|
||||
</FieldLabel>
|
||||
<Slider
|
||||
id="slider-temperature"
|
||||
value={temperature}
|
||||
onChange={setTemperature}
|
||||
minValue={0}
|
||||
maxValue={1}
|
||||
step={0.1}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Range: {temperature[0].toFixed(1)} - {temperature[1].toFixed(1)}
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-price-range">Price Range</FieldLabel>
|
||||
<Slider
|
||||
id="slider-price-range"
|
||||
value={priceRange}
|
||||
onChange={setPriceRange}
|
||||
maxValue={100}
|
||||
step={5}
|
||||
/>
|
||||
<FieldDescription>
|
||||
${priceRange[0]} - ${priceRange[1]}
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="slider-color-balance">Color Balance</FieldLabel>
|
||||
<Slider
|
||||
id="slider-color-balance"
|
||||
value={colorBalance}
|
||||
onChange={setColorBalance}
|
||||
maxValue={100}
|
||||
step={10}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Red: {colorBalance[0]}%, Green: {colorBalance[1]}%, Blue:{" "}
|
||||
{colorBalance[2]}%
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="slider-invalid">Invalid Slider</FieldLabel>
|
||||
<Slider
|
||||
id="slider-invalid"
|
||||
defaultValue={[30]}
|
||||
maxValue={100}
|
||||
aria-invalid
|
||||
/>
|
||||
<FieldDescription>
|
||||
This slider has validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="slider-disabled-field">
|
||||
Disabled Slider
|
||||
</FieldLabel>
|
||||
<Slider
|
||||
id="slider-disabled-field"
|
||||
defaultValue={[50]}
|
||||
maxValue={100}
|
||||
isDisabled
|
||||
/>
|
||||
<FieldDescription>
|
||||
This slider is currently disabled.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPFields() {
|
||||
const [value, setValue] = useState("")
|
||||
const [pinValue, setPinValue] = useState("")
|
||||
|
||||
return (
|
||||
<Example title="OTP Input Fields">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-basic">Verification Code</FieldLabel>
|
||||
<InputOTP id="otp-basic" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-with-desc">Enter OTP</FieldLabel>
|
||||
<InputOTP
|
||||
id="otp-with-desc"
|
||||
maxLength={6}
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
Enter the 6-digit code sent to your email.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-separator">
|
||||
Two-Factor Authentication
|
||||
</FieldLabel>
|
||||
<InputOTP id="otp-separator" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
Enter the code from your authenticator app.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="otp-pin">PIN Code</FieldLabel>
|
||||
<InputOTP
|
||||
id="otp-pin"
|
||||
maxLength={4}
|
||||
pattern={REGEXP_ONLY_DIGITS}
|
||||
value={pinValue}
|
||||
onChange={setPinValue}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
Enter your 4-digit PIN (numbers only).
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="otp-invalid">Invalid OTP</FieldLabel>
|
||||
<InputOTP id="otp-invalid" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} aria-invalid />
|
||||
<InputOTPSlot index={1} aria-invalid />
|
||||
<InputOTPSlot index={2} aria-invalid />
|
||||
<InputOTPSlot index={3} aria-invalid />
|
||||
<InputOTPSlot index={4} aria-invalid />
|
||||
<InputOTPSlot index={5} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
This OTP field contains validation errors.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled>
|
||||
<FieldLabel htmlFor="otp-disabled-field">Disabled OTP</FieldLabel>
|
||||
<InputOTP id="otp-disabled-field" maxLength={6} disabled>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
This OTP field is currently disabled.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function HorizontalFields() {
|
||||
const basicItems = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Orange", value: "orange" },
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="Horizontal Fields">
|
||||
<FieldGroup className="**:data-[slot=field-content]:min-w-48">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-input">Username</FieldLabel>
|
||||
<FieldDescription>Enter your preferred username.</FieldDescription>
|
||||
</FieldContent>
|
||||
<Input id="horizontal-input" placeholder="johndoe" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-textarea">Bio</FieldLabel>
|
||||
<FieldDescription>
|
||||
Write a short description about yourself.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Textarea
|
||||
id="horizontal-textarea"
|
||||
placeholder="Tell us about yourself..."
|
||||
/>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-switch">
|
||||
Email Notifications
|
||||
</FieldLabel>
|
||||
<FieldDescription>
|
||||
Receive email updates about your account.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="horizontal-switch" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-select">Favorite Fruit</FieldLabel>
|
||||
<FieldDescription>Choose your favorite fruit.</FieldDescription>
|
||||
</FieldContent>
|
||||
<Select placeholder="Select a fruit">
|
||||
<SelectTrigger id="horizontal-select">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{basicItems.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-native-select">Country</FieldLabel>
|
||||
<FieldDescription>Select your country.</FieldDescription>
|
||||
</FieldContent>
|
||||
<NativeSelect id="horizontal-native-select">
|
||||
<NativeSelectOption value="">Select a country</NativeSelectOption>
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldLabel htmlFor="horizontal-slider">Volume</FieldLabel>
|
||||
<FieldDescription>Adjust the volume level.</FieldDescription>
|
||||
</FieldContent>
|
||||
<Slider id="horizontal-slider" defaultValue={[50]} maxValue={100} />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
93
apps/v4/registry/bases/aria/examples/hover-card-example.tsx
Normal file
93
apps/v4/registry/bases/aria/examples/hover-card-example.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import {
|
||||
HoverCard,
|
||||
HoverCardTrigger,
|
||||
} from "@/registry/bases/aria/ui/hover-card"
|
||||
|
||||
export default function HoverCardExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<HoverCardSides />
|
||||
<HoverCardInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const HOVER_CARD_PLACEMENTS = [
|
||||
"start",
|
||||
"left",
|
||||
"top",
|
||||
"bottom",
|
||||
"right",
|
||||
"end",
|
||||
] as const
|
||||
|
||||
function HoverCardSides() {
|
||||
return (
|
||||
<Example title="Sides" containerClassName="col-span-2">
|
||||
<div className="flex flex-wrap items-center justify-center gap-2">
|
||||
{HOVER_CARD_PLACEMENTS.map((placement) => (
|
||||
<HoverCardTrigger key={placement} delay={100} closeDelay={100}>
|
||||
<Button variant="outline" className="capitalize">
|
||||
{placement}
|
||||
</Button>
|
||||
<HoverCard placement={placement}>
|
||||
<div className="flex flex-col style-vega:gap-2 style-nova:gap-1.5 style-lyra:gap-1 style-maia:gap-2 style-mira:gap-1 style-luma:gap-2">
|
||||
<h4 className="font-medium">Hover Card</h4>
|
||||
<p>
|
||||
This hover card appears on the {placement} side of the
|
||||
trigger.
|
||||
</p>
|
||||
</div>
|
||||
</HoverCard>
|
||||
</HoverCardTrigger>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function HoverCardInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Hover Card Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Hover over the button below to see the hover card.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<HoverCardTrigger delay={100} closeDelay={100}>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Hover me
|
||||
</Button>
|
||||
<HoverCard>
|
||||
<div className="flex flex-col style-vega:gap-2 style-nova:gap-1.5 style-lyra:gap-1 style-maia:gap-2 style-mira:gap-1 style-luma:gap-2">
|
||||
<h4 className="font-medium">Hover Card</h4>
|
||||
<p>
|
||||
This hover card appears inside a dialog. Hover over the button
|
||||
to see it.
|
||||
</p>
|
||||
</div>
|
||||
</HoverCard>
|
||||
</HoverCardTrigger>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
268
apps/v4/registry/bases/aria/examples/input-example.tsx
Normal file
268
apps/v4/registry/bases/aria/examples/input-example.tsx
Normal file
@@ -0,0 +1,268 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/aria/ui/native-select"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
|
||||
export default function InputExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<InputBasic />
|
||||
<InputInvalid />
|
||||
<InputWithLabel />
|
||||
<InputWithDescription />
|
||||
<InputDisabled />
|
||||
<InputTypes />
|
||||
<InputWithSelect />
|
||||
<InputWithButton />
|
||||
<InputWithNativeSelect />
|
||||
<InputForm />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Input type="email" placeholder="Email" />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<Input type="text" placeholder="Error" aria-invalid="true" />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-email">Email</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-email"
|
||||
type="email"
|
||||
placeholder="name@example.com"
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-username">Username</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-username"
|
||||
type="text"
|
||||
placeholder="Enter your username"
|
||||
/>
|
||||
<FieldDescription>
|
||||
Choose a unique username for your account.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-disabled">Email</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-disabled"
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
disabled
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputTypes() {
|
||||
return (
|
||||
<Example title="Input Types">
|
||||
<div className="flex w-full flex-col gap-6">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-password">Password</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-password"
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-tel">Phone</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-tel"
|
||||
type="tel"
|
||||
placeholder="+1 (555) 123-4567"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-url">URL</FieldLabel>
|
||||
<Input
|
||||
id="input-demo-url"
|
||||
type="url"
|
||||
placeholder="https://example.com"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-search">Search</FieldLabel>
|
||||
<Input id="input-demo-search" type="search" placeholder="Search" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-number">Number</FieldLabel>
|
||||
<Input id="input-demo-number" type="number" placeholder="123" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-date">Date</FieldLabel>
|
||||
<Input id="input-demo-date" type="date" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-time">Time</FieldLabel>
|
||||
<Input id="input-demo-time" type="time" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-demo-file">File</FieldLabel>
|
||||
<Input id="input-demo-file" type="file" />
|
||||
</Field>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithSelect() {
|
||||
return (
|
||||
<Example title="With Select">
|
||||
<div className="flex w-full gap-2">
|
||||
<Input type="text" placeholder="Enter amount" className="flex-1" />
|
||||
<Select defaultValue="usd">
|
||||
<SelectTrigger className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem id="usd">USD</SelectItem>
|
||||
<SelectItem id="eur">EUR</SelectItem>
|
||||
<SelectItem id="gbp">GBP</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithButton() {
|
||||
return (
|
||||
<Example title="With Button">
|
||||
<div className="flex w-full gap-2">
|
||||
<Input type="search" placeholder="Search..." className="flex-1" />
|
||||
<Button>Search</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputWithNativeSelect() {
|
||||
return (
|
||||
<Example title="With Native Select">
|
||||
<div className="flex w-full gap-2">
|
||||
<Input type="tel" placeholder="(555) 123-4567" className="flex-1" />
|
||||
<NativeSelect defaultValue="+1">
|
||||
<NativeSelectOption value="+1">+1</NativeSelectOption>
|
||||
<NativeSelectOption value="+44">+44</NativeSelectOption>
|
||||
<NativeSelectOption value="+46">+46</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputForm() {
|
||||
return (
|
||||
<Example title="Form">
|
||||
<form className="w-full">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-name">Name</FieldLabel>
|
||||
<Input id="form-name" type="text" placeholder="John Doe" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-email">Email</FieldLabel>
|
||||
<Input
|
||||
id="form-email"
|
||||
type="email"
|
||||
placeholder="john@example.com"
|
||||
/>
|
||||
<FieldDescription>
|
||||
We'll never share your email with anyone.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-phone">Phone</FieldLabel>
|
||||
<Input
|
||||
id="form-phone"
|
||||
type="tel"
|
||||
placeholder="+1 (555) 123-4567"
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-country">Country</FieldLabel>
|
||||
<Select defaultValue="us">
|
||||
<SelectTrigger id="form-country">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem id="us">United States</SelectItem>
|
||||
<SelectItem id="uk">United Kingdom</SelectItem>
|
||||
<SelectItem id="ca">Canada</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
</div>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="form-address">Address</FieldLabel>
|
||||
<Input id="form-address" type="text" placeholder="123 Main St" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<Button type="button" variant="outline">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit">Submit</Button>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
897
apps/v4/registry/bases/aria/examples/input-group-example.tsx
Normal file
897
apps/v4/registry/bases/aria/examples/input-group-example.tsx
Normal file
@@ -0,0 +1,897 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
ButtonGroup,
|
||||
ButtonGroupText,
|
||||
} from "@/registry/bases/aria/ui/button-group"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldGroup,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupInput,
|
||||
InputGroupText,
|
||||
InputGroupTextarea,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { Kbd, KbdGroup } from "@/registry/bases/aria/ui/kbd"
|
||||
import {
|
||||
Popover,
|
||||
PopoverDescription,
|
||||
PopoverHeader,
|
||||
PopoverTitle,
|
||||
PopoverTrigger,
|
||||
} from "@/registry/bases/aria/ui/popover"
|
||||
import { Spinner } from "@/registry/bases/aria/ui/spinner"
|
||||
import { Textarea } from "@/registry/bases/aria/ui/textarea"
|
||||
import { Tooltip, TooltipTrigger } from "@/registry/bases/aria/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function InputGroupExample() {
|
||||
const [country, setCountry] = useState("+1")
|
||||
|
||||
return (
|
||||
<ExampleWrapper className="min-w-0">
|
||||
<InputGroupBasic />
|
||||
<InputGroupWithAddons />
|
||||
<InputGroupWithButtons />
|
||||
<InputGroupWithTooltip country={country} setCountry={setCountry} />
|
||||
<InputGroupWithKbd />
|
||||
<InputGroupInCard />
|
||||
<InputGroupTextareaExamples />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-default-01">
|
||||
Default (No Input Group)
|
||||
</FieldLabel>
|
||||
<Input placeholder="Placeholder" id="input-default-01" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-02">Input Group</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-02" placeholder="Placeholder" />
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field data-disabled="true">
|
||||
<FieldLabel htmlFor="input-disabled-03">Disabled</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-disabled-03"
|
||||
placeholder="This field is disabled"
|
||||
disabled
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field data-invalid="true">
|
||||
<FieldLabel htmlFor="input-invalid-04">Invalid</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-invalid-04"
|
||||
placeholder="This field is invalid"
|
||||
aria-invalid="true"
|
||||
/>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithAddons() {
|
||||
return (
|
||||
<Example title="With Addons">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-left-05">
|
||||
Addon (inline-start)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-left-05" />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-right-07">
|
||||
Addon (inline-end)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-right-07" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="EyeOffIcon"
|
||||
tabler="IconEyeClosed"
|
||||
hugeicons="ViewOffIcon"
|
||||
phosphor="EyeSlashIcon"
|
||||
remixicon="RiEyeOffLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-both-09">
|
||||
Addon (inline-start and inline-end)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-both-09" />
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="MicIcon"
|
||||
tabler="IconMicrophone"
|
||||
hugeicons="VoiceIcon"
|
||||
phosphor="MicrophoneIcon"
|
||||
remixicon="RiMicLine"
|
||||
className="text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="RadioIcon"
|
||||
tabler="IconPlayerRecordFilled"
|
||||
hugeicons="RecordIcon"
|
||||
phosphor="RecordIcon"
|
||||
remixicon="RiRecordCircleLine"
|
||||
className="animate-pulse text-red-500"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-addon-20">Addon (block-start)</FieldLabel>
|
||||
<InputGroup className="h-auto">
|
||||
<InputGroupInput id="input-addon-20" />
|
||||
<InputGroupAddon align="block-start">
|
||||
<InputGroupText>First Name</InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-addon-21">Addon (block-end)</FieldLabel>
|
||||
<InputGroup className="h-auto">
|
||||
<InputGroupInput id="input-addon-21" />
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupText>20/240 characters</InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-icon-both-10">Multiple Icons</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-icon-both-10" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="StarIcon"
|
||||
tabler="IconStar"
|
||||
hugeicons="StarIcon"
|
||||
phosphor="StarIcon"
|
||||
remixicon="RiStarLine"
|
||||
/>
|
||||
<InputGroupButton
|
||||
size="icon-xs"
|
||||
onPress={() => toast("Copied to clipboard")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="RadioIcon"
|
||||
tabler="IconPlayerRecordFilled"
|
||||
hugeicons="RecordIcon"
|
||||
phosphor="RecordIcon"
|
||||
remixicon="RiRecordCircleLine"
|
||||
className="animate-pulse text-red-500"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-description-10">Description</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-description-10" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-label-10">Label</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<FieldLabel htmlFor="input-label-10">Label</FieldLabel>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="input-label-10" />
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-optional-12" aria-label="Optional" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupText>(optional)</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithButtons() {
|
||||
return (
|
||||
<Example title="With Buttons">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-button-13">Button</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-13" />
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton>Default</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-14" />
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton variant="outline">Outline</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-15" />
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton variant="secondary">Secondary</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-16" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton variant="secondary">Button</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-17" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-button-18" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton variant="secondary" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="TrashIcon"
|
||||
tabler="IconTrash"
|
||||
hugeicons="DeleteIcon"
|
||||
phosphor="TrashIcon"
|
||||
remixicon="RiDeleteBinLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithTooltip({
|
||||
country,
|
||||
setCountry,
|
||||
}: {
|
||||
country: string
|
||||
setCountry: (value: string) => void
|
||||
}) {
|
||||
return (
|
||||
<Example title="With Tooltip, Dropdown, Popover">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-tooltip-20">Tooltip</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-tooltip-20" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<TooltipTrigger>
|
||||
<InputGroupButton className="rounded-full" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
<Tooltip>This is content in a tooltip.</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-dropdown-21">Dropdown</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-dropdown-21" />
|
||||
<InputGroupAddon>
|
||||
<DropdownMenuTrigger>
|
||||
<InputGroupButton className="text-muted-foreground tabular-nums">
|
||||
{country}{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ChevronDownIcon"
|
||||
tabler="IconChevronDown"
|
||||
hugeicons="ArrowDownIcon"
|
||||
phosphor="CaretDownIcon"
|
||||
remixicon="RiArrowDownSLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
<DropdownMenu
|
||||
placement="bottom start"
|
||||
className="min-w-16"
|
||||
offset={10}
|
||||
crossOffset={-8}
|
||||
>
|
||||
<DropdownMenuItem onAction={() => setCountry("+1")}>
|
||||
+1
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onAction={() => setCountry("+44")}>
|
||||
+44
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onAction={() => setCountry("+46")}>
|
||||
+46
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-secure-19">Popover</FieldLabel>
|
||||
<InputGroup>
|
||||
<PopoverTrigger>
|
||||
<InputGroupAddon>
|
||||
<InputGroupButton variant="secondary" size="icon-xs">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
<Popover placement="bottom start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Your connection is not secure.</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
You should not enter any sensitive information on this site.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
<InputGroupAddon className="pl-1 text-muted-foreground">
|
||||
https://
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="input-secure-19" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<InputGroupButton
|
||||
size="icon-xs"
|
||||
onPress={() => toast("Added to favorites")}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="StarIcon"
|
||||
tabler="IconStar"
|
||||
hugeicons="StarIcon"
|
||||
phosphor="StarIcon"
|
||||
remixicon="RiStarLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="url">Button Group</FieldLabel>
|
||||
<ButtonGroup>
|
||||
<ButtonGroupText>https://</ButtonGroupText>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="url" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<ButtonGroupText>.com</ButtonGroupText>
|
||||
</ButtonGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupWithKbd() {
|
||||
return (
|
||||
<Example title="With Kbd">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-kbd-22">Input Group with Kbd</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-kbd-22" />
|
||||
<InputGroupAddon>
|
||||
<Kbd>⌘K</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-kbd-23" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>⌘K</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-search-apps-24"
|
||||
placeholder="Search for Apps..."
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">Ask AI</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Kbd>Tab</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-search-type-25"
|
||||
placeholder="Type to search..."
|
||||
/>
|
||||
<InputGroupAddon align="inline-start">
|
||||
<IconPlaceholder
|
||||
lucide="SparklesIcon"
|
||||
tabler="IconServerSpark"
|
||||
hugeicons="SparklesIcon"
|
||||
phosphor="SparkleIcon"
|
||||
remixicon="RiSparklingLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<KbdGroup>
|
||||
<Kbd>Ctrl</Kbd>
|
||||
<Kbd>C</Kbd>
|
||||
</KbdGroup>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-username-26">Username</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-username-26" defaultValue="shadcn" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<div className="flex size-4 items-center justify-center rounded-full bg-green-500 dark:bg-green-800">
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
className="size-3 text-white"
|
||||
/>
|
||||
</div>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription className="text-green-700">
|
||||
This username is available.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-search-docs-27"
|
||||
placeholder="Search documentation..."
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">12 results</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<InputGroup data-disabled="true">
|
||||
<InputGroupInput
|
||||
id="input-search-disabled-28"
|
||||
placeholder="Search documentation..."
|
||||
disabled
|
||||
/>
|
||||
<InputGroupAddon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="inline-end">Disabled</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldGroup className="grid grid-cols-2 gap-4">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-11">First Name</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-11" placeholder="First Name" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-12">Last Name</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-12" placeholder="Last Name" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
<Field data-disabled="true">
|
||||
<FieldLabel htmlFor="input-group-29">
|
||||
Loading ("data-disabled="true")
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="input-group-29"
|
||||
disabled
|
||||
defaultValue="shadcn"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<Spinner />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupInCard() {
|
||||
return (
|
||||
<Example title="In Card">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<CardTitle>Card with Input Group</CardTitle>
|
||||
<CardDescription>This is a card with an input group.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="email-input">Email Address</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput
|
||||
id="email-input"
|
||||
type="email"
|
||||
placeholder="you@example.com"
|
||||
/>
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="MailIcon"
|
||||
tabler="IconMail"
|
||||
hugeicons="MailIcon"
|
||||
phosphor="EnvelopeIcon"
|
||||
remixicon="RiMailLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="website-input">Website URL</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupAddon>
|
||||
<InputGroupText>https://</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
<InputGroupInput id="website-input" placeholder="example.com" />
|
||||
<InputGroupAddon align="inline-end">
|
||||
<IconPlaceholder
|
||||
lucide="ExternalLinkIcon"
|
||||
tabler="IconExternalLink"
|
||||
hugeicons="LinkSquare02Icon"
|
||||
phosphor="ArrowSquareOutIcon"
|
||||
remixicon="RiExternalLinkLine"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="feedback-textarea">
|
||||
Feedback & Comments
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="feedback-textarea"
|
||||
placeholder="Share your thoughts..."
|
||||
className="min-h-[100px]"
|
||||
/>
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupText>0/500 characters</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</CardContent>
|
||||
<CardFooter className="justify-end gap-2">
|
||||
<Button variant="outline">Cancel</Button>
|
||||
<Button>Submit</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputGroupTextareaExamples() {
|
||||
return (
|
||||
<Example title="Textarea">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-header-footer-12">
|
||||
Default Textarea (No Input Group)
|
||||
</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-header-footer-12"
|
||||
placeholder="Enter your text here..."
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-header-footer-13">
|
||||
Input Group
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-13"
|
||||
placeholder="Enter your text here..."
|
||||
/>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-invalid="true">
|
||||
<FieldLabel htmlFor="textarea-header-footer-14">Invalid</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-14"
|
||||
placeholder="Enter your text here..."
|
||||
aria-invalid="true"
|
||||
/>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field data-disabled="true">
|
||||
<FieldLabel htmlFor="textarea-header-footer-15">Disabled</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-15"
|
||||
placeholder="Enter your text here..."
|
||||
disabled
|
||||
/>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="prompt-31">Addon (block-start)</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea id="prompt-31" />
|
||||
<InputGroupAddon align="block-start">
|
||||
<InputGroupText>Ask, Search or Chat...</InputGroupText>
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
className="ml-auto text-muted-foreground"
|
||||
/>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
<FieldDescription>
|
||||
This is a description of the input group.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-header-footer-30">
|
||||
Addon (block-end)
|
||||
</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-header-footer-30"
|
||||
placeholder="Enter your text here..."
|
||||
/>
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupText>0/280 characters</InputGroupText>
|
||||
<InputGroupButton
|
||||
variant="default"
|
||||
size="icon-xs"
|
||||
className="ml-auto rounded-full"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUpIcon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
/>
|
||||
<span className="sr-only">Send</span>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-comment-31">Addon (Buttons)</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-comment-31"
|
||||
placeholder="Share your thoughts..."
|
||||
className="min-h-[120px]"
|
||||
/>
|
||||
<InputGroupAddon align="block-end">
|
||||
<InputGroupButton variant="ghost" className="ml-auto" size="sm">
|
||||
Cancel
|
||||
</InputGroupButton>
|
||||
<InputGroupButton variant="default" size="sm">
|
||||
Post Comment
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-code-32">Code Editor</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
id="textarea-code-32"
|
||||
placeholder="console.log('Hello, world!');"
|
||||
className="min-h-[300px] py-3"
|
||||
/>
|
||||
<InputGroupAddon align="block-start" className="border-b">
|
||||
<InputGroupText className="font-mono font-medium">
|
||||
<IconPlaceholder
|
||||
lucide="CodeIcon"
|
||||
tabler="IconBrandJavascript"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
script.js
|
||||
</InputGroupText>
|
||||
<InputGroupButton size="icon-xs" className="ml-auto">
|
||||
<IconPlaceholder
|
||||
lucide="RefreshCwIcon"
|
||||
tabler="IconRefresh"
|
||||
hugeicons="RefreshIcon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
<InputGroupButton size="icon-xs" variant="ghost">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="CopyIcon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
<InputGroupAddon align="block-end" className="border-t">
|
||||
<InputGroupText>Line 1, Column 1</InputGroupText>
|
||||
<InputGroupText className="ml-auto">JavaScript</InputGroupText>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
292
apps/v4/registry/bases/aria/examples/input-otp-example.tsx
Normal file
292
apps/v4/registry/bases/aria/examples/input-otp-example.tsx
Normal file
@@ -0,0 +1,292 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { REGEXP_ONLY_DIGITS, REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldError,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
InputOTP,
|
||||
InputOTPGroup,
|
||||
InputOTPSeparator,
|
||||
InputOTPSlot,
|
||||
} from "@/registry/bases/aria/ui/input-otp"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function InputOTPExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<InputOTPForm />
|
||||
<InputOTPSimple />
|
||||
<InputOTPPattern />
|
||||
<InputOTPWithSeparator />
|
||||
<InputOTPAlphanumeric />
|
||||
<InputOTPDisabled />
|
||||
<InputOTPFourDigits />
|
||||
<InputOTPInvalid />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPSimple() {
|
||||
return (
|
||||
<Example title="Simple">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="simple">Simple</FieldLabel>
|
||||
<InputOTP id="simple" maxLength={6}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPPattern() {
|
||||
return (
|
||||
<Example title="Digits Only">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="digits-only">Digits Only</FieldLabel>
|
||||
<InputOTP id="digits-only" maxLength={6} pattern={REGEXP_ONLY_DIGITS}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPWithSeparator() {
|
||||
const [value, setValue] = React.useState("123456")
|
||||
|
||||
return (
|
||||
<Example title="With Separator">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="with-separator">With Separator</FieldLabel>
|
||||
<InputOTP
|
||||
id="with-separator"
|
||||
maxLength={6}
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPAlphanumeric() {
|
||||
return (
|
||||
<Example title="Alphanumeric">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="alphanumeric">Alphanumeric</FieldLabel>
|
||||
<FieldDescription>Accepts both letters and numbers.</FieldDescription>
|
||||
<InputOTP
|
||||
id="alphanumeric"
|
||||
maxLength={6}
|
||||
pattern={REGEXP_ONLY_DIGITS_AND_CHARS}
|
||||
>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="disabled">Disabled</FieldLabel>
|
||||
<InputOTP id="disabled" maxLength={6} disabled value="123456">
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPFourDigits() {
|
||||
return (
|
||||
<Example title="4 Digits">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="four-digits">4 Digits</FieldLabel>
|
||||
<FieldDescription>Common pattern for PIN codes.</FieldDescription>
|
||||
<InputOTP id="four-digits" maxLength={4} pattern={REGEXP_ONLY_DIGITS}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
<InputOTPSlot index={3} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPInvalid() {
|
||||
const [value, setValue] = React.useState("000000")
|
||||
|
||||
return (
|
||||
<Example title="Invalid State">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="invalid">Invalid State</FieldLabel>
|
||||
<FieldDescription>
|
||||
Example showing the invalid error state.
|
||||
</FieldDescription>
|
||||
<InputOTP id="invalid" maxLength={6} value={value} onChange={setValue}>
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={0} aria-invalid />
|
||||
<InputOTPSlot index={1} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={2} aria-invalid />
|
||||
<InputOTPSlot index={3} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup>
|
||||
<InputOTPSlot index={4} aria-invalid />
|
||||
<InputOTPSlot index={5} aria-invalid />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldError errors={[{ message: "Invalid code. Please try again." }]} />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function InputOTPForm() {
|
||||
return (
|
||||
<Example title="Form">
|
||||
<Card className="mx-auto max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle>Verify your login</CardTitle>
|
||||
<CardDescription>
|
||||
Enter the verification code we sent to your email address:{" "}
|
||||
<span className="font-medium">m@example.com</span>.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form>
|
||||
<Field>
|
||||
<div className="flex items-center justify-between">
|
||||
<FieldLabel htmlFor="otp-verification">
|
||||
Verification code
|
||||
</FieldLabel>
|
||||
<Button variant="outline" size="xs">
|
||||
<IconPlaceholder
|
||||
lucide="RefreshCwIcon"
|
||||
hugeicons="RefreshIcon"
|
||||
tabler="IconRefresh"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Resend Code
|
||||
</Button>
|
||||
</div>
|
||||
<InputOTP maxLength={6} id="otp-verification" required>
|
||||
<InputOTPGroup className="*:data-[slot=input-otp-slot]:text-xl style-vega:*:data-[slot=input-otp-slot]:h-16 style-vega:*:data-[slot=input-otp-slot]:w-12 style-nova:*:data-[slot=input-otp-slot]:h-12 style-nova:*:data-[slot=input-otp-slot]:w-11 style-lyra:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:w-11 style-maia:*:data-[slot=input-otp-slot]:h-16 style-maia:*:data-[slot=input-otp-slot]:w-12 style-mira:*:data-[slot=input-otp-slot]:h-12 style-mira:*:data-[slot=input-otp-slot]:w-11 style-luma:*:data-[slot=input-otp-slot]:h-16 style-luma:*:data-[slot=input-otp-slot]:w-12">
|
||||
<InputOTPSlot index={0} />
|
||||
<InputOTPSlot index={1} />
|
||||
<InputOTPSlot index={2} />
|
||||
</InputOTPGroup>
|
||||
<InputOTPSeparator />
|
||||
<InputOTPGroup className="*:data-[slot=input-otp-slot]:text-xl style-vega:*:data-[slot=input-otp-slot]:h-16 style-vega:*:data-[slot=input-otp-slot]:w-12 style-nova:*:data-[slot=input-otp-slot]:h-12 style-nova:*:data-[slot=input-otp-slot]:w-11 style-lyra:*:data-[slot=input-otp-slot]:h-12 style-lyra:*:data-[slot=input-otp-slot]:w-11 style-maia:*:data-[slot=input-otp-slot]:h-16 style-maia:*:data-[slot=input-otp-slot]:w-12 style-mira:*:data-[slot=input-otp-slot]:h-12 style-mira:*:data-[slot=input-otp-slot]:w-11 style-luma:*:data-[slot=input-otp-slot]:h-16 style-luma:*:data-[slot=input-otp-slot]:w-12">
|
||||
<InputOTPSlot index={3} />
|
||||
<InputOTPSlot index={4} />
|
||||
<InputOTPSlot index={5} />
|
||||
</InputOTPGroup>
|
||||
</InputOTP>
|
||||
<FieldDescription>
|
||||
<a href="#">I no longer have access to this email address.</a>
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</form>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col gap-2">
|
||||
<Button type="submit" className="w-full">
|
||||
Verify
|
||||
</Button>
|
||||
<div className="text-sm text-muted-foreground">
|
||||
Having trouble signing in?{" "}
|
||||
<a
|
||||
href="#"
|
||||
className="underline underline-offset-4 transition-colors hover:text-primary"
|
||||
>
|
||||
Contact support
|
||||
</a>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
2027
apps/v4/registry/bases/aria/examples/item-example.tsx
Normal file
2027
apps/v4/registry/bases/aria/examples/item-example.tsx
Normal file
File diff suppressed because it is too large
Load Diff
188
apps/v4/registry/bases/aria/examples/kbd-example.tsx
Normal file
188
apps/v4/registry/bases/aria/examples/kbd-example.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { Kbd, KbdGroup } from "@/registry/bases/aria/ui/kbd"
|
||||
import { Tooltip, TooltipTrigger } from "@/registry/bases/aria/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function KbdExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<KbdBasic />
|
||||
<KbdModifierKeys />
|
||||
<KbdGroupExample />
|
||||
<KbdArrowKeys />
|
||||
<KbdWithIcons />
|
||||
<KbdWithIconsAndText />
|
||||
<KbdInInputGroup />
|
||||
<KbdInTooltip />
|
||||
<KbdWithSamp />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex items-center gap-2">
|
||||
<Kbd>Ctrl</Kbd>
|
||||
<Kbd>⌘K</Kbd>
|
||||
<Kbd>Ctrl + B</Kbd>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdModifierKeys() {
|
||||
return (
|
||||
<Example title="Modifier Keys">
|
||||
<div className="flex items-center gap-2">
|
||||
<Kbd>⌘</Kbd>
|
||||
<Kbd>C</Kbd>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdGroupExample() {
|
||||
return (
|
||||
<Example title="KbdGroup">
|
||||
<KbdGroup>
|
||||
<Kbd>Ctrl</Kbd>
|
||||
<Kbd>Shift</Kbd>
|
||||
<Kbd>P</Kbd>
|
||||
</KbdGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdArrowKeys() {
|
||||
return (
|
||||
<Example title="Arrow Keys">
|
||||
<div className="flex items-center gap-2">
|
||||
<Kbd>↑</Kbd>
|
||||
<Kbd>↓</Kbd>
|
||||
<Kbd>←</Kbd>
|
||||
<Kbd>→</Kbd>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<KbdGroup>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
</Kbd>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
</Kbd>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</Kbd>
|
||||
</KbdGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdWithIconsAndText() {
|
||||
return (
|
||||
<Example title="With Icons and Text">
|
||||
<KbdGroup>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowLeftIcon"
|
||||
tabler="IconArrowLeft"
|
||||
hugeicons="ArrowLeft01Icon"
|
||||
phosphor="ArrowLeftIcon"
|
||||
remixicon="RiArrowLeftLine"
|
||||
/>
|
||||
Left
|
||||
</Kbd>
|
||||
<Kbd>
|
||||
<IconPlaceholder
|
||||
lucide="CircleDashedIcon"
|
||||
tabler="IconCircleDashed"
|
||||
hugeicons="DashedLineCircleIcon"
|
||||
phosphor="CircleDashedIcon"
|
||||
remixicon="RiLoaderLine"
|
||||
/>
|
||||
Voice Enabled
|
||||
</Kbd>
|
||||
</KbdGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdInInputGroup() {
|
||||
return (
|
||||
<Example title="InputGroup">
|
||||
<InputGroup>
|
||||
<InputGroupInput />
|
||||
<InputGroupAddon>
|
||||
<Kbd>Space</Kbd>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdInTooltip() {
|
||||
return (
|
||||
<Example title="Tooltip">
|
||||
<TooltipTrigger>
|
||||
<Button size="icon-sm" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="SaveIcon"
|
||||
tabler="IconDeviceFloppy"
|
||||
hugeicons="FloppyDiskIcon"
|
||||
phosphor="FloppyDiskIcon"
|
||||
remixicon="RiSaveLine"
|
||||
/>
|
||||
</Button>
|
||||
<Tooltip className="pr-1.5">
|
||||
<div className="flex items-center gap-2">
|
||||
Save Changes <Kbd>S</Kbd>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function KbdWithSamp() {
|
||||
return (
|
||||
<Example title="With samp">
|
||||
<Kbd>
|
||||
<samp>File</samp>
|
||||
</Kbd>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
64
apps/v4/registry/bases/aria/examples/label-example.tsx
Normal file
64
apps/v4/registry/bases/aria/examples/label-example.tsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Checkbox } from "@/registry/bases/aria/ui/checkbox"
|
||||
import { Field } from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import { Label } from "@/registry/bases/aria/ui/label"
|
||||
import { Textarea } from "@/registry/bases/aria/ui/textarea"
|
||||
|
||||
export default function LabelExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<LabelWithCheckbox />
|
||||
<LabelWithInput />
|
||||
<LabelDisabled />
|
||||
<LabelWithTextarea />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelWithCheckbox() {
|
||||
return (
|
||||
<Example title="With Checkbox">
|
||||
<Field orientation="horizontal">
|
||||
<Checkbox id="label-demo-terms" />
|
||||
<Label htmlFor="label-demo-terms">Accept terms and conditions</Label>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelWithInput() {
|
||||
return (
|
||||
<Example title="With Input">
|
||||
<Field>
|
||||
<Label htmlFor="label-demo-username">Username</Label>
|
||||
<Input id="label-demo-username" placeholder="Username" />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field data-disabled={true}>
|
||||
<Label htmlFor="label-demo-disabled">Disabled</Label>
|
||||
<Input id="label-demo-disabled" placeholder="Disabled" disabled />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function LabelWithTextarea() {
|
||||
return (
|
||||
<Example title="With Textarea">
|
||||
<Field>
|
||||
<Label htmlFor="label-demo-message">Message</Label>
|
||||
<Textarea id="label-demo-message" placeholder="Message" />
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
326
apps/v4/registry/bases/aria/examples/marker-example.tsx
Normal file
326
apps/v4/registry/bases/aria/examples/marker-example.tsx
Normal file
@@ -0,0 +1,326 @@
|
||||
"use client"
|
||||
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/registry/bases/aria/ui/accordion"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
DrawerContent,
|
||||
DrawerDescription,
|
||||
DrawerFooter,
|
||||
DrawerHeader,
|
||||
DrawerTitle,
|
||||
DrawerTrigger,
|
||||
} from "@/registry/bases/aria/ui/drawer"
|
||||
import {
|
||||
Marker,
|
||||
MarkerContent,
|
||||
MarkerIcon,
|
||||
} from "@/registry/bases/aria/ui/marker"
|
||||
import { Spinner } from "@/registry/bases/aria/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function MarkerExamples() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<MarkerExample />
|
||||
<MarkerBorder />
|
||||
<MarkerSeparator />
|
||||
<MarkerAccordion />
|
||||
<MarkerDrawer />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerExample() {
|
||||
return (
|
||||
<Example title="Markers" className="gap-8">
|
||||
<Marker>
|
||||
<MarkerContent>A default marker</MarkerContent>
|
||||
</Marker>
|
||||
<Marker>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileDescription"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker with icon</MarkerContent>
|
||||
</Marker>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker with a spinner</MarkerContent>
|
||||
</Marker>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent className="shimmer">
|
||||
Marker with shimmer effect
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
<Marker role="status">
|
||||
<MarkerContent className="shimmer">Thinking...</MarkerContent>
|
||||
</Marker>
|
||||
<Marker render={(props) => <a href="#" {...props} />}>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="GitBranchIcon"
|
||||
tabler="IconGitBranch"
|
||||
hugeicons="GitBranchIcon"
|
||||
phosphor="GitBranchIcon"
|
||||
remixicon="RiGitBranchLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker as a link</MarkerContent>
|
||||
</Marker>
|
||||
<Marker
|
||||
className="transition-colors hover:text-foreground"
|
||||
render={(props) => (
|
||||
<button {...props} onClick={() => toast("You clicked the button")} />
|
||||
)}
|
||||
>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="ClockIcon"
|
||||
tabler="IconClock"
|
||||
hugeicons="Clock01Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent className="flex-1">
|
||||
<div>Marker as a button</div>
|
||||
</MarkerContent>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
</Marker>
|
||||
<Marker>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="CircleUserIcon"
|
||||
tabler="IconUserCircle"
|
||||
hugeicons="UserCircleIcon"
|
||||
phosphor="UserCircleIcon"
|
||||
remixicon="RiUserSmileLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Rhea joined the chat</MarkerContent>
|
||||
</Marker>
|
||||
<Marker className="justify-center">
|
||||
<MarkerContent>
|
||||
<strong className="font-medium">Olivia Rose</strong> left the chat
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
<Marker className="flex-col">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileDescription"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Marker with icon at the top</MarkerContent>
|
||||
</Marker>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerBorder() {
|
||||
return (
|
||||
<Example title="Border" className="gap-3">
|
||||
<Marker variant="border">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="GitBranchIcon"
|
||||
tabler="IconGitBranch"
|
||||
hugeicons="GitBranchIcon"
|
||||
phosphor="GitBranchIcon"
|
||||
remixicon="RiGitBranchLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Switched to release-candidate</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="border">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="Search01Icon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Reviewed 8 related files</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="border">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileDescription"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Opened implementation notes</MarkerContent>
|
||||
</Marker>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerSeparator() {
|
||||
return (
|
||||
<Example title="Separator" className="gap-8">
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>Worked for 42s</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator" role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Compacting conversation</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator" role="status">
|
||||
<MarkerContent className="shimmer">Reading 4 files</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator">
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Conversation compacted</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>
|
||||
With a <a href="#">link to learn more</a>
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
<Marker variant="separator">
|
||||
<MarkerContent>
|
||||
<Button variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="GitBranchIcon"
|
||||
tabler="IconGitBranch"
|
||||
hugeicons="GitBranchIcon"
|
||||
phosphor="GitBranchIcon"
|
||||
remixicon="RiGitBranchLine"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
</MarkerContent>
|
||||
</Marker>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerAccordion() {
|
||||
return (
|
||||
<Example title="Accordion" containerClassName="min-h-72">
|
||||
<Accordion>
|
||||
<AccordionItem id="1">
|
||||
<AccordionTrigger>
|
||||
<Marker>
|
||||
<MarkerIcon>
|
||||
<IconPlaceholder
|
||||
lucide="ClockIcon"
|
||||
tabler="IconClock"
|
||||
hugeicons="Clock01Icon"
|
||||
phosphor="ClockIcon"
|
||||
remixicon="RiTimeLine"
|
||||
/>
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Worked for 42s</MarkerContent>
|
||||
</Marker>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
The user asked for a list of all the files in the current
|
||||
directory. The assistant responded with a list of all the files in
|
||||
the current directory.
|
||||
</p>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MarkerDrawer() {
|
||||
return (
|
||||
<Example title="Drawer">
|
||||
<Drawer swipeDirection="right">
|
||||
<Marker variant="separator">
|
||||
<DrawerTrigger render={<Button variant="outline" />}>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Explored 4 files
|
||||
</DrawerTrigger>
|
||||
</Marker>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>File Activity</DrawerTitle>
|
||||
<DrawerDescription>
|
||||
Files read while preparing the response.
|
||||
</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<div className="grid gap-3 px-4 text-sm">
|
||||
<div className="flex items-center justify-between gap-4 rounded-md border px-3 py-2">
|
||||
<span className="truncate">app/chat/page.tsx</span>
|
||||
<span className="text-muted-foreground">read</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4 rounded-md border px-3 py-2">
|
||||
<span className="truncate">components/message.tsx</span>
|
||||
<span className="text-muted-foreground">read</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-4 rounded-md border px-3 py-2">
|
||||
<span className="truncate">lib/ai.ts</span>
|
||||
<span className="text-muted-foreground">read</span>
|
||||
</div>
|
||||
</div>
|
||||
<DrawerFooter>
|
||||
<DrawerClose render={<Button variant="outline" />}>
|
||||
Close
|
||||
</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
923
apps/v4/registry/bases/aria/examples/message-example.tsx
Normal file
923
apps/v4/registry/bases/aria/examples/message-example.tsx
Normal file
@@ -0,0 +1,923 @@
|
||||
import type { UIMessage } from "ai"
|
||||
|
||||
import { createChat } from "@/lib/ai"
|
||||
import { type MessagePartRenderProps } from "@/components/message-parts"
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Attachment,
|
||||
AttachmentAction,
|
||||
AttachmentActions,
|
||||
AttachmentContent,
|
||||
AttachmentDescription,
|
||||
AttachmentGroup,
|
||||
AttachmentMedia,
|
||||
AttachmentTitle,
|
||||
} from "@/registry/bases/aria/ui/attachment"
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/aria/ui/avatar"
|
||||
import {
|
||||
Bubble,
|
||||
BubbleContent,
|
||||
BubbleGroup,
|
||||
BubbleReactions,
|
||||
} from "@/registry/bases/aria/ui/bubble"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Marker,
|
||||
MarkerContent,
|
||||
MarkerIcon,
|
||||
} from "@/registry/bases/aria/ui/marker"
|
||||
import {
|
||||
Message,
|
||||
MessageAvatar,
|
||||
MessageContent,
|
||||
MessageFooter,
|
||||
MessageGroup,
|
||||
MessageHeader,
|
||||
} from "@/registry/bases/aria/ui/message"
|
||||
import { Spinner } from "@/registry/bases/aria/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
type MessagePartsData = {
|
||||
deployment: {
|
||||
status: "healthy" | "degraded"
|
||||
region: string
|
||||
latency: number
|
||||
}
|
||||
}
|
||||
|
||||
type MessagePartsTools = {
|
||||
getDeploymentHealth: {
|
||||
input: {
|
||||
project: string
|
||||
region: string
|
||||
}
|
||||
output: {
|
||||
status: "healthy" | "degraded"
|
||||
p95: number
|
||||
errors: number
|
||||
recommendation: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type MessagePartsMessage = UIMessage<
|
||||
unknown,
|
||||
MessagePartsData,
|
||||
MessagePartsTools
|
||||
>
|
||||
|
||||
const messagePartsChat = createChat<MessagePartsMessage>()
|
||||
.user("Can you review this screenshot and check the deployment?", {
|
||||
files: [
|
||||
{
|
||||
mediaType: "image/jpeg",
|
||||
filename: "checkout-error.jpg",
|
||||
url: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=900&auto=format&fit=crop&q=80",
|
||||
},
|
||||
],
|
||||
})
|
||||
.assistant(({ writer }) => {
|
||||
writer.reasoning(
|
||||
"The user included an image and asked for deployment status, so I should inspect the screenshot context and call the deployment health tool before answering."
|
||||
)
|
||||
|
||||
const deployment = writer.tool("getDeploymentHealth", {
|
||||
title: "Checking deployment health",
|
||||
input: {
|
||||
project: "checkout",
|
||||
region: "iad1",
|
||||
},
|
||||
})
|
||||
|
||||
deployment.output({
|
||||
status: "healthy",
|
||||
p95: 186,
|
||||
errors: 2,
|
||||
recommendation: "Keep the deployment live and monitor error rate.",
|
||||
})
|
||||
|
||||
writer.data({
|
||||
type: "data-deployment",
|
||||
id: "deployment-health",
|
||||
data: {
|
||||
status: "healthy",
|
||||
region: "iad1",
|
||||
latency: 186,
|
||||
},
|
||||
})
|
||||
writer.text(
|
||||
"The deployment looks healthy. P95 latency is **186ms** with **2 recent errors**, so I would keep it live and monitor error rate for the next 15 minutes."
|
||||
)
|
||||
writer.sourceUrl({
|
||||
sourceId: "source-deployment-docs",
|
||||
title: "Deployment health checks",
|
||||
url: "https://vercel.com/docs/deployments",
|
||||
})
|
||||
writer.sourceDocument({
|
||||
sourceId: "source-runbook",
|
||||
title: "Checkout release runbook",
|
||||
filename: "checkout-release-runbook.md",
|
||||
mediaType: "text/markdown",
|
||||
})
|
||||
})
|
||||
|
||||
const messagePartsMessages = messagePartsChat.get()
|
||||
|
||||
type MessagePartsPart = MessagePartsMessage["parts"][number]
|
||||
|
||||
export default function MessageExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<MessageDefault />
|
||||
<MessageWithAvatar />
|
||||
<MessageGroupExample />
|
||||
<MessageGroupChat />
|
||||
<MessageHeaderFooter />
|
||||
<MessageActions />
|
||||
<MessageAttachment />
|
||||
<MessageAttachmentGroup />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageTextPart({
|
||||
part,
|
||||
message,
|
||||
}: MessagePartRenderProps<MessagePartsPart, MessagePartsMessage>) {
|
||||
if (part.type !== "text") {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Bubble
|
||||
align={message.role === "user" ? "end" : "start"}
|
||||
variant={message.role === "user" ? "default" : "ghost"}
|
||||
>
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">{part.text}</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageDefault() {
|
||||
return (
|
||||
<Example title="Message">
|
||||
<div className="flex w-full max-w-md min-w-0 flex-col gap-10">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>Deploying to prod real quick.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>It's 4:55 PM. On a Friday.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>It's a one-line change.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<BubbleGroup>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
It's always a one-line change 😭. Make sure to run the
|
||||
tests this time.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Alright, go for it.</BubbleContent>
|
||||
</Bubble>
|
||||
</BubbleGroup>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageWithAvatar() {
|
||||
return (
|
||||
<Example title="Avatar">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/shadcn.png"
|
||||
alt="@shadcn"
|
||||
className="grayscale"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Something went wrong. Any idea?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
I checked the latest deployment and found the build failed
|
||||
during dependency installation.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Something went wrong. Any idea?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://avatar.vercel.sh/shadcn"
|
||||
alt="@shadcn"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent className="space-y-2">
|
||||
<div>
|
||||
I checked the latest deployment and found the build failed
|
||||
during dependency installation.
|
||||
</div>
|
||||
<div>Can you share the exact error message from the logs?</div>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="destructive">
|
||||
<BubbleContent>Something went wrong. Any idea?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageGroupExample() {
|
||||
return (
|
||||
<Example title="Group">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<MessageGroup>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<MessageGroup>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<MessageGroup>
|
||||
<Message align="end">
|
||||
<MessageAvatar />
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://avatar.vercel.sh/shadcn"
|
||||
alt="@shadcn"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<MessageGroup>
|
||||
<Message>
|
||||
<MessageAvatar />
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>I checked the registry addresses.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://avatar.vercel.sh/shadcn"
|
||||
alt="@shadcn"
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The component and example JSON now live under the UI registry.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageGroupChat() {
|
||||
return (
|
||||
<Example title="Group Chat">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
Why is the dashboard showing zero users
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<MessageGroup>
|
||||
<Message>
|
||||
<MessageAvatar />
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>Define "zero."</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>What do you mean?</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageGroup>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble variant="tinted">
|
||||
<BubbleContent>
|
||||
<span className="font-medium">@eve</span> can you check?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Checking the logs...</MarkerContent>
|
||||
</Marker>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<MessageHeader>Eve</MessageHeader>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
<span className="whitespace-pre-wrap">
|
||||
{`I found the following error in the logs:
|
||||
|
||||
- Error: No users found
|
||||
- Stack trace:
|
||||
- at src/users/services/user-service.ts:123
|
||||
- at src/users/services/get-user.ts:230
|
||||
|
||||
Can you check if the users are being created?`}
|
||||
</span>
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageHeaderFooter() {
|
||||
return (
|
||||
<Example title="Header and Footer">
|
||||
<div className="flex w-full max-w-md flex-col gap-12">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<MessageHeader className="justify-end">You</MessageHeader>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Can we keep this style quiet and send the update today?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Delivered</span>
|
||||
<Button variant="ghost" size="xs">
|
||||
Undo
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="start">
|
||||
<MessageContent>
|
||||
<MessageHeader>
|
||||
<span>Olivia</span>
|
||||
<span className="ml-auto font-normal">1m ago</span>
|
||||
</MessageHeader>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
I checked the logs. The retry finished and the missing invoices
|
||||
are included now.
|
||||
</BubbleContent>
|
||||
<BubbleReactions>
|
||||
<Button variant="ghost" size="xs">
|
||||
Thanks
|
||||
</Button>
|
||||
</BubbleReactions>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>From Support queue</span>
|
||||
<Button variant="ghost" size="xs">
|
||||
Copy
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<MessageHeader>Marina</MessageHeader>
|
||||
<Bubble variant="outline">
|
||||
<BubbleContent>
|
||||
I drafted the reply with the exact filter path and a link to the
|
||||
export history.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Draft ready</span>
|
||||
<Button variant="outline" size="xs">
|
||||
Review
|
||||
</Button>
|
||||
<Button size="xs">Send</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="start">
|
||||
<MessageContent>
|
||||
<MessageHeader>Assistant note</MessageHeader>
|
||||
<Bubble variant="ghost">
|
||||
<BubbleContent>
|
||||
Ghost messages keep long-form assistant notes aligned with the
|
||||
surrounding text instead of adding a frame.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Internal only</span>
|
||||
<Button variant="ghost" size="xs">
|
||||
Pin
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<MessageHeader className="justify-end">
|
||||
Automation warning
|
||||
</MessageHeader>
|
||||
<Bubble variant="destructive">
|
||||
<BubbleContent>
|
||||
The old export link expires in 10 minutes. Regenerate before
|
||||
sending this transcript externally.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span>Needs action</span>
|
||||
<Button variant="destructive" size="xs">
|
||||
Regenerate
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageAttachment() {
|
||||
return (
|
||||
<Example title="Attachment">
|
||||
<div className="flex w-full max-w-sm flex-col gap-8">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Workspace"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Here's the image. Can you add it to the PDF? Use it for the
|
||||
cover page.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
Done. Here's the PDF with the image added as the cover
|
||||
page.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<Attachment>
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>sales-dashboard.pdf</AttachmentTitle>
|
||||
<AttachmentDescription>PDF · 2.4 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
aria-label="Download"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>Thanks. Looks good.</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageAttachmentGroup() {
|
||||
return (
|
||||
<Example title="Attachment Group">
|
||||
<div className="flex w-full max-w-sm flex-col gap-8">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<AttachmentGroup className="w-[80%]">
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497366754035-f200968a6e72?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Workspace"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497215728101-856f4ea42174?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Desk"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
<Attachment orientation="vertical">
|
||||
<AttachmentMedia variant="image">
|
||||
<img
|
||||
src="https://images.unsplash.com/photo-1497366811353-6870744d04b2?w=900&auto=format&fit=crop&q=80"
|
||||
alt="Office"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
</Attachment>
|
||||
</AttachmentGroup>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Here are the brand photos. Can you add them to the deck?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
Done. Here's the draft deck and the exported assets.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<AttachmentGroup className="w-full">
|
||||
<Attachment className="w-64">
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="FileTextIcon"
|
||||
tabler="IconFileText"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileTextIcon"
|
||||
remixicon="RiFileTextLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>brand-deck.pdf</AttachmentTitle>
|
||||
<AttachmentDescription>PDF · 3.1 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
aria-label="Download brand-deck.pdf"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
<Attachment className="w-64">
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="PresentationIcon"
|
||||
tabler="IconPresentation"
|
||||
hugeicons="Presentation01Icon"
|
||||
phosphor="PresentationIcon"
|
||||
remixicon="RiSlideshowLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>brand-deck.key</AttachmentTitle>
|
||||
<AttachmentDescription>Keynote · 9 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
aria-label="Download brand-deck.key"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
<Attachment className="w-64">
|
||||
<AttachmentMedia>
|
||||
<IconPlaceholder
|
||||
lucide="FileArchiveIcon"
|
||||
tabler="IconFileZip"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileZipIcon"
|
||||
remixicon="RiFileZipLine"
|
||||
/>
|
||||
</AttachmentMedia>
|
||||
<AttachmentContent>
|
||||
<AttachmentTitle>brand-assets.zip</AttachmentTitle>
|
||||
<AttachmentDescription>ZIP · 4.2 MB</AttachmentDescription>
|
||||
</AttachmentContent>
|
||||
<AttachmentActions>
|
||||
<AttachmentAction
|
||||
type="button"
|
||||
aria-label="Download brand-assets.zip"
|
||||
size="icon-sm"
|
||||
variant="secondary"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="DownloadIcon"
|
||||
tabler="IconDownload"
|
||||
hugeicons="Download01Icon"
|
||||
phosphor="DownloadIcon"
|
||||
remixicon="RiDownloadLine"
|
||||
/>
|
||||
</AttachmentAction>
|
||||
</AttachmentActions>
|
||||
</Attachment>
|
||||
</AttachmentGroup>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function MessageActions() {
|
||||
return (
|
||||
<Example title="Actions">
|
||||
<div className="flex w-full max-w-md flex-col gap-10">
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
What is the status of the deployment?
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter>
|
||||
<Button variant="ghost" size="icon" aria-label="Copy">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" aria-label="Retry">
|
||||
<IconPlaceholder
|
||||
lucide="RefreshCcwIcon"
|
||||
tabler="IconRefresh"
|
||||
hugeicons="ReloadIcon"
|
||||
phosphor="ArrowClockwiseIcon"
|
||||
remixicon="RiRefreshLine"
|
||||
/>
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message>
|
||||
<MessageAvatar>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src="https://github.com/evilrabbit.png"
|
||||
alt="@evilrabbit"
|
||||
/>
|
||||
<AvatarFallback>ER</AvatarFallback>
|
||||
</Avatar>
|
||||
</MessageAvatar>
|
||||
<MessageContent>
|
||||
<Bubble variant="muted">
|
||||
<BubbleContent>
|
||||
The install failure is coming from the workspace package. I can
|
||||
open the exact log line or retry the deployment.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter>
|
||||
<Button variant="ghost" size="icon" aria-label="Copy">
|
||||
<IconPlaceholder
|
||||
lucide="CopyIcon"
|
||||
tabler="IconCopy"
|
||||
hugeicons="Copy01Icon"
|
||||
phosphor="CopyIcon"
|
||||
remixicon="RiFileCopyLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" aria-label="Like: thumbs up">
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsUpIcon"
|
||||
tabler="IconThumbUp"
|
||||
hugeicons="ThumbsUpIcon"
|
||||
phosphor="ThumbsUpIcon"
|
||||
remixicon="RiThumbUpLine"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
aria-label="Like: thumbs down"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ThumbsDownIcon"
|
||||
tabler="IconThumbDown"
|
||||
hugeicons="ThumbsDownIcon"
|
||||
phosphor="ThumbsDownIcon"
|
||||
remixicon="RiThumbDownLine"
|
||||
/>
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
<Message align="end">
|
||||
<MessageContent>
|
||||
<Bubble>
|
||||
<BubbleContent>
|
||||
Okay drop me a link. I'll check it out.
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
<MessageFooter className="gap-2">
|
||||
<span className="font-normal text-destructive">
|
||||
Failed to send
|
||||
</span>
|
||||
<Button variant="secondary" size="xs">
|
||||
Retry
|
||||
</Button>
|
||||
</MessageFooter>
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { useChat } from "@ai-sdk/react"
|
||||
|
||||
import { createChat, getMessageText } from "@/lib/ai"
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Bubble, BubbleContent } from "@/registry/bases/aria/ui/bubble"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupButton,
|
||||
InputGroupTextarea,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import {
|
||||
Marker,
|
||||
MarkerContent,
|
||||
MarkerIcon,
|
||||
} from "@/registry/bases/aria/ui/marker"
|
||||
import { Message, MessageContent } from "@/registry/bases/aria/ui/message"
|
||||
import {
|
||||
MessageScroller,
|
||||
MessageScrollerButton,
|
||||
MessageScrollerContent,
|
||||
MessageScrollerItem,
|
||||
MessageScrollerProvider,
|
||||
MessageScrollerViewport,
|
||||
} from "@/registry/bases/aria/ui/message-scroller"
|
||||
import { Spinner } from "@/registry/bases/aria/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function MessageScrollerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<MessageScrollerDemo />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
const chat = createChat()
|
||||
.user("Hello there!")
|
||||
.sleep(2000)
|
||||
.assistant("Hey, how's it going?")
|
||||
.user(
|
||||
`I'm prototyping an AI chat surface for our product docs.
|
||||
|
||||
Can you sketch a sensible component breakdown and call out anything I'd regret baking into v1?`
|
||||
)
|
||||
.sleep(2000)
|
||||
.assistant(
|
||||
`## Recommended layout
|
||||
|
||||
Treat the chat as three layers so scrolling and the composer never fight each other:
|
||||
|
||||
| Layer | Responsibility |
|
||||
| --- | --- |
|
||||
| **Shell** | Card or page frame, title, status indicator |
|
||||
| **Transcript** | \`overflow-y-auto\` message list |
|
||||
| **Composer** | Input group, send, stop |
|
||||
|
||||
### Message rendering
|
||||
|
||||
- **User messages**: right-aligned, muted background, \`max-w-[80%]\`.
|
||||
- **Assistant messages**: full width within the column; use \`whitespace-pre-wrap\` for text.
|
||||
|
||||
### Suggested component split
|
||||
|
||||
\`\`\`tsx
|
||||
<ChatCard>
|
||||
<ChatHeader status={status} />
|
||||
<ChatTranscript messages={messages} />
|
||||
<ChatComposer onSubmit={sendMessage} onStop={stop} />
|
||||
</ChatCard>
|
||||
\`\`\`
|
||||
|
||||
### v1 pitfalls to avoid
|
||||
|
||||
1. **Inlining transport logic in the UI** — keep scripted/demo transport beside your example, not inside shared components.
|
||||
2. **Fixed transcript height without \`overflow-hidden\`** — parent must clip, child must scroll, or the composer jumps.
|
||||
3. **Not giving the scroller a ref or auto-scroll flag** — long replies should stay pinned to the bottom unless the user scrolls up.
|
||||
|
||||
### Practical next step
|
||||
|
||||
Start with plain \`whitespace-pre-wrap\` text to validate spacing and scroll behavior. Once the transcript feels right, you can swap assistant text rendering to a richer renderer if you need it.
|
||||
|
||||
Want me to walk through auto-scroll vs. manual scroll-to-bottom next?`
|
||||
)
|
||||
.user(
|
||||
"What about message spacing when one reply is short and the next is really long?"
|
||||
)
|
||||
.sleep(2000)
|
||||
.assistant(
|
||||
`Good question. The scroll container should own vertical rhythm, not individual bubbles.
|
||||
|
||||
Use a consistent \`gap\` on the message list (something like \`gap-4\` or \`gap-6\`) so short and long messages sit on the same grid. For assistant replies that span many paragraphs, keep everything in one bubble rather than splitting on every line break — otherwise the transcript feels choppy when you're skimming.
|
||||
|
||||
When a long reply streams in, pin the viewport to the bottom with \`MessageScroller autoScroll\` until the user scrolls up. If they've scrolled away, show a scroll-to-bottom affordance instead of yanking them back mid-read.
|
||||
|
||||
That's usually enough for v1. Fancy diff animations or per-paragraph fade-ins can wait until you've validated that the base scroll + composer layout holds up on real devices.`
|
||||
)
|
||||
.user("Thanks, that helps.")
|
||||
.sleep(1000)
|
||||
.assistant(
|
||||
"Happy to help — send another message when you're ready to keep stepping through the demo."
|
||||
)
|
||||
|
||||
const initialMessages = chat.get(0)
|
||||
const transport = chat.transport({
|
||||
delayMs: 10,
|
||||
})
|
||||
|
||||
function MessageScrollerDemo() {
|
||||
const { messages, sendMessage, status, stop } = useChat({
|
||||
messages: initialMessages,
|
||||
transport,
|
||||
})
|
||||
const nextMessage = chat.next(messages)
|
||||
const isBusy = status === "submitted" || status === "streaming"
|
||||
|
||||
function handleFormSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
if (!nextMessage || isBusy) {
|
||||
return
|
||||
}
|
||||
|
||||
void sendMessage(nextMessage)
|
||||
}
|
||||
|
||||
return (
|
||||
<Example title="Chat" containerClassName="self-start">
|
||||
<Card className="h-140">
|
||||
<CardHeader>
|
||||
<CardTitle>How can I help you today?</CardTitle>
|
||||
<CardDescription>Status: {status}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="min-h-0 flex-1 overflow-hidden p-0">
|
||||
<MessageScrollerProvider>
|
||||
<MessageScroller>
|
||||
<MessageScrollerViewport>
|
||||
<MessageScrollerContent className="p-(--card-spacing)">
|
||||
{messages.map((message) => (
|
||||
<MessageScrollerItem
|
||||
key={message.id}
|
||||
messageId={message.id}
|
||||
scrollAnchor={message.role === "user"}
|
||||
>
|
||||
<Message
|
||||
align={message.role === "user" ? "end" : "start"}
|
||||
>
|
||||
<MessageContent>
|
||||
{message.parts.map((part, index) => {
|
||||
if (part.type !== "text") {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Bubble
|
||||
key={`${message.id}-${index}`}
|
||||
variant={
|
||||
message.role === "user" ? "default" : "muted"
|
||||
}
|
||||
>
|
||||
<BubbleContent className="whitespace-pre-wrap">
|
||||
{part.text}
|
||||
</BubbleContent>
|
||||
</Bubble>
|
||||
)
|
||||
})}
|
||||
</MessageContent>
|
||||
</Message>
|
||||
</MessageScrollerItem>
|
||||
))}
|
||||
{status === "submitted" ? (
|
||||
<MessageScrollerItem scrollAnchor={false}>
|
||||
<Marker role="status">
|
||||
<MarkerIcon>
|
||||
<Spinner />
|
||||
</MarkerIcon>
|
||||
<MarkerContent>Thinking...</MarkerContent>
|
||||
</Marker>
|
||||
</MessageScrollerItem>
|
||||
) : null}
|
||||
</MessageScrollerContent>
|
||||
</MessageScrollerViewport>
|
||||
<MessageScrollerButton />
|
||||
</MessageScroller>
|
||||
</MessageScrollerProvider>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<form onSubmit={handleFormSubmit} className="w-full" id="chat-form">
|
||||
<InputGroup>
|
||||
<InputGroupTextarea
|
||||
placeholder="Ask me anything..."
|
||||
className="h-10 min-h-10 overflow-y-auto"
|
||||
value={
|
||||
isBusy ? "" : nextMessage ? getMessageText(nextMessage) : ""
|
||||
}
|
||||
readOnly
|
||||
/>
|
||||
<InputGroupAddon align="block-end" className="p-2">
|
||||
<InputGroupButton
|
||||
variant="default"
|
||||
size="icon-sm"
|
||||
type="submit"
|
||||
isDisabled={!nextMessage || isBusy}
|
||||
className="ml-auto data-[hidden=true]:hidden"
|
||||
data-hidden={isBusy}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUp02Icon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
/>
|
||||
<span className="sr-only">Send</span>
|
||||
</InputGroupButton>
|
||||
<InputGroupButton
|
||||
size="icon-sm"
|
||||
type="button"
|
||||
data-hidden={!isBusy}
|
||||
className="ml-auto data-[hidden=true]:hidden"
|
||||
onClick={() => stop()}
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="StopCircleIcon"
|
||||
tabler="IconPlayerStop"
|
||||
hugeicons="StopCircleIcon"
|
||||
phosphor="StopCircleIcon"
|
||||
remixicon="RiStopCircleLine"
|
||||
/>
|
||||
<span className="sr-only">Stop</span>
|
||||
</InputGroupButton>
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</form>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
129
apps/v4/registry/bases/aria/examples/native-select-example.tsx
Normal file
129
apps/v4/registry/bases/aria/examples/native-select-example.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOptGroup,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/aria/ui/native-select"
|
||||
|
||||
export default function NativeSelectExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<NativeSelectBasic />
|
||||
<NativeSelectWithGroups />
|
||||
<NativeSelectSizes />
|
||||
<NativeSelectWithField />
|
||||
<NativeSelectDisabled />
|
||||
<NativeSelectInvalid />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<NativeSelect>
|
||||
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
<NativeSelectOption value="grapes" disabled>
|
||||
Grapes
|
||||
</NativeSelectOption>
|
||||
<NativeSelectOption value="pineapple">Pineapple</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectWithGroups() {
|
||||
return (
|
||||
<Example title="With Groups">
|
||||
<NativeSelect>
|
||||
<NativeSelectOption value="">Select a food</NativeSelectOption>
|
||||
<NativeSelectOptGroup label="Fruits">
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
<NativeSelectOptGroup label="Vegetables">
|
||||
<NativeSelectOption value="carrot">Carrot</NativeSelectOption>
|
||||
<NativeSelectOption value="broccoli">Broccoli</NativeSelectOption>
|
||||
<NativeSelectOption value="spinach">Spinach</NativeSelectOption>
|
||||
</NativeSelectOptGroup>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-4">
|
||||
<NativeSelect size="sm">
|
||||
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<NativeSelect size="default">
|
||||
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectWithField() {
|
||||
return (
|
||||
<Example title="With Field">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="native-select-country">Country</FieldLabel>
|
||||
<NativeSelect id="native-select-country">
|
||||
<NativeSelectOption value="">Select a country</NativeSelectOption>
|
||||
<NativeSelectOption value="us">United States</NativeSelectOption>
|
||||
<NativeSelectOption value="uk">United Kingdom</NativeSelectOption>
|
||||
<NativeSelectOption value="ca">Canada</NativeSelectOption>
|
||||
<NativeSelectOption value="au">Australia</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
<FieldDescription>Select your country of residence.</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<NativeSelect disabled>
|
||||
<NativeSelectOption value="">Disabled</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function NativeSelectInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<NativeSelect aria-invalid="true">
|
||||
<NativeSelectOption value="">Error state</NativeSelectOption>
|
||||
<NativeSelectOption value="apple">Apple</NativeSelectOption>
|
||||
<NativeSelectOption value="banana">Banana</NativeSelectOption>
|
||||
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
128
apps/v4/registry/bases/aria/examples/pagination-example.tsx
Normal file
128
apps/v4/registry/bases/aria/examples/pagination-example.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Field, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
Pagination,
|
||||
PaginationContent,
|
||||
PaginationEllipsis,
|
||||
PaginationItem,
|
||||
PaginationLink,
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from "@/registry/bases/aria/ui/pagination"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
|
||||
export default function PaginationExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<PaginationBasic />
|
||||
<PaginationSimple />
|
||||
<PaginationIconsOnly />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function PaginationBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationPrevious href="#" />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">1</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#" isActive>
|
||||
2
|
||||
</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">3</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationEllipsis />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationNext href="#" />
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PaginationSimple() {
|
||||
return (
|
||||
<Example title="Simple">
|
||||
<Pagination>
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">1</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#" isActive>
|
||||
2
|
||||
</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">3</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">4</PaginationLink>
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationLink href="#">5</PaginationLink>
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PaginationIconsOnly() {
|
||||
return (
|
||||
<Example title="With Select">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<Field orientation="horizontal" className="w-fit">
|
||||
<FieldLabel htmlFor="select-rows-per-page">Rows per page</FieldLabel>
|
||||
<Select defaultValue="25">
|
||||
<SelectTrigger className="w-20" id="select-rows-per-page">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent placement="bottom start">
|
||||
<SelectGroup>
|
||||
<SelectItem id="10">10</SelectItem>
|
||||
<SelectItem id="25">25</SelectItem>
|
||||
<SelectItem id="50">50</SelectItem>
|
||||
<SelectItem id="100">100</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Pagination className="mx-0 w-auto">
|
||||
<PaginationContent>
|
||||
<PaginationItem>
|
||||
<PaginationPrevious href="#" />
|
||||
</PaginationItem>
|
||||
<PaginationItem>
|
||||
<PaginationNext href="#" />
|
||||
</PaginationItem>
|
||||
</PaginationContent>
|
||||
</Pagination>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
187
apps/v4/registry/bases/aria/examples/popover-example.tsx
Normal file
187
apps/v4/registry/bases/aria/examples/popover-example.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
Popover,
|
||||
PopoverDescription,
|
||||
PopoverHeader,
|
||||
PopoverTitle,
|
||||
PopoverTrigger,
|
||||
} from "@/registry/bases/aria/ui/popover"
|
||||
|
||||
export default function PopoverExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<PopoverBasic />
|
||||
<PopoverSides />
|
||||
<PopoverWithForm />
|
||||
<PopoverAlignments />
|
||||
<PopoverInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<PopoverTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open Popover
|
||||
</Button>
|
||||
<Popover placement="bottom start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Dimensions</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
Set the dimensions for the layer.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverSides() {
|
||||
return (
|
||||
<Example title="Sides">
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{(["start", "left", "top"] as const).map((placement) => {
|
||||
return (
|
||||
<PopoverTrigger key={placement}>
|
||||
<Button variant="outline" className="w-fit capitalize">
|
||||
{placement}
|
||||
</Button>
|
||||
<Popover placement={placement} className="w-40">
|
||||
<p>Popover on {placement}</p>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{(["bottom", "right", "end"] as const).map((placement) => {
|
||||
return (
|
||||
<PopoverTrigger key={placement}>
|
||||
<Button variant="outline" className="w-fit capitalize">
|
||||
{placement}
|
||||
</Button>
|
||||
<Popover placement={placement} className="w-40">
|
||||
<p>Popover on {placement}</p>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverWithForm() {
|
||||
return (
|
||||
<Example title="With Form">
|
||||
<PopoverTrigger>
|
||||
<Button variant="outline">Open Popover</Button>
|
||||
<Popover className="w-64" placement="bottom start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Dimensions</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
Set the dimensions for the layer.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
<FieldGroup className="gap-4">
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="width" className="w-1/2">
|
||||
Width
|
||||
</FieldLabel>
|
||||
<Input id="width" defaultValue="100%" />
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<FieldLabel htmlFor="height" className="w-1/2">
|
||||
Height
|
||||
</FieldLabel>
|
||||
<Input id="height" defaultValue="25px" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverAlignments() {
|
||||
return (
|
||||
<Example title="Alignments">
|
||||
<div className="flex gap-6">
|
||||
<PopoverTrigger>
|
||||
<Button variant="outline" size="sm">
|
||||
Start
|
||||
</Button>
|
||||
<Popover placement="bottom start" className="w-40">
|
||||
Aligned to start
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
<PopoverTrigger>
|
||||
<Button variant="outline" size="sm">
|
||||
Center
|
||||
</Button>
|
||||
<Popover placement="bottom" className="w-40">
|
||||
Aligned to center
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
<PopoverTrigger>
|
||||
<Button variant="outline" size="sm">
|
||||
End
|
||||
</Button>
|
||||
<Popover placement="bottom end" className="w-40">
|
||||
Aligned to end
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverInDialog() {
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Popover Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Click the button below to see the popover.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<PopoverTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Open Popover
|
||||
</Button>
|
||||
<Popover placement="bottom start">
|
||||
<PopoverHeader>
|
||||
<PopoverTitle>Popover in Dialog</PopoverTitle>
|
||||
<PopoverDescription>
|
||||
This popover appears inside a dialog. Click the button to open
|
||||
it.
|
||||
</PopoverDescription>
|
||||
</PopoverHeader>
|
||||
</Popover>
|
||||
</PopoverTrigger>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
142
apps/v4/registry/bases/aria/examples/progress-example.tsx
Normal file
142
apps/v4/registry/bases/aria/examples/progress-example.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemGroup,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/aria/ui/item"
|
||||
import {
|
||||
Progress,
|
||||
ProgressLabel,
|
||||
ProgressValue,
|
||||
} from "@/registry/bases/aria/ui/progress"
|
||||
import { Slider } from "@/registry/bases/aria/ui/slider"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ProgressExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ProgressValues />
|
||||
<ProgressWithLabel />
|
||||
<ProgressControlled />
|
||||
<FileUploadList />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressValues() {
|
||||
return (
|
||||
<Example title="Progress Bar">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Progress value={0} />
|
||||
<Progress value={25} className="w-full" />
|
||||
<Progress value={50} />
|
||||
<Progress value={75} />
|
||||
<Progress value={100} />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<Progress value={56}>
|
||||
<ProgressLabel>Upload progress</ProgressLabel>
|
||||
<ProgressValue />
|
||||
</Progress>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ProgressControlled() {
|
||||
const [value, setValue] = React.useState(50)
|
||||
|
||||
return (
|
||||
<Example title="Controlled">
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<Progress value={value} className="w-full" />
|
||||
<Slider
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
minValue={0}
|
||||
maxValue={100}
|
||||
step={1}
|
||||
/>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function FileUploadList() {
|
||||
const files = React.useMemo(
|
||||
() => [
|
||||
{
|
||||
id: "1",
|
||||
name: "document.pdf",
|
||||
progress: 45,
|
||||
timeRemaining: "2m 30s",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "presentation.pptx",
|
||||
progress: 78,
|
||||
timeRemaining: "45s",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "spreadsheet.xlsx",
|
||||
progress: 12,
|
||||
timeRemaining: "5m 12s",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "image.jpg",
|
||||
progress: 100,
|
||||
timeRemaining: "Complete",
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<Example title="File Upload List">
|
||||
<ItemGroup>
|
||||
{files.map((file) => (
|
||||
<Item key={file.id} size="xs" className="px-0">
|
||||
<ItemMedia variant="icon">
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="FileIcon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
className="size-5"
|
||||
/>
|
||||
</ItemMedia>
|
||||
<ItemContent className="inline-block truncate">
|
||||
<ItemTitle className="inline">{file.name}</ItemTitle>
|
||||
</ItemContent>
|
||||
<ItemContent>
|
||||
<Progress value={file.progress} className="w-32" />
|
||||
</ItemContent>
|
||||
<ItemActions className="w-16 justify-end">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{file.timeRemaining}
|
||||
</span>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
))}
|
||||
</ItemGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
470
apps/v4/registry/bases/aria/examples/questionnaire-example.tsx
Normal file
470
apps/v4/registry/bases/aria/examples/questionnaire-example.tsx
Normal file
@@ -0,0 +1,470 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardAction,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import {
|
||||
Questionnaire,
|
||||
QuestionnaireActions,
|
||||
QuestionnaireChoice,
|
||||
QuestionnaireChoiceDescription,
|
||||
QuestionnaireChoices,
|
||||
QuestionnaireDescription,
|
||||
QuestionnaireError,
|
||||
QuestionnaireInput,
|
||||
QuestionnaireItem,
|
||||
QuestionnaireNext,
|
||||
QuestionnairePrevious,
|
||||
QuestionnaireProgress,
|
||||
QuestionnaireSkip,
|
||||
QuestionnaireSubmit,
|
||||
QuestionnaireTitle,
|
||||
} from "@/registry/bases/aria/ui/questionnaire"
|
||||
|
||||
const questionnaireItems = [
|
||||
{
|
||||
choices: [
|
||||
{ value: "delegation" },
|
||||
{ value: "questions" },
|
||||
{ value: "both" },
|
||||
],
|
||||
name: "direction",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
choices: [
|
||||
{ value: "progress" },
|
||||
{ value: "decisions" },
|
||||
{ value: "risks" },
|
||||
],
|
||||
name: "signals",
|
||||
},
|
||||
{
|
||||
choices: [{ value: "week" }, { value: "cycle" }, { value: "later" }],
|
||||
name: "timing",
|
||||
required: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
const taskItems = [
|
||||
{
|
||||
choices: [
|
||||
{ value: "inspect" },
|
||||
{ value: "implement" },
|
||||
{ value: "review" },
|
||||
],
|
||||
name: "task",
|
||||
required: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
const planItems = [
|
||||
{
|
||||
choices: [
|
||||
{ value: "plus" },
|
||||
{ value: "pro" },
|
||||
{ value: "enterprise", disabled: true },
|
||||
],
|
||||
name: "plan",
|
||||
required: true,
|
||||
},
|
||||
] as const
|
||||
|
||||
export default function QuestionnaireExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<QuestionnaireStandalone />
|
||||
<QuestionnaireCard />
|
||||
<QuestionnaireDialog />
|
||||
<QuestionnaireNoDescription />
|
||||
<QuestionnaireDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireDisabled() {
|
||||
return (
|
||||
<Example title="Disabled" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
className="mx-auto max-w-lg"
|
||||
defaultItem="plan"
|
||||
items={planItems}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireItem name="plan" required>
|
||||
<QuestionnaireTitle>Choose a plan</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Enterprise is not available on your account.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="plus">
|
||||
<span className="font-medium">Plus</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
For individuals and small teams
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="pro">
|
||||
<span className="font-medium">Pro</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
For growing businesses
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="enterprise" disabled>
|
||||
<span className="font-medium">Enterprise</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
For large teams and enterprises
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireNavigation />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireNoDescription() {
|
||||
return (
|
||||
<Example title="No description" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
className="mx-auto max-w-lg"
|
||||
defaultItem="task"
|
||||
items={taskItems}
|
||||
shortcuts="letters"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireProgress />
|
||||
<QuestionnaireItem name="task" required>
|
||||
<QuestionnaireTitle>
|
||||
What should the agent do next?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="inspect">
|
||||
Inspect the codebase
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="implement">
|
||||
Implement the change
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="review">
|
||||
Review the result
|
||||
</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireNavigation />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireStandalone() {
|
||||
return (
|
||||
<Example title="Standalone" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
className="mx-auto max-w-lg"
|
||||
defaultItem="direction"
|
||||
items={questionnaireItems}
|
||||
shortcuts="letters"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireProgress />
|
||||
<QuestionnaireQuestions />
|
||||
<QuestionnaireNavigation />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireCard() {
|
||||
return (
|
||||
<Example title="Card" containerClassName="md:col-span-2">
|
||||
<Questionnaire
|
||||
defaultItem="direction"
|
||||
items={questionnaireItems}
|
||||
shortcuts="numbers"
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<QuestionnaireCardQuestions />
|
||||
</Questionnaire>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireDialog() {
|
||||
return (
|
||||
<Example
|
||||
title="Dialog"
|
||||
className="items-center justify-center"
|
||||
containerClassName="md:col-span-2"
|
||||
>
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Open questionnaire</Button>
|
||||
<Dialog>
|
||||
<Questionnaire
|
||||
defaultItem="direction"
|
||||
items={questionnaireItems}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="sr-only">
|
||||
Plan an agent interface
|
||||
</DialogTitle>
|
||||
<DialogDescription className="sr-only">
|
||||
Answer three questions to shape the next prototype.
|
||||
</DialogDescription>
|
||||
<QuestionnaireProgress
|
||||
className="font-semibold tracking-widest text-foreground uppercase"
|
||||
render={(props, state) => (
|
||||
<span {...props}>
|
||||
Question {state.current} of {state.total}
|
||||
</span>
|
||||
)}
|
||||
/>
|
||||
</DialogHeader>
|
||||
<QuestionnaireQuestions />
|
||||
<DialogFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</DialogFooter>
|
||||
</Questionnaire>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireCardQuestions() {
|
||||
const directionTitleId = React.useId()
|
||||
const signalsTitleId = React.useId()
|
||||
const timingTitleId = React.useId()
|
||||
|
||||
return (
|
||||
<>
|
||||
<QuestionnaireItem
|
||||
aria-labelledby={directionTitleId}
|
||||
name="direction"
|
||||
required
|
||||
>
|
||||
<Card className="mx-auto w-full max-w-lg">
|
||||
<CardHeader>
|
||||
<QuestionnaireTitle id={directionTitleId} render={<CardTitle />}>
|
||||
What should we prototype next?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription render={<CardDescription />}>
|
||||
Choose one direction or write another answer.
|
||||
</QuestionnaireDescription>
|
||||
<CardAction>
|
||||
<QuestionnaireProgress />
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="delegation">
|
||||
<span className="font-medium">Sub-agent delegation</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show when work is delegated and what comes back.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="questions">
|
||||
<span className="font-medium">Question prompts</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show choices while the agent waits for input.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="both">
|
||||
<span className="font-medium">Both together</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Explore one unified interaction pattern.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireInput
|
||||
aria-label="Another direction"
|
||||
placeholder="Type another direction…"
|
||||
/>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem
|
||||
aria-labelledby={signalsTitleId}
|
||||
name="signals"
|
||||
multiple
|
||||
>
|
||||
<Card className="mx-auto w-full max-w-lg">
|
||||
<CardHeader>
|
||||
<QuestionnaireTitle id={signalsTitleId} render={<CardTitle />}>
|
||||
What should every progress update include?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription render={<CardDescription />}>
|
||||
Select all that apply, or skip this question.
|
||||
</QuestionnaireDescription>
|
||||
<CardAction>
|
||||
<QuestionnaireProgress />
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="progress">
|
||||
Progress
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="decisions">
|
||||
Decisions
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="risks">Risks</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem aria-labelledby={timingTitleId} name="timing" required>
|
||||
<Card className="mx-auto w-full max-w-lg">
|
||||
<CardHeader>
|
||||
<QuestionnaireTitle id={timingTitleId} render={<CardTitle />}>
|
||||
When should this be revisited?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription render={<CardDescription />}>
|
||||
Choose when this should be revisited.
|
||||
</QuestionnaireDescription>
|
||||
<CardAction>
|
||||
<QuestionnaireProgress />
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="week">This week</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="cycle">
|
||||
Next cycle
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="later">
|
||||
Revisit later
|
||||
</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<QuestionnaireNavigation />
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</QuestionnaireItem>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireQuestions() {
|
||||
return (
|
||||
<>
|
||||
<QuestionnaireItem name="direction" required>
|
||||
<QuestionnaireTitle>What should we prototype next?</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Choose one direction or write another answer.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="delegation">
|
||||
<span className="font-medium">Sub-agent delegation</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show when work is delegated and what comes back.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="questions">
|
||||
<span className="font-medium">Question prompts</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Show choices while the agent waits for input.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="both">
|
||||
<span className="font-medium">Both together</span>
|
||||
<QuestionnaireChoiceDescription>
|
||||
Explore one unified interaction pattern.
|
||||
</QuestionnaireChoiceDescription>
|
||||
</QuestionnaireChoice>
|
||||
<QuestionnaireInput
|
||||
aria-label="Another direction"
|
||||
placeholder="Type another direction…"
|
||||
/>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem name="signals" multiple>
|
||||
<QuestionnaireTitle>
|
||||
What should every progress update include?
|
||||
</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Select all that apply, or skip this question.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="progress">Progress</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="decisions">Decisions</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="risks">Risks</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
<QuestionnaireItem name="timing" required>
|
||||
<QuestionnaireTitle>When should this be revisited?</QuestionnaireTitle>
|
||||
<QuestionnaireDescription>
|
||||
Choose when this should be revisited.
|
||||
</QuestionnaireDescription>
|
||||
<QuestionnaireChoices>
|
||||
<QuestionnaireChoice value="week">This week</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="cycle">Next cycle</QuestionnaireChoice>
|
||||
<QuestionnaireChoice value="later">Revisit later</QuestionnaireChoice>
|
||||
</QuestionnaireChoices>
|
||||
<QuestionnaireError />
|
||||
</QuestionnaireItem>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function QuestionnaireNavigation() {
|
||||
return (
|
||||
<QuestionnaireActions className="w-full">
|
||||
<QuestionnairePrevious />
|
||||
<QuestionnaireSkip />
|
||||
<QuestionnaireNext>Next</QuestionnaireNext>
|
||||
<QuestionnaireSubmit>Save answers</QuestionnaireSubmit>
|
||||
</QuestionnaireActions>
|
||||
)
|
||||
}
|
||||
|
||||
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault()
|
||||
|
||||
const formData = new FormData(event.currentTarget)
|
||||
const values = {
|
||||
direction: formData.get("direction"),
|
||||
signals: formData.getAll("signals"),
|
||||
timing: formData.get("timing"),
|
||||
}
|
||||
|
||||
toast("Questionnaire submitted", {
|
||||
description: `Direction: ${values.direction ?? "None"} · Progress signals: ${values.signals.join(", ") || "None"} · Timing: ${values.timing ?? "None"}`,
|
||||
})
|
||||
}
|
||||
222
apps/v4/registry/bases/aria/examples/radio-group-example.tsx
Normal file
222
apps/v4/registry/bases/aria/examples/radio-group-example.tsx
Normal file
@@ -0,0 +1,222 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
FieldLegend,
|
||||
FieldSet,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
RadioGroup,
|
||||
RadioGroupItem,
|
||||
} from "@/registry/bases/aria/ui/radio-group"
|
||||
|
||||
export default function RadioGroupExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<RadioGroupBasic />
|
||||
<RadioGroupWithDescriptions />
|
||||
<RadioGroupWithFieldSet />
|
||||
<RadioGroupGrid />
|
||||
<RadioGroupDisabled />
|
||||
<RadioGroupInvalid />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<RadioGroup defaultValue="comfortable">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="default" id="r1" />
|
||||
<FieldLabel htmlFor="r1" className="font-normal">
|
||||
Default
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="comfortable" id="r2" />
|
||||
<FieldLabel htmlFor="r2" className="font-normal">
|
||||
Comfortable
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="compact" id="r3" />
|
||||
<FieldLabel htmlFor="r3" className="font-normal">
|
||||
Compact
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupWithDescriptions() {
|
||||
return (
|
||||
<Example title="With Descriptions">
|
||||
<RadioGroup defaultValue="plus">
|
||||
<FieldLabel htmlFor="plus-plan">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<div className="font-medium">Plus</div>
|
||||
<FieldDescription>
|
||||
For individuals and small teams
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<RadioGroupItem value="plus" id="plus-plan" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="pro-plan">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<div className="font-medium">Pro</div>
|
||||
<FieldDescription>For growing businesses</FieldDescription>
|
||||
</FieldContent>
|
||||
<RadioGroupItem value="pro" id="pro-plan" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="enterprise-plan">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<div className="font-medium">Enterprise</div>
|
||||
<FieldDescription>
|
||||
For large teams and enterprises
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<RadioGroupItem value="enterprise" id="enterprise-plan" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupWithFieldSet() {
|
||||
return (
|
||||
<Example title="With FieldSet">
|
||||
<FieldSet>
|
||||
<FieldLegend>Battery Level</FieldLegend>
|
||||
<FieldDescription>
|
||||
Choose your preferred battery level.
|
||||
</FieldDescription>
|
||||
<RadioGroup defaultValue="medium">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="high" id="battery-high" />
|
||||
<FieldLabel htmlFor="battery-high" className="font-normal">
|
||||
High
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="medium" id="battery-medium" />
|
||||
<FieldLabel htmlFor="battery-medium" className="font-normal">
|
||||
Medium
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="low" id="battery-low" />
|
||||
<FieldLabel htmlFor="battery-low" className="font-normal">
|
||||
Low
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupGrid() {
|
||||
return (
|
||||
<Example title="Grid Layout">
|
||||
<RadioGroup defaultValue="medium" className="grid grid-cols-2 gap-2">
|
||||
<FieldLabel htmlFor="size-small">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="small" id="size-small" />
|
||||
<div className="font-medium">Small</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="size-medium">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="medium" id="size-medium" />
|
||||
<div className="font-medium">Medium</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="size-large">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="large" id="size-large" />
|
||||
<div className="font-medium">Large</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
<FieldLabel htmlFor="size-xlarge">
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="xlarge" id="size-xlarge" />
|
||||
<div className="font-medium">X-Large</div>
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<RadioGroup defaultValue="option2" isDisabled>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option1" id="disabled-1" />
|
||||
<FieldLabel htmlFor="disabled-1" className="font-normal">
|
||||
Option 1
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option2" id="disabled-2" />
|
||||
<FieldLabel htmlFor="disabled-2" className="font-normal">
|
||||
Option 2
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal">
|
||||
<RadioGroupItem value="option3" id="disabled-3" />
|
||||
<FieldLabel htmlFor="disabled-3" className="font-normal">
|
||||
Option 3
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function RadioGroupInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<FieldSet>
|
||||
<FieldLegend>Notification Preferences</FieldLegend>
|
||||
<FieldDescription>
|
||||
Choose how you want to receive notifications.
|
||||
</FieldDescription>
|
||||
<RadioGroup defaultValue="email" isInvalid>
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<RadioGroupItem value="email" id="invalid-email" />
|
||||
<FieldLabel htmlFor="invalid-email" className="font-normal">
|
||||
Email only
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<RadioGroupItem value="sms" id="invalid-sms" />
|
||||
<FieldLabel htmlFor="invalid-sms" className="font-normal">
|
||||
SMS only
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
<Field orientation="horizontal" data-invalid>
|
||||
<RadioGroupItem value="both" id="invalid-both" />
|
||||
<FieldLabel htmlFor="invalid-both" className="font-normal">
|
||||
Both Email & SMS
|
||||
</FieldLabel>
|
||||
</Field>
|
||||
</RadioGroup>
|
||||
</FieldSet>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
158
apps/v4/registry/bases/aria/examples/resizable-example.tsx
Normal file
158
apps/v4/registry/bases/aria/examples/resizable-example.tsx
Normal file
@@ -0,0 +1,158 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type { Layout } from "react-resizable-panels"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
ResizableHandle,
|
||||
ResizablePanel,
|
||||
ResizablePanelGroup,
|
||||
} from "@/registry/bases/aria/ui/resizable"
|
||||
|
||||
export default function ResizableExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ResizableHorizontal />
|
||||
<ResizableVertical />
|
||||
<ResizableWithHandle />
|
||||
<ResizableNested />
|
||||
<ResizableControlled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableHorizontal() {
|
||||
return (
|
||||
<Example title="Horizontal">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="min-h-[200px] rounded-lg border"
|
||||
>
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Sidebar</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Content</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<ResizablePanelGroup
|
||||
orientation="vertical"
|
||||
className="min-h-[200px] rounded-lg border"
|
||||
>
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Header</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Content</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableWithHandle() {
|
||||
return (
|
||||
<Example title="With Handle">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="min-h-[200px] rounded-lg border"
|
||||
>
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Sidebar</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle withHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Content</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableNested() {
|
||||
return (
|
||||
<Example title="Nested">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="rounded-lg border"
|
||||
>
|
||||
<ResizablePanel defaultSize="50%">
|
||||
<div className="flex h-[200px] items-center justify-center p-6">
|
||||
<span className="font-semibold">One</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="50%">
|
||||
<ResizablePanelGroup orientation="vertical">
|
||||
<ResizablePanel defaultSize="25%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Two</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="75%">
|
||||
<div className="flex h-full items-center justify-center p-6">
|
||||
<span className="font-semibold">Three</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ResizableControlled() {
|
||||
const [layout, setLayout] = React.useState<Layout>({})
|
||||
|
||||
return (
|
||||
<Example title="Controlled">
|
||||
<ResizablePanelGroup
|
||||
orientation="horizontal"
|
||||
className="min-h-[200px] rounded-lg border"
|
||||
onLayoutChange={setLayout}
|
||||
>
|
||||
<ResizablePanel defaultSize="30%" id="left" minSize="20%">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2 p-6">
|
||||
<span className="font-semibold">
|
||||
{Math.round(layout.left ?? 30)}%
|
||||
</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
<ResizableHandle />
|
||||
<ResizablePanel defaultSize="70%" id="right" minSize="30%">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2 p-6">
|
||||
<span className="font-semibold">
|
||||
{Math.round(layout.right ?? 70)}%
|
||||
</span>
|
||||
</div>
|
||||
</ResizablePanel>
|
||||
</ResizablePanelGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
85
apps/v4/registry/bases/aria/examples/scroll-area-example.tsx
Normal file
85
apps/v4/registry/bases/aria/examples/scroll-area-example.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import * as React from "react"
|
||||
import Image from "next/image"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { ScrollArea } from "@/registry/bases/aria/ui/scroll-area"
|
||||
import { Separator } from "@/registry/bases/aria/ui/separator"
|
||||
|
||||
const tags = Array.from({ length: 50 }).map(
|
||||
(_, i, a) => `v1.2.0-beta.${a.length - i}`
|
||||
)
|
||||
|
||||
const works = [
|
||||
{
|
||||
artist: "Ornella Binni",
|
||||
art: "https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80",
|
||||
},
|
||||
{
|
||||
artist: "Tom Byrom",
|
||||
art: "https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80",
|
||||
},
|
||||
{
|
||||
artist: "Vladimir Malyav",
|
||||
art: "https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80",
|
||||
},
|
||||
] as const
|
||||
|
||||
export default function ScrollAreaExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ScrollAreaVertical />
|
||||
<ScrollAreaHorizontal />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ScrollAreaVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<ScrollArea className="mx-auto h-72 w-48 rounded-md border style-luma:rounded-2xl style-rhea:rounded-2xl">
|
||||
<div className="p-4">
|
||||
<h4 className="mb-4 text-sm leading-none font-medium">Tags</h4>
|
||||
{tags.map((tag) => (
|
||||
<React.Fragment key={tag}>
|
||||
<div className="text-sm">{tag}</div>
|
||||
<Separator className="my-2" />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ScrollAreaHorizontal() {
|
||||
return (
|
||||
<Example title="Horizontal">
|
||||
<ScrollArea className="mx-auto w-full max-w-96 rounded-md border p-4 style-luma:rounded-2xl style-rhea:rounded-2xl">
|
||||
<div className="flex gap-4">
|
||||
{works.map((artwork) => (
|
||||
<figure key={artwork.artist} className="shrink-0">
|
||||
<div className="overflow-hidden rounded-md">
|
||||
<Image
|
||||
src={artwork.art}
|
||||
alt={`Photo by ${artwork.artist}`}
|
||||
className="aspect-[3/4] h-fit w-fit object-cover"
|
||||
width={300}
|
||||
height={400}
|
||||
/>
|
||||
</div>
|
||||
<figcaption className="pt-2 text-xs text-muted-foreground">
|
||||
Photo by{" "}
|
||||
<span className="font-semibold text-foreground">
|
||||
{artwork.artist}
|
||||
</span>
|
||||
</figcaption>
|
||||
</figure>
|
||||
))}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
793
apps/v4/registry/bases/aria/examples/select-example.tsx
Normal file
793
apps/v4/registry/bases/aria/examples/select-example.tsx
Normal file
@@ -0,0 +1,793 @@
|
||||
"use client"
|
||||
|
||||
import { Autocomplete, useFilter } from "react-aria-components"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/registry/bases/aria/ui/dialog"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldError,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/aria/ui/item"
|
||||
import {
|
||||
NativeSelect,
|
||||
NativeSelectOption,
|
||||
} from "@/registry/bases/aria/ui/native-select"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectEmpty,
|
||||
SelectGroup,
|
||||
SelectInput,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectList,
|
||||
SelectPopover,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SelectExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SelectBasic />
|
||||
<SelectAutocomplete />
|
||||
<SelectSides />
|
||||
<SelectWithIcons />
|
||||
<SelectWithGroups />
|
||||
<SelectLargeList />
|
||||
<SelectMultiple />
|
||||
<SelectSizes />
|
||||
<SelectPlan />
|
||||
<SelectWithButton />
|
||||
<SelectItemAligned />
|
||||
<SelectWithField />
|
||||
<SelectInvalid />
|
||||
<SelectInline />
|
||||
<SelectDisabled />
|
||||
<SelectInDialog />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectBasic() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
{ label: "Grapes", value: "grapes" },
|
||||
{ label: "Pineapple", value: "pineapple" },
|
||||
]
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSides() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
]
|
||||
return (
|
||||
<Example title="Sides" containerClassName="col-span-2">
|
||||
<div className="flex flex-wrap justify-center gap-2">
|
||||
{(["start", "left", "top", "bottom", "right", "end"] as const).map(
|
||||
(placement) => (
|
||||
<Select key={placement} aria-label="Fruits" placeholder="Select">
|
||||
<SelectTrigger className="w-28 capitalize">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent placement={placement}>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithIcons() {
|
||||
const items = [
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Line
|
||||
</>
|
||||
),
|
||||
value: "line",
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
<IconPlaceholder
|
||||
lucide="ChartBarIcon"
|
||||
tabler="IconChartBar"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartBarIcon"
|
||||
remixicon="RiBarChartLine"
|
||||
/>
|
||||
Bar
|
||||
</>
|
||||
),
|
||||
value: "bar",
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<>
|
||||
<IconPlaceholder
|
||||
lucide="ChartPieIcon"
|
||||
tabler="IconChartPie"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartPieIcon"
|
||||
remixicon="RiPieChartLine"
|
||||
/>
|
||||
Pie
|
||||
</>
|
||||
),
|
||||
value: "pie",
|
||||
},
|
||||
]
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Select aria-label="Chart Type">
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue>
|
||||
{({ isPlaceholder, defaultChildren }) =>
|
||||
isPlaceholder ? (
|
||||
<>
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Chart Type
|
||||
</>
|
||||
) : (
|
||||
defaultChildren
|
||||
)
|
||||
}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select aria-label="Chart Type">
|
||||
<SelectTrigger size="default">
|
||||
<SelectValue>
|
||||
{({ isPlaceholder, defaultChildren }) =>
|
||||
isPlaceholder ? (
|
||||
<>
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="Chart03Icon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Chart Type
|
||||
</>
|
||||
) : (
|
||||
defaultChildren
|
||||
)
|
||||
}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithGroups() {
|
||||
const fruits = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
]
|
||||
const vegetables = [
|
||||
{ label: "Carrot", value: "carrot" },
|
||||
{ label: "Broccoli", value: "broccoli" },
|
||||
{ label: "Spinach", value: "spinach" },
|
||||
]
|
||||
return (
|
||||
<Example title="With Groups & Labels">
|
||||
<Select aria-label="Fruits and Vegetables">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectLabel>Fruits</SelectLabel>
|
||||
{fruits.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
<SelectSeparator />
|
||||
<SelectGroup>
|
||||
<SelectLabel>Vegetables</SelectLabel>
|
||||
{vegetables.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLargeList() {
|
||||
const items = Array.from({ length: 100 }).map((_, i) => ({
|
||||
label: `Item ${i}`,
|
||||
value: `item-${i}`,
|
||||
}))
|
||||
return (
|
||||
<Example title="Large List">
|
||||
<Select aria-label="Items">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSizes() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
]
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit">
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select aria-label="Fruits">
|
||||
<SelectTrigger size="default">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithButton() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
]
|
||||
return (
|
||||
<Example title="With Button">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit">
|
||||
<SelectTrigger size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm">
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Select aria-label="Fruits">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline">Submit</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItemAligned() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
{ label: "Grapes", value: "grapes", disabled: true },
|
||||
{ label: "Pineapple", value: "pineapple" },
|
||||
]
|
||||
return (
|
||||
<Example title="Item Aligned">
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem
|
||||
key={item.value}
|
||||
id={item.value}
|
||||
isDisabled={item.disabled}
|
||||
>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectWithField() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
{ label: "Grapes", value: "grapes" },
|
||||
{ label: "Pineapple", value: "pineapple" },
|
||||
]
|
||||
return (
|
||||
<Example title="With Field">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="select-fruit">Favorite Fruit</FieldLabel>
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit">
|
||||
<SelectTrigger id="select-fruit">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldDescription>
|
||||
Choose your favorite fruit from the list.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectInvalid() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
{ label: "Grapes", value: "grapes" },
|
||||
{ label: "Pineapple", value: "pineapple" },
|
||||
]
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<div className="flex flex-col gap-4">
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit" isInvalid>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Field data-invalid>
|
||||
<FieldLabel htmlFor="select-fruit-invalid">Favorite Fruit</FieldLabel>
|
||||
<Select aria-label="Fruits" isInvalid>
|
||||
<SelectTrigger id="select-fruit-invalid">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FieldError errors={[{ message: "Please select a valid fruit." }]} />
|
||||
</Field>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectInline() {
|
||||
const items = [
|
||||
{ label: "All", value: "all" },
|
||||
{ label: "Active", value: "active" },
|
||||
{ label: "Inactive", value: "inactive" },
|
||||
]
|
||||
return (
|
||||
<Example title="Inline with Input & NativeSelect">
|
||||
<div className="flex items-center gap-2">
|
||||
<Input placeholder="Search..." className="flex-1" />
|
||||
<Select aria-label="Filter" placeholder="Filter">
|
||||
<SelectTrigger className="w-[140px]">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<NativeSelect className="w-[140px]">
|
||||
<NativeSelectOption value="">Sort by</NativeSelectOption>
|
||||
<NativeSelectOption value="name">Name</NativeSelectOption>
|
||||
<NativeSelectOption value="date">Date</NativeSelectOption>
|
||||
<NativeSelectOption value="status">Status</NativeSelectOption>
|
||||
</NativeSelect>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectDisabled() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
{ label: "Grapes", value: "grapes", disabled: true },
|
||||
{ label: "Pineapple", value: "pineapple" },
|
||||
]
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit" isDisabled>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem
|
||||
key={item.value}
|
||||
id={item.value}
|
||||
isDisabled={item.disabled}
|
||||
>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const plans = [
|
||||
{
|
||||
name: "Starter",
|
||||
description: "Perfect for individuals getting started.",
|
||||
},
|
||||
{
|
||||
name: "Professional",
|
||||
description: "Ideal for growing teams and businesses.",
|
||||
},
|
||||
{
|
||||
name: "Enterprise",
|
||||
description: "Advanced features for large organizations.",
|
||||
},
|
||||
]
|
||||
|
||||
function SelectPlan() {
|
||||
return (
|
||||
<Example title="Subscription Plan">
|
||||
<Select aria-label="Subscription Plan" defaultValue={plans[0].name}>
|
||||
<SelectTrigger className="h-auto! w-72">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{plans.map((plan) => (
|
||||
<SelectItem key={plan.name} id={plan.name} textValue={plan.name}>
|
||||
<SelectPlanItem plan={plan} />
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectPlanItem({ plan }: { plan: (typeof plans)[number] }) {
|
||||
return (
|
||||
<Item size="xs" className="w-full p-0">
|
||||
<ItemContent className="gap-0 normal-case">
|
||||
<ItemTitle className="font-sans">{plan.name}</ItemTitle>
|
||||
<ItemDescription className="text-xs font-normal tracking-normal">
|
||||
{plan.description}
|
||||
</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectMultiple() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
{ label: "Grapes", value: "grapes" },
|
||||
{ label: "Pineapple", value: "pineapple" },
|
||||
{ label: "Strawberry", value: "strawberry" },
|
||||
{ label: "Watermelon", value: "watermelon" },
|
||||
]
|
||||
|
||||
return (
|
||||
<Example title="Multiple Selection">
|
||||
<Select selectionMode="multiple" aria-label="Fruits">
|
||||
<SelectTrigger className="w-72">
|
||||
<SelectValue<(typeof items)[0]>>
|
||||
{({ selectedItems }) =>
|
||||
selectedItems.length === 0
|
||||
? "Select fruits"
|
||||
: selectedItems.length === 1
|
||||
? (selectedItems[0]?.label ?? "")
|
||||
: `${selectedItems.length} fruits selected`
|
||||
}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup items={items}>
|
||||
{(item) => <SelectItem id={item.value}>{item.label}</SelectItem>}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectInDialog() {
|
||||
const items = [
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
{ label: "Blueberry", value: "blueberry" },
|
||||
{ label: "Grapes", value: "grapes" },
|
||||
{ label: "Pineapple", value: "pineapple" },
|
||||
]
|
||||
return (
|
||||
<Example title="In Dialog">
|
||||
<DialogTrigger>
|
||||
<Button variant="outline">Open Dialog</Button>
|
||||
<Dialog>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Select Example</DialogTitle>
|
||||
<DialogDescription>
|
||||
Use the select below to choose a fruit.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Select aria-label="Fruits" placeholder="Select a fruit">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Dialog>
|
||||
</DialogTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const countries = [
|
||||
{
|
||||
code: "ar",
|
||||
value: "argentina",
|
||||
label: "Argentina",
|
||||
continent: "South America",
|
||||
},
|
||||
{ code: "au", value: "australia", label: "Australia", continent: "Oceania" },
|
||||
{ code: "br", value: "brazil", label: "Brazil", continent: "South America" },
|
||||
{ code: "ca", value: "canada", label: "Canada", continent: "North America" },
|
||||
{ code: "cn", value: "china", label: "China", continent: "Asia" },
|
||||
{
|
||||
code: "co",
|
||||
value: "colombia",
|
||||
label: "Colombia",
|
||||
continent: "South America",
|
||||
},
|
||||
{ code: "eg", value: "egypt", label: "Egypt", continent: "Africa" },
|
||||
{ code: "fr", value: "france", label: "France", continent: "Europe" },
|
||||
{ code: "de", value: "germany", label: "Germany", continent: "Europe" },
|
||||
{ code: "it", value: "italy", label: "Italy", continent: "Europe" },
|
||||
{ code: "jp", value: "japan", label: "Japan", continent: "Asia" },
|
||||
{ code: "ke", value: "kenya", label: "Kenya", continent: "Africa" },
|
||||
{ code: "mx", value: "mexico", label: "Mexico", continent: "North America" },
|
||||
{
|
||||
code: "nz",
|
||||
value: "new-zealand",
|
||||
label: "New Zealand",
|
||||
continent: "Oceania",
|
||||
},
|
||||
{ code: "ng", value: "nigeria", label: "Nigeria", continent: "Africa" },
|
||||
{
|
||||
code: "za",
|
||||
value: "south-africa",
|
||||
label: "South Africa",
|
||||
continent: "Africa",
|
||||
},
|
||||
{ code: "kr", value: "south-korea", label: "South Korea", continent: "Asia" },
|
||||
{
|
||||
code: "gb",
|
||||
value: "united-kingdom",
|
||||
label: "United Kingdom",
|
||||
continent: "Europe",
|
||||
},
|
||||
{
|
||||
code: "us",
|
||||
value: "united-states",
|
||||
label: "United States",
|
||||
continent: "North America",
|
||||
},
|
||||
]
|
||||
|
||||
function SelectAutocomplete() {
|
||||
const { contains } = useFilter({ sensitivity: "base" })
|
||||
|
||||
return (
|
||||
<Example title="With Autocomplete">
|
||||
<Select placeholder="Select country">
|
||||
<SelectTrigger className="w-full max-w-48">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<Autocomplete filter={contains}>
|
||||
<SelectPopover>
|
||||
<SelectInput />
|
||||
<SelectList
|
||||
renderEmptyState={() => (
|
||||
<SelectEmpty>No items found.</SelectEmpty>
|
||||
)}
|
||||
>
|
||||
<SelectGroup items={countries}>
|
||||
{(item) => (
|
||||
<SelectItem id={item.value}>{item.label}</SelectItem>
|
||||
)}
|
||||
</SelectGroup>
|
||||
</SelectList>
|
||||
</SelectPopover>
|
||||
</Autocomplete>
|
||||
</Select>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
100
apps/v4/registry/bases/aria/examples/separator-example.tsx
Normal file
100
apps/v4/registry/bases/aria/examples/separator-example.tsx
Normal file
@@ -0,0 +1,100 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Separator } from "@/registry/bases/aria/ui/separator"
|
||||
|
||||
export default function SeparatorExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SeparatorHorizontal />
|
||||
<SeparatorVertical />
|
||||
<SeparatorVerticalMenu />
|
||||
<SeparatorInList />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorHorizontal() {
|
||||
return (
|
||||
<Example title="Horizontal">
|
||||
<div className="flex flex-col gap-4 text-sm style-lyra:text-xs/relaxed">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="leading-none font-medium">shadcn/ui</div>
|
||||
<div className="text-muted-foreground">
|
||||
The Foundation for your Design System
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div>
|
||||
A set of beautifully designed components that you can customize,
|
||||
extend, and build on.
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<div className="flex h-5 items-center gap-4 text-sm style-lyra:text-xs/relaxed">
|
||||
<div>Blog</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div>Docs</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div>Source</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorVerticalMenu() {
|
||||
return (
|
||||
<Example title="Vertical Menu">
|
||||
<div className="flex items-center gap-2 text-sm md:gap-4 style-lyra:text-xs/relaxed">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="font-medium">Settings</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Manage preferences
|
||||
</span>
|
||||
</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="font-medium">Account</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Profile & security
|
||||
</span>
|
||||
</div>
|
||||
<Separator orientation="vertical" />
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="font-medium">Help</span>
|
||||
<span className="text-xs text-muted-foreground">Support & docs</span>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SeparatorInList() {
|
||||
return (
|
||||
<Example title="In List">
|
||||
<div className="flex flex-col gap-2 text-sm style-lyra:text-xs/relaxed">
|
||||
<dl className="flex items-center justify-between">
|
||||
<dt>Item 1</dt>
|
||||
<dd className="text-muted-foreground">Value 1</dd>
|
||||
</dl>
|
||||
<Separator />
|
||||
<dl className="flex items-center justify-between">
|
||||
<dt>Item 2</dt>
|
||||
<dd className="text-muted-foreground">Value 2</dd>
|
||||
</dl>
|
||||
<Separator />
|
||||
<dl className="flex items-center justify-between">
|
||||
<dt>Item 3</dt>
|
||||
<dd className="text-muted-foreground">Value 3</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
131
apps/v4/registry/bases/aria/examples/sheet-example.tsx
Normal file
131
apps/v4/registry/bases/aria/examples/sheet-example.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { Field, FieldGroup, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
Sheet,
|
||||
SheetClose,
|
||||
SheetDescription,
|
||||
SheetFooter,
|
||||
SheetHeader,
|
||||
SheetTitle,
|
||||
SheetTrigger,
|
||||
} from "@/registry/bases/aria/ui/sheet"
|
||||
|
||||
export default function SheetExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SheetWithForm />
|
||||
<SheetNoCloseButton />
|
||||
<SheetWithSides />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SheetWithForm() {
|
||||
return (
|
||||
<Example title="With Form">
|
||||
<SheetTrigger>
|
||||
<Button variant="outline">Open</Button>
|
||||
<Sheet>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Edit profile</SheetTitle>
|
||||
<SheetDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="style-vega:px-4 style-nova:px-4 style-lyra:px-4 style-maia:px-6 style-mira:px-6 style-luma:px-6 style-rhea:px-6">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="sheet-demo-name">Name</FieldLabel>
|
||||
<Input id="sheet-demo-name" defaultValue="Pedro Duarte" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="sheet-demo-username">Username</FieldLabel>
|
||||
<Input id="sheet-demo-username" defaultValue="@peduarte" />
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<Button type="submit">Save changes</Button>
|
||||
<SheetClose variant="outline">Close</SheetClose>
|
||||
</SheetFooter>
|
||||
</Sheet>
|
||||
</SheetTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SheetNoCloseButton() {
|
||||
return (
|
||||
<Example title="No Close Button">
|
||||
<SheetTrigger>
|
||||
<Button variant="outline">No Close Button</Button>
|
||||
<Sheet showCloseButton={false}>
|
||||
<SheetHeader>
|
||||
<SheetTitle>No Close Button</SheetTitle>
|
||||
<SheetDescription>
|
||||
This sheet doesn't have a close button in the top-right
|
||||
corner. You can only close it using the button below.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
</Sheet>
|
||||
</SheetTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const SHEET_SIDES = ["top", "right", "bottom", "left"] as const
|
||||
|
||||
function SheetWithSides() {
|
||||
return (
|
||||
<Example title="Sides">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{SHEET_SIDES.map((side) => (
|
||||
<SheetTrigger key={side}>
|
||||
<Button variant="outline" className="capitalize">
|
||||
{side}
|
||||
</Button>
|
||||
<Sheet
|
||||
side={side}
|
||||
className="data-[side=bottom]:max-h-[50vh] data-[side=top]:max-h-[50vh]"
|
||||
>
|
||||
<SheetHeader>
|
||||
<SheetTitle>Edit profile</SheetTitle>
|
||||
<SheetDescription>
|
||||
Make changes to your profile here. Click save when you're
|
||||
done.
|
||||
</SheetDescription>
|
||||
</SheetHeader>
|
||||
<div className="no-scrollbar overflow-y-auto style-vega:px-4 style-nova:px-4 style-lyra:px-4 style-maia:px-6 style-mira:px-6 style-luma:px-6 style-rhea:px-6">
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<p
|
||||
key={index}
|
||||
className="mb-4 leading-normal style-lyra:mb-2 style-lyra:leading-relaxed"
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
|
||||
do eiusmod tempor incididunt ut labore et dolore magna
|
||||
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
||||
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit
|
||||
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia
|
||||
deserunt mollit anim id est laborum.
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
<SheetFooter>
|
||||
<Button type="submit">Save changes</Button>
|
||||
<SheetClose variant="outline">Cancel</SheetClose>
|
||||
</SheetFooter>
|
||||
</Sheet>
|
||||
</SheetTrigger>
|
||||
))}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
281
apps/v4/registry/bases/aria/examples/sidebar-example.tsx
Normal file
281
apps/v4/registry/bases/aria/examples/sidebar-example.tsx
Normal file
@@ -0,0 +1,281 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import {
|
||||
Item,
|
||||
ItemActions,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/aria/ui/item"
|
||||
import { Label } from "@/registry/bases/aria/ui/label"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarInput,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/aria/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarExample() {
|
||||
const data = {
|
||||
versions: ["1.0.1", "1.1.0-alpha", "2.0.0-beta1"],
|
||||
navMain: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Installation",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Project Structure",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Build Your Application",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Routing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Data Fetching",
|
||||
url: "#",
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: "Rendering",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Caching",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Styling",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Optimizing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Configuring",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Testing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Authentication",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Deploying",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Upgrading",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Examples",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "API Reference",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Components",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "File Conventions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Functions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "next.config.js Options",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "CLI",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Edge Runtime",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Architecture",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Accessibility",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Fast Refresh",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Next.js Compiler",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Supported Browsers",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Turbopack",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const [selectedVersion, setSelectedVersion] = React.useState(data.versions[0])
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar>
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenuTrigger>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
className="aria-expanded:bg-sidebar-accent aria-expanded:text-sidebar-accent-foreground"
|
||||
>
|
||||
<Item className="p-0" size="xs">
|
||||
<ItemContent>
|
||||
<ItemTitle className="text-sm">Documentation</ItemTitle>
|
||||
<ItemDescription>v{selectedVersion}</ItemDescription>
|
||||
</ItemContent>
|
||||
<ItemActions>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</ItemActions>
|
||||
</Item>
|
||||
</SidebarMenuButton>
|
||||
<DropdownMenu>
|
||||
{data.versions.map((version) => (
|
||||
<DropdownMenuItem
|
||||
key={version}
|
||||
onAction={() => setSelectedVersion(version)}
|
||||
>
|
||||
v{version}{" "}
|
||||
{version === selectedVersion && (
|
||||
<IconPlaceholder
|
||||
lucide="CheckIcon"
|
||||
tabler="IconCheck"
|
||||
hugeicons="Tick02Icon"
|
||||
phosphor="CheckIcon"
|
||||
remixicon="RiCheckLine"
|
||||
className="ml-auto"
|
||||
/>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
<form>
|
||||
<SidebarGroup className="py-0">
|
||||
<SidebarGroupContent className="relative">
|
||||
<Label htmlFor="search" className="sr-only">
|
||||
Search
|
||||
</Label>
|
||||
<SidebarInput
|
||||
id="search"
|
||||
placeholder="Search the docs..."
|
||||
className="pl-8"
|
||||
/>
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
className="pointer-events-none absolute top-1/2 left-2 size-4 -translate-y-1/2 opacity-50 select-none"
|
||||
/>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</form>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
{data.navMain.map((item) => (
|
||||
<SidebarGroup key={item.title}>
|
||||
<SidebarGroupLabel>{item.title}</SidebarGroupLabel>
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{item.items.map((subItem) => (
|
||||
<SidebarMenuItem key={subItem.title}>
|
||||
<SidebarMenuButton
|
||||
href={subItem.url}
|
||||
isActive={subItem.isActive}
|
||||
>
|
||||
{subItem.title}
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
))}
|
||||
</SidebarContent>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
"use client"
|
||||
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/registry/bases/aria/ui/card"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import { Field } from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/aria/ui/item"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarHeader,
|
||||
SidebarInput,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/aria/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarFloatingExample() {
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Installation",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Project Structure",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Build Your Application",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Routing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Data Fetching",
|
||||
url: "#",
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
title: "Rendering",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Caching",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Styling",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Optimizing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Configuring",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Testing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Authentication",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Deploying",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Upgrading",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Examples",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "API Reference",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Components",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "File Conventions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Functions",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "next.config.js Options",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "CLI",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Edge Runtime",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Architecture",
|
||||
url: "#",
|
||||
items: [
|
||||
{
|
||||
title: "Accessibility",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Fast Refresh",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Next.js Compiler",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Supported Browsers",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Turbopack",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarProvider className="bg-background">
|
||||
<Sidebar variant="floating">
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton href="#" size="lg">
|
||||
<Item className="p-0" size="xs">
|
||||
<ItemContent>
|
||||
<ItemTitle className="text-sm">Documentation</ItemTitle>
|
||||
<ItemDescription>v1.0.0</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarMenu>
|
||||
{data.navMain.map((item) => (
|
||||
<SidebarMenuItem key={item.title}>
|
||||
<DropdownMenuTrigger>
|
||||
<SidebarMenuButton className="aria-expanded:bg-sidebar-accent aria-expanded:text-sidebar-accent-foreground">
|
||||
{item.title}{" "}
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
className="ml-auto"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
{item.items?.length ? (
|
||||
<DropdownMenu placement="right top">
|
||||
<DropdownMenuGroup>
|
||||
{item.items.map((subItem) => (
|
||||
<DropdownMenuItem
|
||||
href={subItem.url}
|
||||
key={subItem.title}
|
||||
>
|
||||
{subItem.title}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
) : null}
|
||||
</DropdownMenuTrigger>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
<SidebarGroup>
|
||||
<Card size="sm" className="-mx-2">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm">
|
||||
Subscribe to our newsletter
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Opt-in to receive updates and news about the sidebar.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form>
|
||||
<Field>
|
||||
<SidebarInput type="email" placeholder="Email" />
|
||||
<Button
|
||||
className="w-full bg-sidebar-primary text-sidebar-primary-foreground"
|
||||
size="sm"
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
</Field>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</SidebarGroup>
|
||||
</SidebarFooter>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
449
apps/v4/registry/bases/aria/examples/sidebar-icon-example.tsx
Normal file
449
apps/v4/registry/bases/aria/examples/sidebar-icon-example.tsx
Normal file
@@ -0,0 +1,449 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from "@/registry/bases/aria/ui/avatar"
|
||||
import { buttonVariants } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/registry/bases/aria/ui/collapsible"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import {
|
||||
Item,
|
||||
ItemContent,
|
||||
ItemDescription,
|
||||
ItemMedia,
|
||||
ItemTitle,
|
||||
} from "@/registry/bases/aria/ui/item"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarGroup,
|
||||
SidebarGroupLabel,
|
||||
SidebarHeader,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/aria/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarIconExample() {
|
||||
const data = {
|
||||
user: {
|
||||
name: "shadcn",
|
||||
email: "m@example.com",
|
||||
avatar: "/avatars/shadcn.jpg",
|
||||
},
|
||||
teams: [
|
||||
{
|
||||
name: "Acme Inc",
|
||||
plan: "Enterprise",
|
||||
},
|
||||
{
|
||||
name: "Acme Corp.",
|
||||
plan: "Startup",
|
||||
},
|
||||
{
|
||||
name: "Evil Corp.",
|
||||
plan: "Free",
|
||||
},
|
||||
],
|
||||
navMain: [
|
||||
{
|
||||
title: "Playground",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="TerminalSquareIcon"
|
||||
tabler="IconTerminal2"
|
||||
hugeicons="ComputerTerminalIcon"
|
||||
phosphor="TerminalIcon"
|
||||
remixicon="RiTerminalBoxLine"
|
||||
/>
|
||||
),
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
title: "History",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Starred",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Models",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="BotIcon"
|
||||
tabler="IconRobot"
|
||||
hugeicons="RoboticIcon"
|
||||
phosphor="RobotIcon"
|
||||
remixicon="RiRobotLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "Genesis",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Explorer",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Quantum",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Documentation",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="BookOpen"
|
||||
tabler="IconBook"
|
||||
hugeicons="BookOpen02Icon"
|
||||
phosphor="BookOpenIcon"
|
||||
remixicon="RiBookOpenLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "Introduction",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Get Started",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Tutorials",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Changelog",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="Settings2Icon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="Settings05Icon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "General",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Team",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Billing",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Limits",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
name: "Design Engineering",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="FrameIcon"
|
||||
tabler="IconFrame"
|
||||
hugeicons="CropIcon"
|
||||
phosphor="CropIcon"
|
||||
remixicon="RiCropLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Sales & Marketing",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="PieChartIcon"
|
||||
tabler="IconChartPie"
|
||||
hugeicons="PieChartIcon"
|
||||
phosphor="ChartPieIcon"
|
||||
remixicon="RiPieChartLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "Travel",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="MapIcon"
|
||||
tabler="IconMap"
|
||||
hugeicons="MapsIcon"
|
||||
phosphor="MapTrifoldIcon"
|
||||
remixicon="RiMapLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const [activeTeam, setActiveTeam] = React.useState(data.teams[0])
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar collapsible="icon">
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenuTrigger>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
className="aria-expanded:bg-sidebar-accent aria-expanded:text-sidebar-accent-foreground"
|
||||
>
|
||||
<span
|
||||
data-slot="button"
|
||||
className={buttonVariants({
|
||||
size: "icon-sm",
|
||||
className: "size-8",
|
||||
})}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 256 256"
|
||||
>
|
||||
<rect width="256" height="256" fill="none"></rect>
|
||||
<line
|
||||
x1="208"
|
||||
y1="128"
|
||||
x2="128"
|
||||
y2="208"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="32"
|
||||
></line>
|
||||
<line
|
||||
x1="192"
|
||||
y1="40"
|
||||
x2="40"
|
||||
y2="192"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="32"
|
||||
></line>
|
||||
</svg>
|
||||
</span>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">
|
||||
{activeTeam.name}
|
||||
</span>
|
||||
<span className="truncate text-xs">{activeTeam.plan}</span>
|
||||
</div>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>Teams</DropdownMenuLabel>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuGroup>
|
||||
{data.teams.map((team) => (
|
||||
<DropdownMenuItem
|
||||
key={team.name}
|
||||
onAction={() => setActiveTeam(team)}
|
||||
>
|
||||
{team.name}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Platform</SidebarGroupLabel>
|
||||
<SidebarMenu>
|
||||
{data.navMain.map((item) => (
|
||||
<Collapsible
|
||||
key={item.title}
|
||||
defaultExpanded={item.isActive}
|
||||
className="group/collapsible"
|
||||
>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton slot="trigger" tooltip={item.title}>
|
||||
{item.icon}
|
||||
<span>{item.title}</span>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
className="ml-auto transition-transform duration-100 group-data-expanded/collapsible:rotate-90"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{item.items?.map((subItem) => (
|
||||
<SidebarMenuSubItem key={subItem.title}>
|
||||
<SidebarMenuSubButton href={subItem.url}>
|
||||
{subItem.title}
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</SidebarMenuItem>
|
||||
</Collapsible>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
<SidebarGroup className="group-data-[collapsible=icon]:hidden">
|
||||
<SidebarGroupLabel>Projects</SidebarGroupLabel>
|
||||
<SidebarMenu>
|
||||
{data.projects.map((item) => (
|
||||
<SidebarMenuItem key={item.name}>
|
||||
<SidebarMenuButton href={item.url}>
|
||||
{item.icon}
|
||||
{item.name}
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<DropdownMenuTrigger>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
className="aria-expanded:bg-sidebar-accent aria-expanded:text-sidebar-accent-foreground"
|
||||
>
|
||||
<Avatar>
|
||||
<AvatarImage src={data.user.avatar} alt={data.user.name} />
|
||||
<AvatarFallback className="rounded-lg">CN</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="grid flex-1 text-left text-sm leading-tight">
|
||||
<span className="truncate font-medium">
|
||||
{data.user.name}
|
||||
</span>
|
||||
<span className="truncate text-xs">{data.user.email}</span>
|
||||
</div>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronsUpDownIcon"
|
||||
tabler="IconSelector"
|
||||
hugeicons="UnfoldMoreIcon"
|
||||
phosphor="CaretUpDownIcon"
|
||||
remixicon="RiArrowUpDownLine"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuLabel>
|
||||
<Item size="xs">
|
||||
<ItemMedia>
|
||||
<Avatar>
|
||||
<AvatarImage
|
||||
src={data.user.avatar}
|
||||
alt={data.user.name}
|
||||
/>
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
</ItemMedia>
|
||||
<ItemContent>
|
||||
<ItemTitle>{data.user.name}</ItemTitle>
|
||||
<ItemDescription> {data.user.email}</ItemDescription>
|
||||
</ItemContent>
|
||||
</Item>
|
||||
</DropdownMenuLabel>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Account</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem>Log out</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarFooter>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-12">
|
||||
<div className="flex items-center gap-2 px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</div>
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
281
apps/v4/registry/bases/aria/examples/sidebar-inset-example.tsx
Normal file
281
apps/v4/registry/bases/aria/examples/sidebar-inset-example.tsx
Normal file
@@ -0,0 +1,281 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "@/registry/bases/aria/ui/collapsible"
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupContent,
|
||||
SidebarGroupLabel,
|
||||
SidebarInset,
|
||||
SidebarMenu,
|
||||
SidebarMenuAction,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
SidebarProvider,
|
||||
SidebarRail,
|
||||
SidebarTrigger,
|
||||
} from "@/registry/bases/aria/ui/sidebar"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SidebarInsetExample() {
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "Dashboard",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="HomeIcon"
|
||||
tabler="IconHome"
|
||||
hugeicons="Home01Icon"
|
||||
phosphor="HouseIcon"
|
||||
remixicon="RiHomeLine"
|
||||
/>
|
||||
),
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
title: "Overview",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Analytics",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Analytics",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="ChartLineIcon"
|
||||
tabler="IconChartLine"
|
||||
hugeicons="ChartIcon"
|
||||
phosphor="ChartLineIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "Reports",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Metrics",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Orders",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="ShoppingBagIcon"
|
||||
tabler="IconShoppingBag"
|
||||
hugeicons="ShoppingBag01Icon"
|
||||
phosphor="BagIcon"
|
||||
remixicon="RiShoppingBagLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "All Orders",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Pending",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Completed",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Products",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="ShoppingCartIcon"
|
||||
tabler="IconShoppingCart"
|
||||
hugeicons="ShoppingCart01Icon"
|
||||
phosphor="ShoppingCartIcon"
|
||||
remixicon="RiShoppingCartLine"
|
||||
/>
|
||||
),
|
||||
items: [
|
||||
{
|
||||
title: "All Products",
|
||||
url: "#",
|
||||
},
|
||||
{
|
||||
title: "Categories",
|
||||
url: "#",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Invoices",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="FileIcon"
|
||||
tabler="IconFile"
|
||||
hugeicons="File01Icon"
|
||||
phosphor="FileIcon"
|
||||
remixicon="RiFileLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Customers",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="UserIcon"
|
||||
tabler="IconUser"
|
||||
hugeicons="UserIcon"
|
||||
phosphor="UserIcon"
|
||||
remixicon="RiUserLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="Settings2Icon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="Settings05Icon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
navSecondary: [
|
||||
{
|
||||
title: "Support",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="LifeBuoy"
|
||||
tabler="IconLifebuoy"
|
||||
hugeicons="ChartRingIcon"
|
||||
phosphor="LifebuoyIcon"
|
||||
remixicon="RiLifebuoyLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Feedback",
|
||||
url: "#",
|
||||
icon: (
|
||||
<IconPlaceholder
|
||||
lucide="Send"
|
||||
tabler="IconSend"
|
||||
hugeicons="SentIcon"
|
||||
phosphor="PaperPlaneTiltIcon"
|
||||
remixicon="RiSendPlaneLine"
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarProvider>
|
||||
<Sidebar variant="inset">
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>Dashboard</SidebarGroupLabel>
|
||||
<SidebarMenu>
|
||||
{data.navMain.map((item) => (
|
||||
<Collapsible
|
||||
key={item.title}
|
||||
defaultExpanded={item.isActive}
|
||||
render={(props) => <SidebarMenuItem {...props} />}
|
||||
>
|
||||
<SidebarMenuButton href={item.url} isActive={item.isActive}>
|
||||
{item.icon}
|
||||
<span>{item.title}</span>
|
||||
</SidebarMenuButton>
|
||||
{item.items?.length ? (
|
||||
<>
|
||||
<SidebarMenuAction
|
||||
slot="trigger"
|
||||
className="group-data-open/menu-item:rotate-90"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ChevronRightIcon"
|
||||
tabler="IconChevronRight"
|
||||
hugeicons="ArrowRight01Icon"
|
||||
phosphor="CaretRightIcon"
|
||||
remixicon="RiArrowRightSLine"
|
||||
/>
|
||||
<span className="sr-only">Toggle</span>
|
||||
</SidebarMenuAction>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
{item.items.map((subItem) => (
|
||||
<SidebarMenuSubItem key={subItem.title}>
|
||||
<SidebarMenuSubButton href={subItem.url}>
|
||||
{subItem.title}
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
))}
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</>
|
||||
) : null}
|
||||
</Collapsible>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroup>
|
||||
<SidebarGroup className="mt-auto">
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{data.navSecondary.map((item) => (
|
||||
<SidebarMenuItem key={item.title}>
|
||||
<SidebarMenuButton href={item.url} size="sm">
|
||||
{item.icon}
|
||||
<span>{item.title}</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
</SidebarMenu>
|
||||
</SidebarGroupContent>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
<SidebarInset>
|
||||
<header className="flex h-16 shrink-0 items-center gap-2 border-b px-4">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
</header>
|
||||
<div className="flex flex-1 flex-col gap-4 p-4">
|
||||
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
<div className="aspect-video rounded-xl bg-muted/50" />
|
||||
</div>
|
||||
<div className="min-h-[100vh] flex-1 rounded-xl bg-muted/50 md:min-h-min" />
|
||||
</div>
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
102
apps/v4/registry/bases/aria/examples/skeleton-example.tsx
Normal file
102
apps/v4/registry/bases/aria/examples/skeleton-example.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Card, CardContent, CardHeader } from "@/registry/bases/aria/ui/card"
|
||||
import { Skeleton } from "@/registry/bases/aria/ui/skeleton"
|
||||
|
||||
export default function SkeletonExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SkeletonAvatar />
|
||||
<SkeletonCard />
|
||||
<SkeletonText />
|
||||
<SkeletonForm />
|
||||
<SkeletonTable />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonAvatar() {
|
||||
return (
|
||||
<Example title="Avatar">
|
||||
<div className="flex w-full items-center gap-4">
|
||||
<Skeleton className="size-10 shrink-0 rounded-full" />
|
||||
<div className="grid gap-2">
|
||||
<Skeleton className="h-4 w-[150px]" />
|
||||
<Skeleton className="h-4 w-[100px]" />
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonCard() {
|
||||
return (
|
||||
<Example title="Card">
|
||||
<Card className="w-full">
|
||||
<CardHeader>
|
||||
<Skeleton className="h-4 w-2/3" />
|
||||
<Skeleton className="h-4 w-1/2" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<Skeleton className="aspect-square w-full" />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonText() {
|
||||
return (
|
||||
<Example title="Text">
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-full" />
|
||||
<Skeleton className="h-4 w-3/4" />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonForm() {
|
||||
return (
|
||||
<Example title="Form">
|
||||
<div className="flex w-full flex-col gap-7">
|
||||
<div className="flex flex-col gap-3">
|
||||
<Skeleton className="h-4 w-20" />
|
||||
<Skeleton className="h-10 w-full" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-10 w-full" />
|
||||
</div>
|
||||
<Skeleton className="h-9 w-24" />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SkeletonTable() {
|
||||
return (
|
||||
<Example title="Table">
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<div className="flex gap-4">
|
||||
<Skeleton className="h-4 flex-1" />
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Skeleton className="h-4 flex-1" />
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</div>
|
||||
<div className="flex gap-4">
|
||||
<Skeleton className="h-4 flex-1" />
|
||||
<Skeleton className="h-4 w-24" />
|
||||
<Skeleton className="h-4 w-20" />
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
127
apps/v4/registry/bases/aria/examples/slider-example.tsx
Normal file
127
apps/v4/registry/bases/aria/examples/slider-example.tsx
Normal file
@@ -0,0 +1,127 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Label } from "@/registry/bases/aria/ui/label"
|
||||
import { Slider } from "@/registry/bases/aria/ui/slider"
|
||||
|
||||
export default function SliderExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SliderBasic />
|
||||
<SliderRange />
|
||||
<SliderMultiple />
|
||||
<SliderVertical />
|
||||
<SliderControlled />
|
||||
<SliderDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Slider
|
||||
aria-label="Basic slider"
|
||||
defaultValue={50}
|
||||
maxValue={100}
|
||||
step={1}
|
||||
/>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderRange() {
|
||||
return (
|
||||
<Example title="Range">
|
||||
<Slider
|
||||
aria-label="Range slider"
|
||||
defaultValue={[25, 50]}
|
||||
maxValue={100}
|
||||
step={5}
|
||||
/>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderMultiple() {
|
||||
return (
|
||||
<Example title="Multiple Thumbs">
|
||||
<Slider
|
||||
aria-label="Multiple thumbs slider"
|
||||
defaultValue={[10, 20, 70]}
|
||||
maxValue={100}
|
||||
step={10}
|
||||
/>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<div className="flex items-center gap-6">
|
||||
<Slider
|
||||
aria-label="Vertical slider"
|
||||
defaultValue={[50]}
|
||||
maxValue={100}
|
||||
step={1}
|
||||
orientation="vertical"
|
||||
className="h-40"
|
||||
/>
|
||||
<Slider
|
||||
aria-label="Vertical slider"
|
||||
defaultValue={[25]}
|
||||
maxValue={100}
|
||||
step={1}
|
||||
orientation="vertical"
|
||||
className="h-40"
|
||||
/>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderControlled() {
|
||||
const [value, setValue] = React.useState([0.3, 0.7])
|
||||
|
||||
return (
|
||||
<Example title="Controlled">
|
||||
<div className="grid w-full gap-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<Label htmlFor="slider-demo-temperature">Temperature</Label>
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{value.join(", ")}
|
||||
</span>
|
||||
</div>
|
||||
<Slider
|
||||
aria-label="Controlled slider"
|
||||
id="slider-demo-temperature"
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
minValue={0}
|
||||
maxValue={1}
|
||||
step={0.1}
|
||||
/>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SliderDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Slider
|
||||
aria-label="Disabled slider"
|
||||
defaultValue={[50]}
|
||||
maxValue={100}
|
||||
step={1}
|
||||
isDisabled
|
||||
/>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
50
apps/v4/registry/bases/aria/examples/sonner-example.tsx
Normal file
50
apps/v4/registry/bases/aria/examples/sonner-example.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
"use client"
|
||||
|
||||
import { toast } from "sonner"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
|
||||
export default function SonnerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SonnerBasic />
|
||||
<SonnerWithDescription />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SonnerBasic() {
|
||||
return (
|
||||
<Example title="Basic" className="items-center justify-center">
|
||||
<Button
|
||||
onPress={() => toast("Event has been created")}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Show Toast
|
||||
</Button>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SonnerWithDescription() {
|
||||
return (
|
||||
<Example title="With Description" className="items-center justify-center">
|
||||
<Button
|
||||
onPress={() =>
|
||||
toast("Event has been created", {
|
||||
description: "Monday, January 3rd at 6:00pm",
|
||||
})
|
||||
}
|
||||
variant="outline"
|
||||
className="w-fit"
|
||||
>
|
||||
Show Toast
|
||||
</Button>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
143
apps/v4/registry/bases/aria/examples/spinner-example.tsx
Normal file
143
apps/v4/registry/bases/aria/examples/spinner-example.tsx
Normal file
@@ -0,0 +1,143 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Badge } from "@/registry/bases/aria/ui/badge"
|
||||
import { Button, LinkButton } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
Empty,
|
||||
EmptyContent,
|
||||
EmptyDescription,
|
||||
EmptyHeader,
|
||||
EmptyMedia,
|
||||
EmptyTitle,
|
||||
} from "@/registry/bases/aria/ui/empty"
|
||||
import { Field, FieldLabel } from "@/registry/bases/aria/ui/field"
|
||||
import {
|
||||
InputGroup,
|
||||
InputGroupAddon,
|
||||
InputGroupInput,
|
||||
} from "@/registry/bases/aria/ui/input-group"
|
||||
import { Spinner } from "@/registry/bases/aria/ui/spinner"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function SpinnerExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SpinnerBasic />
|
||||
<SpinnerInButtons />
|
||||
<SpinnerInBadges />
|
||||
<SpinnerInInputGroup />
|
||||
<SpinnerInEmpty />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex items-center gap-6">
|
||||
<Spinner />
|
||||
<Spinner className="size-6" />
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInButtons() {
|
||||
return (
|
||||
<Example title="In Buttons">
|
||||
<div className="flex flex-wrap items-center gap-4">
|
||||
<Button>
|
||||
<Spinner data-icon="inline-start" /> Submit
|
||||
</Button>
|
||||
<Button isDisabled>
|
||||
<Spinner data-icon="inline-start" /> Disabled
|
||||
</Button>
|
||||
<Button variant="outline" isDisabled>
|
||||
<Spinner data-icon="inline-start" /> Outline
|
||||
</Button>
|
||||
<Button variant="outline" size="icon" isDisabled>
|
||||
<Spinner data-icon="inline-start" />
|
||||
<span className="sr-only">Loading...</span>
|
||||
</Button>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInBadges() {
|
||||
return (
|
||||
<Example title="In Badges" className="items-center justify-center">
|
||||
<div className="flex flex-wrap items-center justify-center gap-4">
|
||||
<Badge>
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
<Badge variant="secondary">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
<Badge variant="destructive">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
<Badge variant="outline">
|
||||
<Spinner data-icon="inline-start" />
|
||||
Badge
|
||||
</Badge>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInInputGroup() {
|
||||
return (
|
||||
<Example title="In Input Group">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="input-group-spinner">Input Group</FieldLabel>
|
||||
<InputGroup>
|
||||
<InputGroupInput id="input-group-spinner" />
|
||||
<InputGroupAddon>
|
||||
<Spinner />
|
||||
</InputGroupAddon>
|
||||
</InputGroup>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SpinnerInEmpty() {
|
||||
return (
|
||||
<Example title="In Empty State" containerClassName="lg:col-span-full">
|
||||
<Empty className="min-h-[300px]">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<Spinner />
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No projects yet</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
You haven't created any projects yet. Get started by creating
|
||||
your first project.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
<EmptyContent>
|
||||
<div className="flex gap-2">
|
||||
<LinkButton href="#">Create project</LinkButton>
|
||||
<Button variant="outline">Import project</Button>
|
||||
</div>
|
||||
<LinkButton variant="link" href="#" className="text-muted-foreground">
|
||||
Learn more{" "}
|
||||
<IconPlaceholder
|
||||
lucide="ArrowRightIcon"
|
||||
tabler="IconArrowRight"
|
||||
hugeicons="ArrowRight02Icon"
|
||||
phosphor="ArrowRightIcon"
|
||||
remixicon="RiArrowRightLine"
|
||||
/>
|
||||
</LinkButton>
|
||||
</EmptyContent>
|
||||
</Empty>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
102
apps/v4/registry/bases/aria/examples/switch-example.tsx
Normal file
102
apps/v4/registry/bases/aria/examples/switch-example.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldContent,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
FieldTitle,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Label } from "@/registry/bases/aria/ui/label"
|
||||
import { Switch } from "@/registry/bases/aria/ui/switch"
|
||||
|
||||
export default function SwitchExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<SwitchBasic />
|
||||
<SwitchWithDescription />
|
||||
<SwitchWithLabel />
|
||||
<SwitchDisabled />
|
||||
<SwitchSizes />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Field orientation="horizontal">
|
||||
<Switch id="switch-basic" />
|
||||
<FieldLabel htmlFor="switch-basic">Airplane Mode</FieldLabel>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-bluetooth" defaultSelected />
|
||||
<Label htmlFor="switch-bluetooth">Bluetooth</Label>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<FieldLabel htmlFor="switch-focus-mode">
|
||||
<Field orientation="horizontal">
|
||||
<FieldContent>
|
||||
<FieldTitle>Share across devices</FieldTitle>
|
||||
<FieldDescription>
|
||||
Focus is shared across devices, and turns off when you leave the
|
||||
app.
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
<Switch id="switch-focus-mode" />
|
||||
</Field>
|
||||
</FieldLabel>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<div className="flex flex-col gap-12">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-disabled-unchecked" isDisabled />
|
||||
<Label htmlFor="switch-disabled-unchecked">
|
||||
Disabled (Unchecked)
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-disabled-checked" defaultSelected isDisabled />
|
||||
<Label htmlFor="switch-disabled-checked">Disabled (Checked)</Label>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function SwitchSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-12">
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-size-sm" size="sm" />
|
||||
<Label htmlFor="switch-size-sm">Small</Label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Switch id="switch-size-default" size="default" />
|
||||
<Label htmlFor="switch-size-default">Default</Label>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
457
apps/v4/registry/bases/aria/examples/table-example.tsx
Normal file
457
apps/v4/registry/bases/aria/examples/table-example.tsx
Normal file
@@ -0,0 +1,457 @@
|
||||
"use client"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/registry/bases/aria/ui/table"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
const invoices = [
|
||||
{
|
||||
invoice: "INV001",
|
||||
paymentStatus: "Paid",
|
||||
totalAmount: "$250.00",
|
||||
paymentMethod: "Credit Card",
|
||||
},
|
||||
{
|
||||
invoice: "INV002",
|
||||
paymentStatus: "Pending",
|
||||
totalAmount: "$150.00",
|
||||
paymentMethod: "PayPal",
|
||||
},
|
||||
{
|
||||
invoice: "INV003",
|
||||
paymentStatus: "Unpaid",
|
||||
totalAmount: "$350.00",
|
||||
paymentMethod: "Bank Transfer",
|
||||
},
|
||||
{
|
||||
invoice: "INV004",
|
||||
paymentStatus: "Paid",
|
||||
totalAmount: "$450.00",
|
||||
paymentMethod: "Credit Card",
|
||||
},
|
||||
{
|
||||
invoice: "INV005",
|
||||
paymentStatus: "Paid",
|
||||
totalAmount: "$550.00",
|
||||
paymentMethod: "PayPal",
|
||||
},
|
||||
{
|
||||
invoice: "INV006",
|
||||
paymentStatus: "Pending",
|
||||
totalAmount: "$200.00",
|
||||
paymentMethod: "Bank Transfer",
|
||||
},
|
||||
{
|
||||
invoice: "INV007",
|
||||
paymentStatus: "Unpaid",
|
||||
totalAmount: "$300.00",
|
||||
paymentMethod: "Credit Card",
|
||||
},
|
||||
]
|
||||
|
||||
export default function TableExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TableBasic />
|
||||
<TableWithFooter />
|
||||
<TableSimple />
|
||||
<TableWithBadges />
|
||||
<TableWithActions />
|
||||
<TableWithSelect />
|
||||
<TableWithInput />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TableBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<figure>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead isRowHeader className="w-[100px]">
|
||||
Invoice
|
||||
</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Method</TableHead>
|
||||
<TableHead className="text-right">Amount</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{invoices.slice(0, 3).map((invoice) => (
|
||||
<TableRow key={invoice.invoice}>
|
||||
<TableCell className="font-medium">{invoice.invoice}</TableCell>
|
||||
<TableCell>{invoice.paymentStatus}</TableCell>
|
||||
<TableCell>{invoice.paymentMethod}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{invoice.totalAmount}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TableCaption>A list of your recent invoices.</TableCaption>
|
||||
</figure>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithFooter() {
|
||||
return (
|
||||
<Example title="With Footer">
|
||||
<figure>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead isRowHeader className="w-[100px]">
|
||||
Invoice
|
||||
</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Method</TableHead>
|
||||
<TableHead className="text-right">Amount</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{invoices.slice(0, 3).map((invoice) => (
|
||||
<TableRow key={invoice.invoice}>
|
||||
<TableCell className="font-medium">{invoice.invoice}</TableCell>
|
||||
<TableCell>{invoice.paymentStatus}</TableCell>
|
||||
<TableCell>{invoice.paymentMethod}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
{invoice.totalAmount}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TableCell colSpan={3}>Total</TableCell>
|
||||
<TableCell className="text-right">$2,500.00</TableCell>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
<TableCaption>A list of your recent invoices.</TableCaption>
|
||||
</figure>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableSimple() {
|
||||
return (
|
||||
<Example title="Simple">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead isRowHeader>Name</TableHead>
|
||||
<TableHead>Email</TableHead>
|
||||
<TableHead className="text-right">Role</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Alex Morgan</TableCell>
|
||||
<TableCell>alex@example.com</TableCell>
|
||||
<TableCell className="text-right">Admin</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Jordan Lee</TableCell>
|
||||
<TableCell>jordan@example.com</TableCell>
|
||||
<TableCell className="text-right">User</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Taylor Kim</TableCell>
|
||||
<TableCell>taylor@example.com</TableCell>
|
||||
<TableCell className="text-right">User</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithBadges() {
|
||||
return (
|
||||
<Example title="With Badges">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead isRowHeader>Task</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead className="text-right">Priority</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Design homepage</TableCell>
|
||||
<TableCell>
|
||||
<span className="inline-flex items-center rounded-full bg-green-500/10 px-2 py-1 text-xs font-medium text-green-700 dark:text-green-400">
|
||||
Completed
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="inline-flex items-center rounded-full bg-blue-500/10 px-2 py-1 text-xs font-medium text-blue-700 dark:text-blue-400">
|
||||
High
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Implement API</TableCell>
|
||||
<TableCell>
|
||||
<span className="inline-flex items-center rounded-full bg-yellow-500/10 px-2 py-1 text-xs font-medium text-yellow-700 dark:text-yellow-400">
|
||||
In Progress
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="inline-flex items-center rounded-full bg-gray-500/10 px-2 py-1 text-xs font-medium text-gray-700 dark:text-gray-400">
|
||||
Medium
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Write tests</TableCell>
|
||||
<TableCell>
|
||||
<span className="inline-flex items-center rounded-full bg-gray-500/10 px-2 py-1 text-xs font-medium text-gray-700 dark:text-gray-400">
|
||||
Pending
|
||||
</span>
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<span className="inline-flex items-center rounded-full bg-gray-500/10 px-2 py-1 text-xs font-medium text-gray-700 dark:text-gray-400">
|
||||
Low
|
||||
</span>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithActions() {
|
||||
return (
|
||||
<Example title="With Actions">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead isRowHeader>Product</TableHead>
|
||||
<TableHead>Price</TableHead>
|
||||
<TableHead className="text-right">Actions</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Wireless Mouse</TableCell>
|
||||
<TableCell>$29.99</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">Open menu</span>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom end">
|
||||
<DropdownMenuItem>Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem>Duplicate</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Mechanical Keyboard</TableCell>
|
||||
<TableCell>$129.99</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">Open menu</span>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom end">
|
||||
<DropdownMenuItem>Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem>Duplicate</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">USB-C Hub</TableCell>
|
||||
<TableCell>$49.99</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">Open menu</span>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom end">
|
||||
<DropdownMenuItem>Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem>Duplicate</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem variant="destructive">
|
||||
Delete
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
const people = [
|
||||
{ value: "sarah", label: "Sarah Chen" },
|
||||
{ value: "marcus", label: "Marc Rodriguez" },
|
||||
{ value: "emily", label: "Emily Watson" },
|
||||
{ value: "david", label: "David Kim" },
|
||||
]
|
||||
|
||||
const tasks = [
|
||||
{
|
||||
task: "Design homepage",
|
||||
assignee: "sarah",
|
||||
status: "In Progress",
|
||||
},
|
||||
{
|
||||
task: "Implement API",
|
||||
assignee: "marcus",
|
||||
status: "Pending",
|
||||
},
|
||||
{
|
||||
task: "Write tests",
|
||||
assignee: "emily",
|
||||
status: "Not Started",
|
||||
},
|
||||
]
|
||||
|
||||
function TableWithSelect() {
|
||||
return (
|
||||
<Example title="With Select">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead isRowHeader>Task</TableHead>
|
||||
<TableHead>Assignee</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{tasks.map((item) => (
|
||||
<TableRow key={item.task}>
|
||||
<TableCell className="font-medium">{item.task}</TableCell>
|
||||
<TableCell>
|
||||
<Select defaultValue={item.assignee}>
|
||||
<SelectTrigger className="w-40" size="sm">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{people.map((person) => (
|
||||
<SelectItem key={person.value} id={person.value}>
|
||||
{person.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</TableCell>
|
||||
<TableCell>{item.status}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TableWithInput() {
|
||||
return (
|
||||
<Example title="With Input">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableHead isRowHeader>Product</TableHead>
|
||||
<TableHead>Quantity</TableHead>
|
||||
<TableHead>Price</TableHead>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Wireless Mouse</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
defaultValue="1"
|
||||
className="h-8 w-20"
|
||||
min="0"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>$29.99</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">Mechanical Keyboard</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
defaultValue="2"
|
||||
className="h-8 w-20"
|
||||
min="0"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>$129.99</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableCell className="font-medium">USB-C Hub</TableCell>
|
||||
<TableCell>
|
||||
<Input
|
||||
type="number"
|
||||
defaultValue="1"
|
||||
className="h-8 w-20"
|
||||
min="0"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>$49.99</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
357
apps/v4/registry/bases/aria/examples/tabs-example.tsx
Normal file
357
apps/v4/registry/bases/aria/examples/tabs-example.tsx
Normal file
@@ -0,0 +1,357 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/registry/bases/aria/ui/dropdown-menu"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/registry/bases/aria/ui/tabs"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function TabsExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TabsBasic />
|
||||
<TabsLine />
|
||||
<TabsVariantsComparison />
|
||||
<TabsDisabled />
|
||||
<TabsWithIcons />
|
||||
<TabsIconOnly />
|
||||
<TabsMultiple />
|
||||
<TabsWithContent />
|
||||
<TabsLineWithContent />
|
||||
<TabsLineDisabled />
|
||||
<TabsWithDropdown />
|
||||
<TabsVertical />
|
||||
<TabsWithInputAndButton />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Tabs defaultSelectedKey="home">
|
||||
<TabsList>
|
||||
<TabsTrigger id="home">Home</TabsTrigger>
|
||||
<TabsTrigger id="settings">Settings</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsLine() {
|
||||
return (
|
||||
<Example title="Line">
|
||||
<Tabs defaultSelectedKey="overview">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger id="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger id="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger id="reports">Reports</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsVariantsComparison() {
|
||||
return (
|
||||
<Example title="Variants Alignment">
|
||||
<div className="flex gap-4">
|
||||
<Tabs defaultSelectedKey="overview">
|
||||
<TabsList>
|
||||
<TabsTrigger id="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger id="analytics">Analytics</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
<Tabs defaultSelectedKey="overview">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger id="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger id="analytics">Analytics</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Tabs defaultSelectedKey="home">
|
||||
<TabsList>
|
||||
<TabsTrigger id="home">Home</TabsTrigger>
|
||||
<TabsTrigger id="settings" isDisabled>
|
||||
Disabled
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<Tabs defaultSelectedKey="preview">
|
||||
<TabsList>
|
||||
<TabsTrigger id="preview">
|
||||
<IconPlaceholder
|
||||
lucide="AppWindowIcon"
|
||||
tabler="IconAppWindow"
|
||||
hugeicons="CursorInWindowIcon"
|
||||
phosphor="AppWindowIcon"
|
||||
remixicon="RiWindowLine"
|
||||
/>
|
||||
Preview
|
||||
</TabsTrigger>
|
||||
<TabsTrigger id="code">
|
||||
<IconPlaceholder
|
||||
lucide="CodeIcon"
|
||||
tabler="IconCode"
|
||||
hugeicons="CodeIcon"
|
||||
phosphor="CodeIcon"
|
||||
remixicon="RiCodeLine"
|
||||
/>
|
||||
Code
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsIconOnly() {
|
||||
return (
|
||||
<Example title="Icon Only">
|
||||
<Tabs defaultSelectedKey="home">
|
||||
<TabsList>
|
||||
<TabsTrigger id="home">
|
||||
<IconPlaceholder
|
||||
lucide="HomeIcon"
|
||||
tabler="IconHome"
|
||||
hugeicons="HomeIcon"
|
||||
phosphor="HouseIcon"
|
||||
remixicon="RiHomeLine"
|
||||
/>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger id="search">
|
||||
<IconPlaceholder
|
||||
lucide="SearchIcon"
|
||||
tabler="IconSearch"
|
||||
hugeicons="SearchIcon"
|
||||
phosphor="MagnifyingGlassIcon"
|
||||
remixicon="RiSearchLine"
|
||||
/>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger id="settings">
|
||||
<IconPlaceholder
|
||||
lucide="SettingsIcon"
|
||||
tabler="IconSettings"
|
||||
hugeicons="SettingsIcon"
|
||||
phosphor="GearIcon"
|
||||
remixicon="RiSettingsLine"
|
||||
/>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsMultiple() {
|
||||
return (
|
||||
<Example title="Multiple">
|
||||
<Tabs defaultSelectedKey="overview">
|
||||
<TabsList>
|
||||
<TabsTrigger id="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger id="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger id="reports">Reports</TabsTrigger>
|
||||
<TabsTrigger id="settings">Settings</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithContent() {
|
||||
return (
|
||||
<Example title="With Content">
|
||||
<Tabs defaultSelectedKey="account">
|
||||
<TabsList>
|
||||
<TabsTrigger id="account">Account</TabsTrigger>
|
||||
<TabsTrigger id="password">Password</TabsTrigger>
|
||||
<TabsTrigger id="notifications">Notifications</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent id="account">
|
||||
Manage your account preferences and profile information.
|
||||
</TabsContent>
|
||||
<TabsContent id="password">
|
||||
Update your password to keep your account secure.
|
||||
</TabsContent>
|
||||
<TabsContent id="notifications">
|
||||
Configure how you receive notifications and alerts.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsLineWithContent() {
|
||||
return (
|
||||
<Example title="Line With Content">
|
||||
<Tabs defaultSelectedKey="account">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger id="account">Account</TabsTrigger>
|
||||
<TabsTrigger id="password">Password</TabsTrigger>
|
||||
<TabsTrigger id="notifications">Notifications</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent id="account">
|
||||
Manage your account preferences and profile information.
|
||||
</TabsContent>
|
||||
<TabsContent id="password">
|
||||
Update your password to keep your account secure.
|
||||
</TabsContent>
|
||||
<TabsContent id="notifications">
|
||||
Configure how you receive notifications and alerts.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsLineDisabled() {
|
||||
return (
|
||||
<Example title="Line Disabled">
|
||||
<Tabs defaultSelectedKey="overview">
|
||||
<TabsList variant="line">
|
||||
<TabsTrigger id="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger id="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger id="reports" isDisabled>
|
||||
Reports
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithDropdown() {
|
||||
return (
|
||||
<Example title="With Dropdown">
|
||||
<Tabs defaultSelectedKey="overview">
|
||||
<div className="flex items-center justify-between">
|
||||
<TabsList>
|
||||
<TabsTrigger id="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger id="analytics">Analytics</TabsTrigger>
|
||||
<TabsTrigger id="reports">Reports</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="ghost" size="icon" className="size-8">
|
||||
<IconPlaceholder
|
||||
lucide="MoreHorizontalIcon"
|
||||
tabler="IconDots"
|
||||
hugeicons="MoreHorizontalCircle01Icon"
|
||||
phosphor="DotsThreeOutlineIcon"
|
||||
remixicon="RiMoreLine"
|
||||
/>
|
||||
<span className="sr-only">More options</span>
|
||||
</Button>
|
||||
<DropdownMenu placement="bottom end">
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
<DropdownMenuItem>Export</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Archive</DropdownMenuItem>
|
||||
</DropdownMenu>
|
||||
</DropdownMenuTrigger>
|
||||
</div>
|
||||
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent id="overview">
|
||||
View your dashboard metrics and key performance indicators.
|
||||
</TabsContent>
|
||||
<TabsContent id="analytics">
|
||||
Detailed analytics and insights about your data.
|
||||
</TabsContent>
|
||||
<TabsContent id="reports">
|
||||
Generate and view custom reports.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<Tabs defaultSelectedKey="account" orientation="vertical">
|
||||
<TabsList>
|
||||
<TabsTrigger id="account">Account</TabsTrigger>
|
||||
<TabsTrigger id="password">Password</TabsTrigger>
|
||||
<TabsTrigger id="notifications">Notifications</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent id="account">
|
||||
Manage your account preferences and profile information.
|
||||
</TabsContent>
|
||||
<TabsContent id="password">
|
||||
Update your password to keep your account secure. Use a strong
|
||||
password with a mix of letters, numbers, and symbols.
|
||||
</TabsContent>
|
||||
<TabsContent id="notifications">
|
||||
Configure how you receive notifications and alerts. Choose which
|
||||
types of notifications you want to receive and how you want to
|
||||
receive them.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsWithInputAndButton() {
|
||||
return (
|
||||
<Example title="With Input and Button" containerClassName="col-span-full">
|
||||
<Tabs defaultSelectedKey="overview" className="mx-auto w-full max-w-lg">
|
||||
<div className="flex items-center gap-4">
|
||||
<TabsList>
|
||||
<TabsTrigger id="overview">Overview</TabsTrigger>
|
||||
<TabsTrigger id="analytics">Analytics</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<Input placeholder="Search..." className="w-44" />
|
||||
<Button>Action</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border style-vega:rounded-lg style-vega:p-6 style-nova:rounded-lg style-nova:p-4 style-lyra:rounded-none style-lyra:p-4 style-maia:rounded-xl style-maia:p-6 style-mira:rounded-md style-mira:p-4 style-luma:rounded-xl style-luma:p-6 style-rhea:rounded-xl style-rhea:p-6">
|
||||
<TabsContent id="overview">
|
||||
View your dashboard metrics and key performance indicators.
|
||||
</TabsContent>
|
||||
<TabsContent id="analytics">
|
||||
Detailed analytics and insights about your data.
|
||||
</TabsContent>
|
||||
<TabsContent id="reports">
|
||||
Generate and view custom reports.
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
86
apps/v4/registry/bases/aria/examples/textarea-example.tsx
Normal file
86
apps/v4/registry/bases/aria/examples/textarea-example.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Textarea } from "@/registry/bases/aria/ui/textarea"
|
||||
|
||||
export default function TextareaExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TextareaBasic />
|
||||
<TextareaInvalid />
|
||||
<TextareaWithLabel />
|
||||
<TextareaWithDescription />
|
||||
<TextareaDisabled />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<Textarea placeholder="Type your message here." />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaInvalid() {
|
||||
return (
|
||||
<Example title="Invalid">
|
||||
<Textarea placeholder="Type your message here." aria-invalid="true" />
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaWithLabel() {
|
||||
return (
|
||||
<Example title="With Label">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-demo-message">Message</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-demo-message"
|
||||
placeholder="Type your message here."
|
||||
rows={6}
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaWithDescription() {
|
||||
return (
|
||||
<Example title="With Description">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-demo-message-2">Message</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-demo-message-2"
|
||||
placeholder="Type your message here."
|
||||
rows={6}
|
||||
/>
|
||||
<FieldDescription>
|
||||
Type your message and press enter to send.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TextareaDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<Field>
|
||||
<FieldLabel htmlFor="textarea-demo-disabled">Message</FieldLabel>
|
||||
<Textarea
|
||||
id="textarea-demo-disabled"
|
||||
placeholder="Type your message here."
|
||||
disabled
|
||||
/>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
342
apps/v4/registry/bases/aria/examples/toggle-example.tsx
Normal file
342
apps/v4/registry/bases/aria/examples/toggle-example.tsx
Normal file
@@ -0,0 +1,342 @@
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { Toggle } from "@/registry/bases/aria/ui/toggle"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ToggleExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ToggleBasic />
|
||||
<ToggleOutline />
|
||||
<ToggleSizes />
|
||||
<ToggleWithButtonText />
|
||||
<ToggleWithButtonIcon />
|
||||
<ToggleWithButtonIconText />
|
||||
<ToggleDisabled />
|
||||
<ToggleWithIcon />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle aria-label="Toggle bold" defaultSelected>
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</Toggle>
|
||||
<Toggle aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</Toggle>
|
||||
<Toggle aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleOutline() {
|
||||
return (
|
||||
<Example title="Outline">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle variant="outline" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
Italic
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
Bold
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle variant="outline" aria-label="Toggle small" size="sm">
|
||||
Small
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle default" size="default">
|
||||
Default
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle large" size="lg">
|
||||
Large
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithButtonText() {
|
||||
return (
|
||||
<Example title="With Button Text">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="sm" variant="outline">
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle sm" size="sm">
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="default" variant="outline">
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle default" size="default">
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="lg" variant="outline">
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle lg" size="lg">
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithButtonIcon() {
|
||||
return (
|
||||
<Example title="With Button Icon">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle sm icon" size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</Button>
|
||||
<Toggle
|
||||
variant="outline"
|
||||
aria-label="Toggle default icon"
|
||||
size="default"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="outline" size="icon-lg">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle lg icon" size="lg">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithButtonIconText() {
|
||||
return (
|
||||
<Example title="With Button Icon + Text">
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="sm" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle sm icon text" size="sm">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="default" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
<Toggle
|
||||
variant="outline"
|
||||
aria-label="Toggle default icon text"
|
||||
size="default"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button size="lg" variant="outline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
data-icon="inline-start"
|
||||
/>
|
||||
Button
|
||||
</Button>
|
||||
<Toggle variant="outline" aria-label="Toggle lg icon text" size="lg">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
Toggle
|
||||
</Toggle>
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle aria-label="Toggle disabled" isDisabled>
|
||||
Disabled
|
||||
</Toggle>
|
||||
<Toggle
|
||||
variant="outline"
|
||||
aria-label="Toggle disabled outline"
|
||||
isDisabled
|
||||
>
|
||||
Disabled
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleWithIcon() {
|
||||
return (
|
||||
<Example title="With Icon">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Toggle aria-label="Toggle bookmark" defaultSelected>
|
||||
<IconPlaceholder
|
||||
lucide="BookmarkIcon"
|
||||
tabler="IconBookmark"
|
||||
hugeicons="BookmarkIcon"
|
||||
phosphor="BookmarkIcon"
|
||||
remixicon="RiBookmarkLine"
|
||||
className="group-data-[selected]/toggle:fill-accent-foreground"
|
||||
/>
|
||||
</Toggle>
|
||||
<Toggle variant="outline" aria-label="Toggle bookmark outline">
|
||||
<IconPlaceholder
|
||||
lucide="BookmarkIcon"
|
||||
tabler="IconBookmark"
|
||||
hugeicons="BookmarkIcon"
|
||||
phosphor="BookmarkIcon"
|
||||
remixicon="RiBookmarkLine"
|
||||
className="group-data-[selected]/toggle:fill-accent-foreground"
|
||||
/>
|
||||
Bookmark
|
||||
</Toggle>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
562
apps/v4/registry/bases/aria/examples/toggle-group-example.tsx
Normal file
562
apps/v4/registry/bases/aria/examples/toggle-group-example.tsx
Normal file
@@ -0,0 +1,562 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import {
|
||||
Field,
|
||||
FieldDescription,
|
||||
FieldLabel,
|
||||
} from "@/registry/bases/aria/ui/field"
|
||||
import { Input } from "@/registry/bases/aria/ui/input"
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/registry/bases/aria/ui/select"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/bases/aria/ui/toggle-group"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function ToggleGroupExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<ToggleGroupBasic />
|
||||
<ToggleGroupOutline />
|
||||
<ToggleGroupOutlineWithIcons />
|
||||
<ToggleGroupSizes />
|
||||
<ToggleGroupSpacing />
|
||||
<ToggleGroupWithIcons />
|
||||
<ToggleGroupFilter />
|
||||
<ToggleGroupDateRange />
|
||||
<ToggleGroupSort />
|
||||
<ToggleGroupWithInputAndSelect />
|
||||
<ToggleGroupVertical />
|
||||
<ToggleGroupVerticalOutline />
|
||||
<ToggleGroupVerticalOutlineWithIcons />
|
||||
<ToggleGroupVerticalWithSpacing />
|
||||
<ToggleGroupFontWeightSelector />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<ToggleGroup selectionMode="multiple" spacing={1}>
|
||||
<ToggleGroupItem id="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupOutline() {
|
||||
return (
|
||||
<Example title="Outline">
|
||||
<ToggleGroup variant="outline" defaultSelectedKeys={["all"]}>
|
||||
<ToggleGroupItem id="all" aria-label="Toggle all">
|
||||
All
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="missed" aria-label="Toggle missed">
|
||||
Missed
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupOutlineWithIcons() {
|
||||
return (
|
||||
<Example title="Outline With Icons">
|
||||
<ToggleGroup variant="outline" selectionMode="multiple" size="sm">
|
||||
<ToggleGroupItem id="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupSizes() {
|
||||
return (
|
||||
<Example title="Sizes">
|
||||
<div className="flex flex-col gap-4">
|
||||
<ToggleGroup size="sm" defaultSelectedKeys={["top"]} variant="outline">
|
||||
<ToggleGroupItem id="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
<ToggleGroup defaultSelectedKeys={["top"]} variant="outline">
|
||||
<ToggleGroupItem id="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupSpacing() {
|
||||
return (
|
||||
<Example title="With Spacing">
|
||||
<ToggleGroup size="sm" defaultSelectedKeys={["top"]} spacing={2}>
|
||||
<ToggleGroupItem id="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupWithIcons() {
|
||||
return (
|
||||
<Example title="With Icons">
|
||||
<ToggleGroup
|
||||
selectionMode="multiple"
|
||||
variant="outline"
|
||||
spacing={2}
|
||||
size="sm"
|
||||
>
|
||||
<ToggleGroupItem
|
||||
id="star"
|
||||
aria-label="Toggle star"
|
||||
className="data-selected:bg-transparent data-selected:*:[svg]:fill-foreground data-selected:*:[svg]:stroke-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="StarIcon"
|
||||
tabler="IconStar"
|
||||
hugeicons="StarIcon"
|
||||
phosphor="StarIcon"
|
||||
remixicon="RiStarLine"
|
||||
/>
|
||||
Star
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
id="heart"
|
||||
aria-label="Toggle heart"
|
||||
className="data-selected:bg-transparent data-selected:*:[svg]:fill-foreground data-selected:*:[svg]:stroke-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="HeartIcon"
|
||||
tabler="IconHeart"
|
||||
hugeicons="FavouriteIcon"
|
||||
phosphor="HeartIcon"
|
||||
remixicon="RiHeartLine"
|
||||
/>
|
||||
Heart
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
id="bookmark"
|
||||
aria-label="Toggle bookmark"
|
||||
className="data-selected:bg-transparent data-selected:*:[svg]:fill-foreground data-selected:*:[svg]:stroke-foreground"
|
||||
>
|
||||
<IconPlaceholder
|
||||
lucide="BookmarkIcon"
|
||||
tabler="IconBookmark"
|
||||
hugeicons="BookmarkIcon"
|
||||
phosphor="BookmarkIcon"
|
||||
remixicon="RiBookmarkLine"
|
||||
/>
|
||||
Bookmark
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupFilter() {
|
||||
return (
|
||||
<Example title="Filter">
|
||||
<ToggleGroup defaultSelectedKeys={["all"]} variant="outline" size="sm">
|
||||
<ToggleGroupItem id="all" aria-label="All">
|
||||
All
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="active" aria-label="Active">
|
||||
Active
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="completed" aria-label="Completed">
|
||||
Completed
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="archived" aria-label="Archived">
|
||||
Archived
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupDateRange() {
|
||||
return (
|
||||
<Example title="Date Range">
|
||||
<ToggleGroup
|
||||
defaultSelectedKeys={["today"]}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
spacing={2}
|
||||
>
|
||||
<ToggleGroupItem id="today" aria-label="Today">
|
||||
Today
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="week" aria-label="This Week">
|
||||
This Week
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="month" aria-label="This Month">
|
||||
This Month
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="year" aria-label="This Year">
|
||||
This Year
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupSort() {
|
||||
return (
|
||||
<Example title="Sort">
|
||||
<ToggleGroup defaultSelectedKeys={["newest"]} variant="outline" size="sm">
|
||||
<ToggleGroupItem id="newest" aria-label="Newest">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowDownIcon"
|
||||
tabler="IconArrowDown"
|
||||
hugeicons="ArrowDownIcon"
|
||||
phosphor="ArrowDownIcon"
|
||||
remixicon="RiArrowDownLine"
|
||||
/>
|
||||
Newest
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="oldest" aria-label="Oldest">
|
||||
<IconPlaceholder
|
||||
lucide="ArrowUpIcon"
|
||||
tabler="IconArrowUp"
|
||||
hugeicons="ArrowUpIcon"
|
||||
phosphor="ArrowUpIcon"
|
||||
remixicon="RiArrowUpLine"
|
||||
/>
|
||||
Oldest
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="popular" aria-label="Popular">
|
||||
<IconPlaceholder
|
||||
lucide="TrendingUpIcon"
|
||||
tabler="IconTrendingUp"
|
||||
hugeicons="TradeUpIcon"
|
||||
phosphor="TrendUpIcon"
|
||||
remixicon="RiLineChartLine"
|
||||
/>
|
||||
Popular
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupWithInputAndSelect() {
|
||||
const items = [
|
||||
{ label: "All", value: "all" },
|
||||
{ label: "Active", value: "active" },
|
||||
{ label: "Archived", value: "archived" },
|
||||
]
|
||||
return (
|
||||
<Example title="With Input and Select">
|
||||
<div className="flex items-center gap-2">
|
||||
<Input type="search" placeholder="Search..." className="flex-1" />
|
||||
<Select defaultValue={items[0].value}>
|
||||
<SelectTrigger className="w-32">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} id={item.value}>
|
||||
{item.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<ToggleGroup defaultSelectedKeys={["grid"]} variant="outline">
|
||||
<ToggleGroupItem id="grid" aria-label="Grid view">
|
||||
Grid
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="list" aria-label="List view">
|
||||
List
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVertical() {
|
||||
return (
|
||||
<Example title="Vertical">
|
||||
<ToggleGroup selectionMode="multiple" orientation="vertical" spacing={1}>
|
||||
<ToggleGroupItem id="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVerticalOutline() {
|
||||
return (
|
||||
<Example title="Vertical Outline">
|
||||
<ToggleGroup
|
||||
variant="outline"
|
||||
defaultSelectedKeys={["all"]}
|
||||
orientation="vertical"
|
||||
size="sm"
|
||||
>
|
||||
<ToggleGroupItem id="all" aria-label="Toggle all">
|
||||
All
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="active" aria-label="Toggle active">
|
||||
Active
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="completed" aria-label="Toggle completed">
|
||||
Completed
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="archived" aria-label="Toggle archived">
|
||||
Archived
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVerticalOutlineWithIcons() {
|
||||
return (
|
||||
<Example title="Vertical Outline With Icons">
|
||||
<ToggleGroup
|
||||
variant="outline"
|
||||
selectionMode="multiple"
|
||||
orientation="vertical"
|
||||
size="sm"
|
||||
>
|
||||
<ToggleGroupItem id="bold" aria-label="Toggle bold">
|
||||
<IconPlaceholder
|
||||
lucide="BoldIcon"
|
||||
tabler="IconBold"
|
||||
hugeicons="TextBoldIcon"
|
||||
phosphor="TextBIcon"
|
||||
remixicon="RiBold"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="italic" aria-label="Toggle italic">
|
||||
<IconPlaceholder
|
||||
lucide="ItalicIcon"
|
||||
tabler="IconItalic"
|
||||
hugeicons="TextItalicIcon"
|
||||
phosphor="TextItalicIcon"
|
||||
remixicon="RiItalic"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="underline" aria-label="Toggle underline">
|
||||
<IconPlaceholder
|
||||
lucide="UnderlineIcon"
|
||||
tabler="IconUnderline"
|
||||
hugeicons="TextUnderlineIcon"
|
||||
phosphor="TextUnderlineIcon"
|
||||
remixicon="RiUnderline"
|
||||
/>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupFontWeightSelector() {
|
||||
const [fontWeight, setFontWeight] = React.useState("normal")
|
||||
return (
|
||||
<Example title="Font Weight Selector">
|
||||
<Field>
|
||||
<FieldLabel>Font Weight</FieldLabel>
|
||||
<ToggleGroup
|
||||
selectedKeys={[fontWeight]}
|
||||
onSelectionChange={(value) => {
|
||||
setFontWeight((Array.from(value)[0] as string) ?? "normal")
|
||||
}}
|
||||
variant="outline"
|
||||
spacing={2}
|
||||
size="lg"
|
||||
>
|
||||
<ToggleGroupItem
|
||||
id="light"
|
||||
aria-label="Light"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-light">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Light</span>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
id="normal"
|
||||
aria-label="Normal"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-normal">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Normal</span>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
id="medium"
|
||||
aria-label="Medium"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-medium">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Medium</span>
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem
|
||||
id="bold"
|
||||
aria-label="Bold"
|
||||
className="flex size-16 flex-col items-center justify-center rounded-xl"
|
||||
>
|
||||
<span className="text-2xl leading-none font-bold">Aa</span>
|
||||
<span className="text-xs text-muted-foreground">Bold</span>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
<FieldDescription>
|
||||
Use{" "}
|
||||
<code className="rounded-md bg-muted px-1 py-0.5 font-mono">
|
||||
font-{fontWeight}
|
||||
</code>{" "}
|
||||
to set the font weight.
|
||||
</FieldDescription>
|
||||
</Field>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function ToggleGroupVerticalWithSpacing() {
|
||||
return (
|
||||
<Example title="Vertical With Spacing">
|
||||
<ToggleGroup
|
||||
size="sm"
|
||||
defaultSelectedKeys={["top"]}
|
||||
orientation="vertical"
|
||||
spacing={1}
|
||||
>
|
||||
<ToggleGroupItem id="top" aria-label="Toggle top">
|
||||
Top
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="bottom" aria-label="Toggle bottom">
|
||||
Bottom
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="left" aria-label="Toggle left">
|
||||
Left
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem id="right" aria-label="Toggle right">
|
||||
Right
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
176
apps/v4/registry/bases/aria/examples/tooltip-example.tsx
Normal file
176
apps/v4/registry/bases/aria/examples/tooltip-example.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
"use client"
|
||||
|
||||
import { Link } from "react-aria-components"
|
||||
|
||||
import {
|
||||
Example,
|
||||
ExampleWrapper,
|
||||
} from "@/registry/bases/aria/components/example"
|
||||
import { Button } from "@/registry/bases/aria/ui/button"
|
||||
import { Kbd } from "@/registry/bases/aria/ui/kbd"
|
||||
import { Tooltip, TooltipTrigger } from "@/registry/bases/aria/ui/tooltip"
|
||||
import { IconPlaceholder } from "@/app/(create)/components/icon-placeholder"
|
||||
|
||||
export default function TooltipExample() {
|
||||
return (
|
||||
<ExampleWrapper>
|
||||
<TooltipBasic />
|
||||
<TooltipSides />
|
||||
<TooltipWithIcon />
|
||||
<TooltipLongContent />
|
||||
<TooltipDisabled />
|
||||
<TooltipWithKeyboard />
|
||||
<TooltipOnLink />
|
||||
<TooltipFormatted />
|
||||
</ExampleWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipBasic() {
|
||||
return (
|
||||
<Example title="Basic">
|
||||
<TooltipTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Show Tooltip
|
||||
</Button>
|
||||
<Tooltip>
|
||||
<p>Add to library</p>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipSides() {
|
||||
return (
|
||||
<Example title="Sides">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{(["start", "left", "top", "bottom", "right", "end"] as const).map(
|
||||
(placement) => (
|
||||
<TooltipTrigger key={placement}>
|
||||
<Button variant="outline" className="w-fit capitalize">
|
||||
{placement}
|
||||
</Button>
|
||||
<Tooltip placement={placement}>
|
||||
<p>Add to library</p>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipWithIcon() {
|
||||
return (
|
||||
<Example title="With Icon">
|
||||
<TooltipTrigger>
|
||||
<Button variant="ghost" size="icon">
|
||||
<IconPlaceholder
|
||||
lucide="InfoIcon"
|
||||
tabler="IconInfoCircle"
|
||||
hugeicons="AlertCircleIcon"
|
||||
phosphor="InfoIcon"
|
||||
remixicon="RiInformationLine"
|
||||
/>
|
||||
<span className="sr-only">Info</span>
|
||||
</Button>
|
||||
<Tooltip>
|
||||
<p>Additional information</p>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipLongContent() {
|
||||
return (
|
||||
<Example title="Long Content">
|
||||
<TooltipTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Show Tooltip
|
||||
</Button>
|
||||
<Tooltip>
|
||||
To learn more about how this works, check out the docs. If you have
|
||||
any questions, please reach out to us.
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipDisabled() {
|
||||
return (
|
||||
<Example title="Disabled">
|
||||
<TooltipTrigger>
|
||||
<span className="inline-block w-fit">
|
||||
<Button variant="outline" isDisabled>
|
||||
Disabled
|
||||
</Button>
|
||||
</span>
|
||||
<Tooltip>
|
||||
<p>This feature is currently unavailable</p>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipWithKeyboard() {
|
||||
return (
|
||||
<Example title="With Keyboard Shortcut">
|
||||
<TooltipTrigger>
|
||||
<Button variant="outline" size="icon-sm">
|
||||
<IconPlaceholder
|
||||
lucide="SaveIcon"
|
||||
tabler="IconDeviceFloppy"
|
||||
hugeicons="FloppyDiskIcon"
|
||||
phosphor="FloppyDiskIcon"
|
||||
remixicon="RiSaveLine"
|
||||
/>
|
||||
</Button>
|
||||
<Tooltip>
|
||||
Save Changes <Kbd>S</Kbd>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipOnLink() {
|
||||
return (
|
||||
<Example title="On Link">
|
||||
<TooltipTrigger>
|
||||
<Link
|
||||
href="#"
|
||||
className="w-fit text-sm text-primary underline-offset-4 hover:underline"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
>
|
||||
Learn more
|
||||
</Link>
|
||||
<Tooltip>
|
||||
<p>Click to read the documentation</p>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
|
||||
function TooltipFormatted() {
|
||||
return (
|
||||
<Example title="Formatted Content">
|
||||
<TooltipTrigger>
|
||||
<Button variant="outline" className="w-fit">
|
||||
Status
|
||||
</Button>
|
||||
<Tooltip>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="font-semibold">Active</p>
|
||||
<p className="text-xs opacity-80">Last updated 2 hours ago</p>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</TooltipTrigger>
|
||||
</Example>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user